Automatic sources dropoff on 2020-06-10 18:32:38.095721

The change is generated with prebuilt drop tool.

Change-Id: I24cbf6ba6db262a1ae1445db1427a08fee35b3b4
diff --git a/java/util/AbstractCollection.annotated.java b/java/util/AbstractCollection.annotated.java
new file mode 100644
index 0000000..529e351
--- /dev/null
+++ b/java/util/AbstractCollection.annotated.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class AbstractCollection<E> implements java.util.Collection<E> {
+
+protected AbstractCollection() { throw new RuntimeException("Stub!"); }
+
[email protected] public abstract java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator();
+
+public abstract int size();
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/AbstractCollection.java b/java/util/AbstractCollection.java
new file mode 100644
index 0000000..1f7cdd9
--- /dev/null
+++ b/java/util/AbstractCollection.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class provides a skeletal implementation of the <tt>Collection</tt>
+ * interface, to minimize the effort required to implement this interface. <p>
+ *
+ * To implement an unmodifiable collection, the programmer needs only to
+ * extend this class and provide implementations for the <tt>iterator</tt> and
+ * <tt>size</tt> methods.  (The iterator returned by the <tt>iterator</tt>
+ * method must implement <tt>hasNext</tt> and <tt>next</tt>.)<p>
+ *
+ * To implement a modifiable collection, the programmer must additionally
+ * override this class's <tt>add</tt> method (which otherwise throws an
+ * <tt>UnsupportedOperationException</tt>), and the iterator returned by the
+ * <tt>iterator</tt> method must additionally implement its <tt>remove</tt>
+ * method.<p>
+ *
+ * The programmer should generally provide a void (no argument) and
+ * <tt>Collection</tt> constructor, as per the recommendation in the
+ * <tt>Collection</tt> interface specification.<p>
+ *
+ * The documentation for each non-abstract method in this class describes its
+ * implementation in detail.  Each of these methods may be overridden if
+ * the collection being implemented admits a more efficient implementation.<p>
+ *
+ * This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @since 1.2
+ */
+
+public abstract class AbstractCollection<E> implements Collection<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractCollection() {
+    }
+
+    // Query Operations
+
+    /**
+     * Returns an iterator over the elements contained in this collection.
+     *
+     * @return an iterator over the elements contained in this collection
+     */
+    public abstract Iterator<E> iterator();
+
+    public abstract int size();
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation returns <tt>size() == 0</tt>.
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over the elements in the collection,
+     * checking each element in turn for equality with the specified element.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean contains(Object o) {
+        Iterator<E> it = iterator();
+        if (o==null) {
+            while (it.hasNext())
+                if (it.next()==null)
+                    return true;
+        } else {
+            while (it.hasNext())
+                if (o.equals(it.next()))
+                    return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation returns an array containing all the elements
+     * returned by this collection's iterator, in the same order, stored in
+     * consecutive elements of the array, starting with index {@code 0}.
+     * The length of the returned array is equal to the number of elements
+     * returned by the iterator, even if the size of this collection changes
+     * during iteration, as might happen if the collection permits
+     * concurrent modification during iteration.  The {@code size} method is
+     * called only as an optimization hint; the correct result is returned
+     * even if the iterator returns a different number of elements.
+     *
+     * <p>This method is equivalent to:
+     *
+     *  <pre> {@code
+     * List<E> list = new ArrayList<E>(size());
+     * for (E e : this)
+     *     list.add(e);
+     * return list.toArray();
+     * }</pre>
+     */
+    public Object[] toArray() {
+        // Estimate size of array; be prepared to see more or fewer elements
+        Object[] r = new Object[size()];
+        Iterator<E> it = iterator();
+        for (int i = 0; i < r.length; i++) {
+            if (! it.hasNext()) // fewer elements than expected
+                return Arrays.copyOf(r, i);
+            r[i] = it.next();
+        }
+        return it.hasNext() ? finishToArray(r, it) : r;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation returns an array containing all the elements
+     * returned by this collection's iterator in the same order, stored in
+     * consecutive elements of the array, starting with index {@code 0}.
+     * If the number of elements returned by the iterator is too large to
+     * fit into the specified array, then the elements are returned in a
+     * newly allocated array with length equal to the number of elements
+     * returned by the iterator, even if the size of this collection
+     * changes during iteration, as might happen if the collection permits
+     * concurrent modification during iteration.  The {@code size} method is
+     * called only as an optimization hint; the correct result is returned
+     * even if the iterator returns a different number of elements.
+     *
+     * <p>This method is equivalent to:
+     *
+     *  <pre> {@code
+     * List<E> list = new ArrayList<E>(size());
+     * for (E e : this)
+     *     list.add(e);
+     * return list.toArray(a);
+     * }</pre>
+     *
+     * @throws ArrayStoreException  {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        // Estimate size of array; be prepared to see more or fewer elements
+        int size = size();
+        T[] r = a.length >= size ? a :
+                  (T[])java.lang.reflect.Array
+                  .newInstance(a.getClass().getComponentType(), size);
+        Iterator<E> it = iterator();
+
+        for (int i = 0; i < r.length; i++) {
+            if (! it.hasNext()) { // fewer elements than expected
+                if (a == r) {
+                    r[i] = null; // null-terminate
+                } else if (a.length < i) {
+                    return Arrays.copyOf(r, i);
+                } else {
+                    System.arraycopy(r, 0, a, 0, i);
+                    if (a.length > i) {
+                        a[i] = null;
+                    }
+                }
+                return a;
+            }
+            r[i] = (T)it.next();
+        }
+        // more elements than expected
+        return it.hasNext() ? finishToArray(r, it) : r;
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Reallocates the array being used within toArray when the iterator
+     * returned more elements than expected, and finishes filling it from
+     * the iterator.
+     *
+     * @param r the array, replete with previously stored elements
+     * @param it the in-progress iterator over this collection
+     * @return array containing the elements in the given array, plus any
+     *         further elements returned by the iterator, trimmed to size
+     */
+    @SuppressWarnings("unchecked")
+    private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
+        int i = r.length;
+        while (it.hasNext()) {
+            int cap = r.length;
+            if (i == cap) {
+                int newCap = cap + (cap >> 1) + 1;
+                // overflow-conscious code
+                if (newCap - MAX_ARRAY_SIZE > 0)
+                    newCap = hugeCapacity(cap + 1);
+                r = Arrays.copyOf(r, newCap);
+            }
+            r[i++] = (T)it.next();
+        }
+        // trim if overallocated
+        return (i == r.length) ? r : Arrays.copyOf(r, i);
+    }
+
+    private static int hugeCapacity(int minCapacity) {
+        if (minCapacity < 0) // overflow
+            throw new OutOfMemoryError
+                ("Required array size too large");
+        return (minCapacity > MAX_ARRAY_SIZE) ?
+            Integer.MAX_VALUE :
+            MAX_ARRAY_SIZE;
+    }
+
+    // Modification Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation always throws an
+     * <tt>UnsupportedOperationException</tt>.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IllegalStateException         {@inheritDoc}
+     */
+    public boolean add(E e) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over the collection looking for the
+     * specified element.  If it finds the element, it removes the element
+     * from the collection using the iterator's remove method.
+     *
+     * <p>Note that this implementation throws an
+     * <tt>UnsupportedOperationException</tt> if the iterator returned by this
+     * collection's iterator method does not implement the <tt>remove</tt>
+     * method and this collection contains the specified object.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     */
+    public boolean remove(Object o) {
+        Iterator<E> it = iterator();
+        if (o==null) {
+            while (it.hasNext()) {
+                if (it.next()==null) {
+                    it.remove();
+                    return true;
+                }
+            }
+        } else {
+            while (it.hasNext()) {
+                if (o.equals(it.next())) {
+                    it.remove();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over the specified collection,
+     * checking each element returned by the iterator in turn to see
+     * if it's contained in this collection.  If all elements are so
+     * contained <tt>true</tt> is returned, otherwise <tt>false</tt>.
+     *
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @see #contains(Object)
+     */
+    public boolean containsAll(Collection<?> c) {
+        for (Object e : c)
+            if (!contains(e))
+                return false;
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over the specified collection, and adds
+     * each object returned by the iterator to this collection, in turn.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> unless <tt>add</tt> is
+     * overridden (assuming the specified collection is non-empty).
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IllegalStateException         {@inheritDoc}
+     *
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        boolean modified = false;
+        for (E e : c)
+            if (add(e))
+                modified = true;
+        return modified;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over this collection, checking each
+     * element returned by the iterator in turn to see if it's contained
+     * in the specified collection.  If it's so contained, it's removed from
+     * this collection with the iterator's <tt>remove</tt> method.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the iterator returned by the
+     * <tt>iterator</tt> method does not implement the <tt>remove</tt> method
+     * and this collection contains one or more elements in common with the
+     * specified collection.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     *
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        boolean modified = false;
+        Iterator<?> it = iterator();
+        while (it.hasNext()) {
+            if (c.contains(it.next())) {
+                it.remove();
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over this collection, checking each
+     * element returned by the iterator in turn to see if it's contained
+     * in the specified collection.  If it's not so contained, it's removed
+     * from this collection with the iterator's <tt>remove</tt> method.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the iterator returned by the
+     * <tt>iterator</tt> method does not implement the <tt>remove</tt> method
+     * and this collection contains one or more elements not present in the
+     * specified collection.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     *
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        boolean modified = false;
+        Iterator<E> it = iterator();
+        while (it.hasNext()) {
+            if (!c.contains(it.next())) {
+                it.remove();
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over this collection, removing each
+     * element using the <tt>Iterator.remove</tt> operation.  Most
+     * implementations will probably choose to override this method for
+     * efficiency.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the iterator returned by this
+     * collection's <tt>iterator</tt> method does not implement the
+     * <tt>remove</tt> method and this collection is non-empty.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     */
+    public void clear() {
+        Iterator<E> it = iterator();
+        while (it.hasNext()) {
+            it.next();
+            it.remove();
+        }
+    }
+
+
+    //  String conversion
+
+    /**
+     * Returns a string representation of this collection.  The string
+     * representation consists of a list of the collection's elements in the
+     * order they are returned by its iterator, enclosed in square brackets
+     * (<tt>"[]"</tt>).  Adjacent elements are separated by the characters
+     * <tt>", "</tt> (comma and space).  Elements are converted to strings as
+     * by {@link String#valueOf(Object)}.
+     *
+     * @return a string representation of this collection
+     */
+    public String toString() {
+        Iterator<E> it = iterator();
+        if (! it.hasNext())
+            return "[]";
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('[');
+        for (;;) {
+            E e = it.next();
+            sb.append(e == this ? "(this Collection)" : e);
+            if (! it.hasNext())
+                return sb.append(']').toString();
+            sb.append(',').append(' ');
+        }
+    }
+
+}
diff --git a/java/util/AbstractList.annotated.java b/java/util/AbstractList.annotated.java
new file mode 100644
index 0000000..ed89f7b
--- /dev/null
+++ b/java/util/AbstractList.annotated.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class AbstractList<E> extends java.util.AbstractCollection<E> implements java.util.List<E> {
+
+protected AbstractList() { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public abstract E get(int index);
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+protected void removeRange(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+protected transient int modCount = 0; // 0x0
+}
diff --git a/java/util/AbstractList.java b/java/util/AbstractList.java
new file mode 100644
index 0000000..c8c160d
--- /dev/null
+++ b/java/util/AbstractList.java
@@ -0,0 +1,942 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * This class provides a skeletal implementation of the {@link List}
+ * interface to minimize the effort required to implement this interface
+ * backed by a "random access" data store (such as an array).  For sequential
+ * access data (such as a linked list), {@link AbstractSequentialList} should
+ * be used in preference to this class.
+ *
+ * <p>To implement an unmodifiable list, the programmer needs only to extend
+ * this class and provide implementations for the {@link #get(int)} and
+ * {@link List#size() size()} methods.
+ *
+ * <p>To implement a modifiable list, the programmer must additionally
+ * override the {@link #set(int, Object) set(int, E)} method (which otherwise
+ * throws an {@code UnsupportedOperationException}).  If the list is
+ * variable-size the programmer must additionally override the
+ * {@link #add(int, Object) add(int, E)} and {@link #remove(int)} methods.
+ *
+ * <p>The programmer should generally provide a void (no argument) and collection
+ * constructor, as per the recommendation in the {@link Collection} interface
+ * specification.
+ *
+ * <p>Unlike the other abstract collection implementations, the programmer does
+ * <i>not</i> have to provide an iterator implementation; the iterator and
+ * list iterator are implemented by this class, on top of the "random access"
+ * methods:
+ * {@link #get(int)},
+ * {@link #set(int, Object) set(int, E)},
+ * {@link #add(int, Object) add(int, E)} and
+ * {@link #remove(int)}.
+ *
+ * <p>The documentation for each non-abstract method in this class describes its
+ * implementation in detail.  Each of these methods may be overridden if the
+ * collection being implemented admits a more efficient implementation.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @since 1.2
+ */
+
+public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractList() {
+    }
+
+    /**
+     * Appends the specified element to the end of this list (optional
+     * operation).
+     *
+     * <p>Lists that support this operation may place limitations on what
+     * elements may be added to this list.  In particular, some
+     * lists will refuse to add null elements, and others will impose
+     * restrictions on the type of elements that may be added.  List
+     * classes should clearly specify in their documentation any restrictions
+     * on what elements may be added.
+     *
+     * @implSpec
+     * This implementation calls {@code add(size(), e)}.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} unless
+     * {@link #add(int, Object) add(int, E)} is overridden.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this list
+     */
+    public boolean add(E e) {
+        add(size(), e);
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public abstract E get(int index);
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E remove(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+
+    // Search Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation first gets a list iterator (with
+     * {@code listIterator()}).  Then, it iterates over the list until the
+     * specified element is found or the end of the list is reached.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public int indexOf(Object o) {
+        ListIterator<E> it = listIterator();
+        if (o==null) {
+            while (it.hasNext())
+                if (it.next()==null)
+                    return it.previousIndex();
+        } else {
+            while (it.hasNext())
+                if (o.equals(it.next()))
+                    return it.previousIndex();
+        }
+        return -1;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation first gets a list iterator that points to the end
+     * of the list (with {@code listIterator(size())}).  Then, it iterates
+     * backwards over the list until the specified element is found, or the
+     * beginning of the list is reached.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public int lastIndexOf(Object o) {
+        ListIterator<E> it = listIterator(size());
+        if (o==null) {
+            while (it.hasPrevious())
+                if (it.previous()==null)
+                    return it.nextIndex();
+        } else {
+            while (it.hasPrevious())
+                if (o.equals(it.previous()))
+                    return it.nextIndex();
+        }
+        return -1;
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * Removes all of the elements from this list (optional operation).
+     * The list will be empty after this call returns.
+     *
+     * @implSpec
+     * This implementation calls {@code removeRange(0, size())}.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} unless {@code remove(int
+     * index)} or {@code removeRange(int fromIndex, int toIndex)} is
+     * overridden.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} operation
+     *         is not supported by this list
+     */
+    public void clear() {
+        removeRange(0, size());
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation gets an iterator over the specified collection
+     * and iterates over it, inserting the elements obtained from the
+     * iterator into this list at the appropriate position, one at a time,
+     * using {@code add(int, E)}.
+     * Many implementations will override this method for efficiency.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} unless
+     * {@link #add(int, Object) add(int, E)} is overridden.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        rangeCheckForAdd(index);
+        boolean modified = false;
+        for (E e : c) {
+            add(index++, e);
+            modified = true;
+        }
+        return modified;
+    }
+
+
+    // Iterators
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * @implSpec
+     * This implementation returns a straightforward implementation of the
+     * iterator interface, relying on the backing list's {@code size()},
+     * {@code get(int)}, and {@code remove(int)} methods.
+     *
+     * <p>Note that the iterator returned by this method will throw an
+     * {@link UnsupportedOperationException} in response to its
+     * {@code remove} method unless the list's {@code remove(int)} method is
+     * overridden.
+     *
+     * <p>This implementation can be made to throw runtime exceptions in the
+     * face of concurrent modification, as described in the specification
+     * for the (protected) {@link #modCount} field.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns {@code listIterator(0)}.
+     *
+     * @see #listIterator(int)
+     */
+    public ListIterator<E> listIterator() {
+        return listIterator(0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a straightforward implementation of the
+     * {@code ListIterator} interface that extends the implementation of the
+     * {@code Iterator} interface returned by the {@code iterator()} method.
+     * The {@code ListIterator} implementation relies on the backing list's
+     * {@code get(int)}, {@code set(int, E)}, {@code add(int, E)}
+     * and {@code remove(int)} methods.
+     *
+     * <p>Note that the list iterator returned by this implementation will
+     * throw an {@link UnsupportedOperationException} in response to its
+     * {@code remove}, {@code set} and {@code add} methods unless the
+     * list's {@code remove(int)}, {@code set(int, E)}, and
+     * {@code add(int, E)} methods are overridden.
+     *
+     * <p>This implementation can be made to throw runtime exceptions in the
+     * face of concurrent modification, as described in the specification for
+     * the (protected) {@link #modCount} field.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public ListIterator<E> listIterator(final int index) {
+        rangeCheckForAdd(index);
+
+        return new ListItr(index);
+    }
+
+    private class Itr implements Iterator<E> {
+        /**
+         * Index of element to be returned by subsequent call to next.
+         */
+        int cursor = 0;
+
+        /**
+         * Index of element returned by most recent call to next or
+         * previous.  Reset to -1 if this element is deleted by a call
+         * to remove.
+         */
+        int lastRet = -1;
+
+        /**
+         * The modCount value that the iterator believes that the backing
+         * List should have.  If this expectation is violated, the iterator
+         * has detected concurrent modification.
+         */
+        int expectedModCount = modCount;
+
+        public boolean hasNext() {
+            return cursor != size();
+        }
+
+        public E next() {
+            checkForComodification();
+            try {
+                int i = cursor;
+                E next = get(i);
+                lastRet = i;
+                cursor = i + 1;
+                return next;
+            } catch (IndexOutOfBoundsException e) {
+                checkForComodification();
+                throw new NoSuchElementException();
+            }
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            checkForComodification();
+
+            try {
+                AbstractList.this.remove(lastRet);
+                if (lastRet < cursor)
+                    cursor--;
+                lastRet = -1;
+                expectedModCount = modCount;
+            } catch (IndexOutOfBoundsException e) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        final void checkForComodification() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    private class ListItr extends Itr implements ListIterator<E> {
+        ListItr(int index) {
+            cursor = index;
+        }
+
+        public boolean hasPrevious() {
+            return cursor != 0;
+        }
+
+        public E previous() {
+            checkForComodification();
+            try {
+                int i = cursor - 1;
+                E previous = get(i);
+                lastRet = cursor = i;
+                return previous;
+            } catch (IndexOutOfBoundsException e) {
+                checkForComodification();
+                throw new NoSuchElementException();
+            }
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor-1;
+        }
+
+        public void set(E e) {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            checkForComodification();
+
+            try {
+                AbstractList.this.set(lastRet, e);
+                expectedModCount = modCount;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        public void add(E e) {
+            checkForComodification();
+
+            try {
+                int i = cursor;
+                AbstractList.this.add(i, e);
+                lastRet = -1;
+                cursor = i + 1;
+                expectedModCount = modCount;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a list that subclasses
+     * {@code AbstractList}.  The subclass stores, in private fields, the
+     * size of the subList (which can change over its lifetime), and the
+     * expected {@code modCount} value of the backing list.  There are two
+     * variants of the subclass, one of which implements {@code RandomAccess}.
+     * If this list implements {@code RandomAccess} the returned list will
+     * be an instance of the subclass that implements {@code RandomAccess}.
+     *
+     * <p>The subclass's {@code set(int, E)}, {@code get(int)},
+     * {@code add(int, E)}, {@code remove(int)}, {@code addAll(int,
+     * Collection)} and {@code removeRange(int, int)} methods all
+     * delegate to the corresponding methods on the backing abstract list,
+     * after bounds-checking the index and adjusting for the offset.  The
+     * {@code addAll(Collection c)} method merely returns {@code addAll(size,
+     * c)}.
+     *
+     * <p>The {@code listIterator(int)} method returns a "wrapper object"
+     * over a list iterator on the backing list, which is created with the
+     * corresponding method on the backing list.  The {@code iterator} method
+     * merely returns {@code listIterator()}, and the {@code size} method
+     * merely returns the subclass's {@code size} field.
+     *
+     * <p>All methods first check to see if the actual {@code modCount} of
+     * the backing list is equal to its expected value, and throw a
+     * {@code ConcurrentModificationException} if it is not.
+     *
+     * @throws IndexOutOfBoundsException if an endpoint index value is out of range
+     *         {@code (fromIndex < 0 || toIndex > size)}
+     * @throws IllegalArgumentException if the endpoint indices are out of order
+     *         {@code (fromIndex > toIndex)}
+     */
+    public List<E> subList(int fromIndex, int toIndex) {
+        subListRangeCheck(fromIndex, toIndex, size());
+        return (this instanceof RandomAccess ?
+                new RandomAccessSubList<>(this, fromIndex, toIndex) :
+                new SubList<>(this, fromIndex, toIndex));
+    }
+
+    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        if (toIndex > size)
+            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+        if (fromIndex > toIndex)
+            throw new IllegalArgumentException("fromIndex(" + fromIndex +
+                                               ") > toIndex(" + toIndex + ")");
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this list for equality.  Returns
+     * {@code true} if and only if the specified object is also a list, both
+     * lists have the same size, and all corresponding pairs of elements in
+     * the two lists are <i>equal</i>.  (Two elements {@code e1} and
+     * {@code e2} are <i>equal</i> if {@code (e1==null ? e2==null :
+     * e1.equals(e2))}.)  In other words, two lists are defined to be
+     * equal if they contain the same elements in the same order.
+     *
+     * @implSpec
+     * This implementation first checks if the specified object is this
+     * list. If so, it returns {@code true}; if not, it checks if the
+     * specified object is a list. If not, it returns {@code false}; if so,
+     * it iterates over both lists, comparing corresponding pairs of elements.
+     * If any comparison returns {@code false}, this method returns
+     * {@code false}.  If either iterator runs out of elements before the
+     * other it returns {@code false} (as the lists are of unequal length);
+     * otherwise it returns {@code true} when the iterations complete.
+     *
+     * @param o the object to be compared for equality with this list
+     * @return {@code true} if the specified object is equal to this list
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+        if (!(o instanceof List))
+            return false;
+
+        ListIterator<E> e1 = listIterator();
+        ListIterator<?> e2 = ((List<?>) o).listIterator();
+        while (e1.hasNext() && e2.hasNext()) {
+            E o1 = e1.next();
+            Object o2 = e2.next();
+            if (!(o1==null ? o2==null : o1.equals(o2)))
+                return false;
+        }
+        return !(e1.hasNext() || e2.hasNext());
+    }
+
+    /**
+     * Returns the hash code value for this list.
+     *
+     * @implSpec
+     * This implementation uses exactly the code that is used to define the
+     * list hash function in the documentation for the {@link List#hashCode}
+     * method.
+     *
+     * @return the hash code value for this list
+     */
+    public int hashCode() {
+        int hashCode = 1;
+        for (E e : this)
+            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
+        return hashCode;
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     *
+     * <p>This method is called by the {@code clear} operation on this list
+     * and its subLists.  Overriding this method to take advantage of
+     * the internals of the list implementation can <i>substantially</i>
+     * improve the performance of the {@code clear} operation on this list
+     * and its subLists.
+     *
+     * @implSpec
+     * This implementation gets a list iterator positioned before
+     * {@code fromIndex}, and repeatedly calls {@code ListIterator.next}
+     * followed by {@code ListIterator.remove} until the entire range has
+     * been removed.  <b>Note: if {@code ListIterator.remove} requires linear
+     * time, this implementation requires quadratic time.</b>
+     *
+     * @param fromIndex index of first element to be removed
+     * @param toIndex index after last element to be removed
+     */
+    protected void removeRange(int fromIndex, int toIndex) {
+        ListIterator<E> it = listIterator(fromIndex);
+        for (int i=0, n=toIndex-fromIndex; i<n; i++) {
+            it.next();
+            it.remove();
+        }
+    }
+
+    /**
+     * The number of times this list has been <i>structurally modified</i>.
+     * Structural modifications are those that change the size of the
+     * list, or otherwise perturb it in such a fashion that iterations in
+     * progress may yield incorrect results.
+     *
+     * <p>This field is used by the iterator and list iterator implementation
+     * returned by the {@code iterator} and {@code listIterator} methods.
+     * If the value of this field changes unexpectedly, the iterator (or list
+     * iterator) will throw a {@code ConcurrentModificationException} in
+     * response to the {@code next}, {@code remove}, {@code previous},
+     * {@code set} or {@code add} operations.  This provides
+     * <i>fail-fast</i> behavior, rather than non-deterministic behavior in
+     * the face of concurrent modification during iteration.
+     *
+     * <p><b>Use of this field by subclasses is optional.</b> If a subclass
+     * wishes to provide fail-fast iterators (and list iterators), then it
+     * merely has to increment this field in its {@code add(int, E)} and
+     * {@code remove(int)} methods (and any other methods that it overrides
+     * that result in structural modifications to the list).  A single call to
+     * {@code add(int, E)} or {@code remove(int)} must add no more than
+     * one to this field, or the iterators (and list iterators) will throw
+     * bogus {@code ConcurrentModificationExceptions}.  If an implementation
+     * does not wish to provide fail-fast iterators, this field may be
+     * ignored.
+     */
+    protected transient int modCount = 0;
+
+    private void rangeCheckForAdd(int index) {
+        if (index < 0 || index > size())
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+    }
+
+    private String outOfBoundsMsg(int index) {
+        return "Index: "+index+", Size: "+size();
+    }
+
+    /**
+     * An index-based split-by-two, lazily initialized Spliterator covering
+     * a List that access elements via {@link List#get}.
+     *
+     * If access results in an IndexOutOfBoundsException then a
+     * ConcurrentModificationException is thrown instead (since the list has
+     * been structurally modified while traversing).
+     *
+     * If the List is an instance of AbstractList then concurrent modification
+     * checking is performed using the AbstractList's modCount field.
+     */
+    static final class RandomAccessSpliterator<E> implements Spliterator<E> {
+
+        private final List<E> list;
+        private int index; // current index, modified on advance/split
+        private int fence; // -1 until used; then one past last index
+
+        // The following fields are valid if covering an AbstractList
+        private final AbstractList<E> alist;
+        private int expectedModCount; // initialized when fence set
+
+        RandomAccessSpliterator(List<E> list) {
+            assert list instanceof RandomAccess;
+
+            this.list = list;
+            this.index = 0;
+            this.fence = -1;
+
+            this.alist = list instanceof AbstractList ? (AbstractList<E>) list : null;
+            this.expectedModCount = alist != null ? alist.modCount : 0;
+        }
+
+        /** Create new spliterator covering the given  range */
+        private RandomAccessSpliterator(RandomAccessSpliterator<E> parent,
+                                int origin, int fence) {
+            this.list = parent.list;
+            this.index = origin;
+            this.fence = fence;
+
+            this.alist = parent.alist;
+            this.expectedModCount = parent.expectedModCount;
+        }
+
+        private int getFence() { // initialize fence to size on first use
+            int hi;
+            List<E> lst = list;
+            if ((hi = fence) < 0) {
+                if (alist != null) {
+                    expectedModCount = alist.modCount;
+                }
+                hi = fence = lst.size();
+            }
+            return hi;
+        }
+
+        public Spliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null : // divide range in half unless too small
+                    new RandomAccessSpliterator<>(this, lo, index = mid);
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int hi = getFence(), i = index;
+            if (i < hi) {
+                index = i + 1;
+                action.accept(get(list, i));
+                checkAbstractListModCount(alist, expectedModCount);
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            List<E> lst = list;
+            int hi = getFence();
+            int i = index;
+            index = hi;
+            for (; i < hi; i++) {
+                action.accept(get(lst, i));
+            }
+            checkAbstractListModCount(alist, expectedModCount);
+        }
+
+        public long estimateSize() {
+            return (long) (getFence() - index);
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        private static <E> E get(List<E> list, int i) {
+            try {
+                return list.get(i);
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        static void checkAbstractListModCount(AbstractList<?> alist, int expectedModCount) {
+            if (alist != null && alist.modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    private static class SubList<E> extends AbstractList<E> {
+        private final AbstractList<E> root;
+        private final SubList<E> parent;
+        private final int offset;
+        protected int size;
+
+        /**
+         * Constructs a sublist of an arbitrary AbstractList, which is
+         * not a SubList itself.
+         */
+        public SubList(AbstractList<E> root, int fromIndex, int toIndex) {
+            this.root = root;
+            this.parent = null;
+            this.offset = fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = root.modCount;
+        }
+
+        /**
+         * Constructs a sublist of another SubList.
+         */
+        protected SubList(SubList<E> parent, int fromIndex, int toIndex) {
+            this.root = parent.root;
+            this.parent = parent;
+            this.offset = parent.offset + fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = root.modCount;
+        }
+
+        public E set(int index, E element) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            return root.set(offset + index, element);
+        }
+
+        public E get(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            return root.get(offset + index);
+        }
+
+        public int size() {
+            checkForComodification();
+            return size;
+        }
+
+        public void add(int index, E element) {
+            rangeCheckForAdd(index);
+            checkForComodification();
+            root.add(offset + index, element);
+            updateSizeAndModCount(1);
+        }
+
+        public E remove(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            E result = root.remove(offset + index);
+            updateSizeAndModCount(-1);
+            return result;
+        }
+
+        protected void removeRange(int fromIndex, int toIndex) {
+            checkForComodification();
+            root.removeRange(offset + fromIndex, offset + toIndex);
+            updateSizeAndModCount(fromIndex - toIndex);
+        }
+
+        public boolean addAll(Collection<? extends E> c) {
+            return addAll(size, c);
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            rangeCheckForAdd(index);
+            int cSize = c.size();
+            if (cSize==0)
+                return false;
+            checkForComodification();
+            root.addAll(offset + index, c);
+            updateSizeAndModCount(cSize);
+            return true;
+        }
+
+        public Iterator<E> iterator() {
+            return listIterator();
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            checkForComodification();
+            rangeCheckForAdd(index);
+
+            return new ListIterator<E>() {
+                private final ListIterator<E> i =
+                        root.listIterator(offset + index);
+
+                public boolean hasNext() {
+                    return nextIndex() < size;
+                }
+
+                public E next() {
+                    if (hasNext())
+                        return i.next();
+                    else
+                        throw new NoSuchElementException();
+                }
+
+                public boolean hasPrevious() {
+                    return previousIndex() >= 0;
+                }
+
+                public E previous() {
+                    if (hasPrevious())
+                        return i.previous();
+                    else
+                        throw new NoSuchElementException();
+                }
+
+                public int nextIndex() {
+                    return i.nextIndex() - offset;
+                }
+
+                public int previousIndex() {
+                    return i.previousIndex() - offset;
+                }
+
+                public void remove() {
+                    i.remove();
+                    updateSizeAndModCount(-1);
+                }
+
+                public void set(E e) {
+                    i.set(e);
+                }
+
+                public void add(E e) {
+                    i.add(e);
+                    updateSizeAndModCount(1);
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new SubList<>(this, fromIndex, toIndex);
+        }
+
+        private void rangeCheckForAdd(int index) {
+            if (index < 0 || index > size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+        }
+
+        private String outOfBoundsMsg(int index) {
+            return "Index: "+index+", Size: "+size;
+        }
+
+        private void checkForComodification() {
+            if (root.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+        }
+
+        private void updateSizeAndModCount(int sizeChange) {
+            SubList<E> slist = this;
+            do {
+                slist.size += sizeChange;
+                slist.modCount = root.modCount;
+                slist = slist.parent;
+            } while (slist != null);
+        }
+    }
+
+    private static class RandomAccessSubList<E>
+            extends SubList<E> implements RandomAccess {
+
+        /**
+         * Constructs a sublist of an arbitrary AbstractList, which is
+         * not a RandomAccessSubList itself.
+         */
+        RandomAccessSubList(AbstractList<E> root,
+                int fromIndex, int toIndex) {
+            super(root, fromIndex, toIndex);
+        }
+
+        /**
+         * Constructs a sublist of another RandomAccessSubList.
+         */
+        RandomAccessSubList(RandomAccessSubList<E> parent,
+                int fromIndex, int toIndex) {
+            super(parent, fromIndex, toIndex);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new RandomAccessSubList<>(this, fromIndex, toIndex);
+        }
+    }
+}
diff --git a/java/util/AbstractMap.annotated.java b/java/util/AbstractMap.annotated.java
new file mode 100644
index 0000000..a0c97b0
--- /dev/null
+++ b/java/util/AbstractMap.annotated.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.util.Map.Entry;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class AbstractMap<K, V> implements java.util.Map<K,V> {
+
+protected AbstractMap() { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+public boolean containsValue(@libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public boolean containsKey(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
[email protected] public V get(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
[email protected] public V put(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
[email protected] public V remove(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values() { throw new RuntimeException("Stub!"); }
+
[email protected] public abstract java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet();
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] protected java.lang.Object clone() throws java.lang.CloneNotSupportedException { throw new RuntimeException("Stub!"); }
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static class SimpleEntry<K, V> implements java.util.Map.Entry<K,V>, java.io.Serializable {
+
+public SimpleEntry(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public SimpleEntry(@libcore.util.NonNull java.util.Map.Entry<? extends @libcore.util.NullFromTypeParam K, ? extends @libcore.util.NullFromTypeParam V> entry) { throw new RuntimeException("Stub!"); }
+
[email protected] public K getKey() { throw new RuntimeException("Stub!"); }
+
[email protected] public V getValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public V setValue(@libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+}
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static class SimpleImmutableEntry<K, V> implements java.util.Map.Entry<K,V>, java.io.Serializable {
+
+public SimpleImmutableEntry(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public SimpleImmutableEntry(@libcore.util.NonNull java.util.Map.Entry<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> entry) { throw new RuntimeException("Stub!"); }
+
[email protected] public K getKey() { throw new RuntimeException("Stub!"); }
+
[email protected] public V getValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public V setValue(@libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+}
+
+}
diff --git a/java/util/AbstractMap.java b/java/util/AbstractMap.java
new file mode 100644
index 0000000..948bf51
--- /dev/null
+++ b/java/util/AbstractMap.java
@@ -0,0 +1,860 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+import java.util.Map.Entry;
+
+/**
+ * This class provides a skeletal implementation of the <tt>Map</tt>
+ * interface, to minimize the effort required to implement this interface.
+ *
+ * <p>To implement an unmodifiable map, the programmer needs only to extend this
+ * class and provide an implementation for the <tt>entrySet</tt> method, which
+ * returns a set-view of the map's mappings.  Typically, the returned set
+ * will, in turn, be implemented atop <tt>AbstractSet</tt>.  This set should
+ * not support the <tt>add</tt> or <tt>remove</tt> methods, and its iterator
+ * should not support the <tt>remove</tt> method.
+ *
+ * <p>To implement a modifiable map, the programmer must additionally override
+ * this class's <tt>put</tt> method (which otherwise throws an
+ * <tt>UnsupportedOperationException</tt>), and the iterator returned by
+ * <tt>entrySet().iterator()</tt> must additionally implement its
+ * <tt>remove</tt> method.
+ *
+ * <p>The programmer should generally provide a void (no argument) and map
+ * constructor, as per the recommendation in the <tt>Map</tt> interface
+ * specification.
+ *
+ * <p>The documentation for each non-abstract method in this class describes its
+ * implementation in detail.  Each of these methods may be overridden if the
+ * map being implemented admits a more efficient implementation.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Map
+ * @see Collection
+ * @since 1.2
+ */
+
+public abstract class AbstractMap<K,V> implements Map<K,V> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractMap() {
+    }
+
+    // Query Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns <tt>entrySet().size()</tt>.
+     */
+    public int size() {
+        return entrySet().size();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns <tt>size() == 0</tt>.
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over <tt>entrySet()</tt> searching
+     * for an entry with the specified value.  If such an entry is found,
+     * <tt>true</tt> is returned.  If the iteration terminates without
+     * finding such an entry, <tt>false</tt> is returned.  Note that this
+     * implementation requires linear time in the size of the map.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean containsValue(Object value) {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        if (value==null) {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getValue()==null)
+                    return true;
+            }
+        } else {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (value.equals(e.getValue()))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over <tt>entrySet()</tt> searching
+     * for an entry with the specified key.  If such an entry is found,
+     * <tt>true</tt> is returned.  If the iteration terminates without
+     * finding such an entry, <tt>false</tt> is returned.  Note that this
+     * implementation requires linear time in the size of the map; many
+     * implementations will override this method.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean containsKey(Object key) {
+        Iterator<Map.Entry<K,V>> i = entrySet().iterator();
+        if (key==null) {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getKey()==null)
+                    return true;
+            }
+        } else {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (key.equals(e.getKey()))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over <tt>entrySet()</tt> searching
+     * for an entry with the specified key.  If such an entry is found,
+     * the entry's value is returned.  If the iteration terminates without
+     * finding such an entry, <tt>null</tt> is returned.  Note that this
+     * implementation requires linear time in the size of the map; many
+     * implementations will override this method.
+     *
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     */
+    public V get(Object key) {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        if (key==null) {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getKey()==null)
+                    return e.getValue();
+            }
+        } else {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (key.equals(e.getKey()))
+                    return e.getValue();
+            }
+        }
+        return null;
+    }
+
+
+    // Modification Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * <tt>UnsupportedOperationException</tt>.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public V put(K key, V value) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over <tt>entrySet()</tt> searching for an
+     * entry with the specified key.  If such an entry is found, its value is
+     * obtained with its <tt>getValue</tt> operation, the entry is removed
+     * from the collection (and the backing map) with the iterator's
+     * <tt>remove</tt> operation, and the saved value is returned.  If the
+     * iteration terminates without finding such an entry, <tt>null</tt> is
+     * returned.  Note that this implementation requires linear time in the
+     * size of the map; many implementations will override this method.
+     *
+     * <p>Note that this implementation throws an
+     * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
+     * iterator does not support the <tt>remove</tt> method and this map
+     * contains a mapping for the specified key.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     */
+    public V remove(Object key) {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        Entry<K,V> correctEntry = null;
+        if (key==null) {
+            while (correctEntry==null && i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getKey()==null)
+                    correctEntry = e;
+            }
+        } else {
+            while (correctEntry==null && i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (key.equals(e.getKey()))
+                    correctEntry = e;
+            }
+        }
+
+        V oldValue = null;
+        if (correctEntry !=null) {
+            oldValue = correctEntry.getValue();
+            i.remove();
+        }
+        return oldValue;
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over the specified map's
+     * <tt>entrySet()</tt> collection, and calls this map's <tt>put</tt>
+     * operation once for each entry returned by the iteration.
+     *
+     * <p>Note that this implementation throws an
+     * <tt>UnsupportedOperationException</tt> if this map does not support
+     * the <tt>put</tt> operation and the specified map is nonempty.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation calls <tt>entrySet().clear()</tt>.
+     *
+     * <p>Note that this implementation throws an
+     * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
+     * does not support the <tt>clear</tt> operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     */
+    public void clear() {
+        entrySet().clear();
+    }
+
+
+    // Views
+
+    /**
+     * Each of these fields are initialized to contain an instance of the
+     * appropriate view the first time this view is requested.  The views are
+     * stateless, so there's no reason to create more than one of each.
+     *
+     * <p>Since there is no synchronization performed while accessing these fields,
+     * it is expected that java.util.Map view classes using these fields have
+     * no non-final fields (or any fields at all except for outer-this). Adhering
+     * to this rule would make the races on these fields benign.
+     *
+     * <p>It is also imperative that implementations read the field only once,
+     * as in:
+     *
+     * <pre> {@code
+     * public Set<K> keySet() {
+     *   Set<K> ks = keySet;  // single racy read
+     *   if (ks == null) {
+     *     ks = new KeySet();
+     *     keySet = ks;
+     *   }
+     *   return ks;
+     * }
+     *}</pre>
+     */
+    transient Set<K>        keySet;
+    transient Collection<V> values;
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a set that subclasses {@link AbstractSet}.
+     * The subclass's iterator method returns a "wrapper object" over this
+     * map's <tt>entrySet()</tt> iterator.  The <tt>size</tt> method
+     * delegates to this map's <tt>size</tt> method and the
+     * <tt>contains</tt> method delegates to this map's
+     * <tt>containsKey</tt> method.
+     *
+     * <p>The set is created the first time this method is called,
+     * and returned in response to all subsequent calls.  No synchronization
+     * is performed, so there is a slight chance that multiple calls to this
+     * method will not all return the same set.
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new AbstractSet<K>() {
+                public Iterator<K> iterator() {
+                    return new Iterator<K>() {
+                        private Iterator<Entry<K,V>> i = entrySet().iterator();
+
+                        public boolean hasNext() {
+                            return i.hasNext();
+                        }
+
+                        public K next() {
+                            return i.next().getKey();
+                        }
+
+                        public void remove() {
+                            i.remove();
+                        }
+                    };
+                }
+
+                public int size() {
+                    return AbstractMap.this.size();
+                }
+
+                public boolean isEmpty() {
+                    return AbstractMap.this.isEmpty();
+                }
+
+                public void clear() {
+                    AbstractMap.this.clear();
+                }
+
+                public boolean contains(Object k) {
+                    return AbstractMap.this.containsKey(k);
+                }
+            };
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a collection that subclasses {@link
+     * AbstractCollection}.  The subclass's iterator method returns a
+     * "wrapper object" over this map's <tt>entrySet()</tt> iterator.
+     * The <tt>size</tt> method delegates to this map's <tt>size</tt>
+     * method and the <tt>contains</tt> method delegates to this map's
+     * <tt>containsValue</tt> method.
+     *
+     * <p>The collection is created the first time this method is called, and
+     * returned in response to all subsequent calls.  No synchronization is
+     * performed, so there is a slight chance that multiple calls to this
+     * method will not all return the same collection.
+     */
+    public Collection<V> values() {
+        Collection<V> vals = values;
+        if (vals == null) {
+            vals = new AbstractCollection<V>() {
+                public Iterator<V> iterator() {
+                    return new Iterator<V>() {
+                        private Iterator<Entry<K,V>> i = entrySet().iterator();
+
+                        public boolean hasNext() {
+                            return i.hasNext();
+                        }
+
+                        public V next() {
+                            return i.next().getValue();
+                        }
+
+                        public void remove() {
+                            i.remove();
+                        }
+                    };
+                }
+
+                public int size() {
+                    return AbstractMap.this.size();
+                }
+
+                public boolean isEmpty() {
+                    return AbstractMap.this.isEmpty();
+                }
+
+                public void clear() {
+                    AbstractMap.this.clear();
+                }
+
+                public boolean contains(Object v) {
+                    return AbstractMap.this.containsValue(v);
+                }
+            };
+            values = vals;
+        }
+        return vals;
+    }
+
+    public abstract Set<Entry<K,V>> entrySet();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * <tt>true</tt> if the given object is also a map and the two maps
+     * represent the same mappings.  More formally, two maps <tt>m1</tt> and
+     * <tt>m2</tt> represent the same mappings if
+     * <tt>m1.entrySet().equals(m2.entrySet())</tt>.  This ensures that the
+     * <tt>equals</tt> method works properly across different implementations
+     * of the <tt>Map</tt> interface.
+     *
+     * @implSpec
+     * This implementation first checks if the specified object is this map;
+     * if so it returns <tt>true</tt>.  Then, it checks if the specified
+     * object is a map whose size is identical to the size of this map; if
+     * not, it returns <tt>false</tt>.  If so, it iterates over this map's
+     * <tt>entrySet</tt> collection, and checks that the specified map
+     * contains each mapping that this map contains.  If the specified map
+     * fails to contain such a mapping, <tt>false</tt> is returned.  If the
+     * iteration completes, <tt>true</tt> is returned.
+     *
+     * @param o object to be compared for equality with this map
+     * @return <tt>true</tt> if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+
+        if (!(o instanceof Map))
+            return false;
+        Map<?,?> m = (Map<?,?>) o;
+        if (m.size() != size())
+            return false;
+
+        try {
+            Iterator<Entry<K,V>> i = entrySet().iterator();
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                K key = e.getKey();
+                V value = e.getValue();
+                if (value == null) {
+                    if (!(m.get(key)==null && m.containsKey(key)))
+                        return false;
+                } else {
+                    if (!value.equals(m.get(key)))
+                        return false;
+                }
+            }
+        } catch (ClassCastException unused) {
+            return false;
+        } catch (NullPointerException unused) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map's
+     * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
+     * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two maps
+     * <tt>m1</tt> and <tt>m2</tt>, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * @implSpec
+     * This implementation iterates over <tt>entrySet()</tt>, calling
+     * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the
+     * set, and adding up the results.
+     *
+     * @return the hash code value for this map
+     * @see Map.Entry#hashCode()
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     */
+    public int hashCode() {
+        int h = 0;
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        while (i.hasNext())
+            h += i.next().hashCode();
+        return h;
+    }
+
+    /**
+     * Returns a string representation of this map.  The string representation
+     * consists of a list of key-value mappings in the order returned by the
+     * map's <tt>entrySet</tt> view's iterator, enclosed in braces
+     * (<tt>"{}"</tt>).  Adjacent mappings are separated by the characters
+     * <tt>", "</tt> (comma and space).  Each key-value mapping is rendered as
+     * the key followed by an equals sign (<tt>"="</tt>) followed by the
+     * associated value.  Keys and values are converted to strings as by
+     * {@link String#valueOf(Object)}.
+     *
+     * @return a string representation of this map
+     */
+    public String toString() {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        if (! i.hasNext())
+            return "{}";
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        for (;;) {
+            Entry<K,V> e = i.next();
+            K key = e.getKey();
+            V value = e.getValue();
+            sb.append(key   == this ? "(this Map)" : key);
+            sb.append('=');
+            sb.append(value == this ? "(this Map)" : value);
+            if (! i.hasNext())
+                return sb.append('}').toString();
+            sb.append(',').append(' ');
+        }
+    }
+
+    /**
+     * Returns a shallow copy of this <tt>AbstractMap</tt> instance: the keys
+     * and values themselves are not cloned.
+     *
+     * @return a shallow copy of this map
+     */
+    protected Object clone() throws CloneNotSupportedException {
+        AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
+        result.keySet = null;
+        result.values = null;
+        return result;
+    }
+
+    /**
+     * Utility method for SimpleEntry and SimpleImmutableEntry.
+     * Test for equality, checking for nulls.
+     *
+     * NB: Do not replace with Object.equals until JDK-8015417 is resolved.
+     */
+    private static boolean eq(Object o1, Object o2) {
+        return o1 == null ? o2 == null : o1.equals(o2);
+    }
+
+    // Implementation Note: SimpleEntry and SimpleImmutableEntry
+    // are distinct unrelated classes, even though they share
+    // some code. Since you can't add or subtract final-ness
+    // of a field in a subclass, they can't share representations,
+    // and the amount of duplicated code is too small to warrant
+    // exposing a common abstract class.
+
+
+    /**
+     * An Entry maintaining a key and a value.  The value may be
+     * changed using the <tt>setValue</tt> method.  This class
+     * facilitates the process of building custom map
+     * implementations. For example, it may be convenient to return
+     * arrays of <tt>SimpleEntry</tt> instances in method
+     * <tt>Map.entrySet().toArray</tt>.
+     *
+     * @since 1.6
+     */
+    public static class SimpleEntry<K,V>
+        implements Entry<K,V>, java.io.Serializable
+    {
+        private static final long serialVersionUID = -8499721149061103585L;
+
+        private final K key;
+        private V value;
+
+        /**
+         * Creates an entry representing a mapping from the specified
+         * key to the specified value.
+         *
+         * @param key the key represented by this entry
+         * @param value the value represented by this entry
+         */
+        public SimpleEntry(K key, V value) {
+            this.key   = key;
+            this.value = value;
+        }
+
+        /**
+         * Creates an entry representing the same mapping as the
+         * specified entry.
+         *
+         * @param entry the entry to copy
+         */
+        public SimpleEntry(Entry<? extends K, ? extends V> entry) {
+            this.key   = entry.getKey();
+            this.value = entry.getValue();
+        }
+
+        /**
+         * Returns the key corresponding to this entry.
+         *
+         * @return the key corresponding to this entry
+         */
+        public K getKey() {
+            return key;
+        }
+
+        /**
+         * Returns the value corresponding to this entry.
+         *
+         * @return the value corresponding to this entry
+         */
+        public V getValue() {
+            return value;
+        }
+
+        /**
+         * Replaces the value corresponding to this entry with the specified
+         * value.
+         *
+         * @param value new value to be stored in this entry
+         * @return the old value corresponding to the entry
+         */
+        public V setValue(V value) {
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        /**
+         * Compares the specified object with this entry for equality.
+         * Returns {@code true} if the given object is also a map entry and
+         * the two entries represent the same mapping.  More formally, two
+         * entries {@code e1} and {@code e2} represent the same mapping
+         * if<pre>
+         *   (e1.getKey()==null ?
+         *    e2.getKey()==null :
+         *    e1.getKey().equals(e2.getKey()))
+         *   &amp;&amp;
+         *   (e1.getValue()==null ?
+         *    e2.getValue()==null :
+         *    e1.getValue().equals(e2.getValue()))</pre>
+         * This ensures that the {@code equals} method works properly across
+         * different implementations of the {@code Map.Entry} interface.
+         *
+         * @param o object to be compared for equality with this map entry
+         * @return {@code true} if the specified object is equal to this map
+         *         entry
+         * @see    #hashCode
+         */
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            return eq(key, e.getKey()) && eq(value, e.getValue());
+        }
+
+        /**
+         * Returns the hash code value for this map entry.  The hash code
+         * of a map entry {@code e} is defined to be: <pre>
+         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
+         * This ensures that {@code e1.equals(e2)} implies that
+         * {@code e1.hashCode()==e2.hashCode()} for any two Entries
+         * {@code e1} and {@code e2}, as required by the general
+         * contract of {@link Object#hashCode}.
+         *
+         * @return the hash code value for this map entry
+         * @see    #equals
+         */
+        public int hashCode() {
+            return (key   == null ? 0 :   key.hashCode()) ^
+                   (value == null ? 0 : value.hashCode());
+        }
+
+        /**
+         * Returns a String representation of this map entry.  This
+         * implementation returns the string representation of this
+         * entry's key followed by the equals character ("<tt>=</tt>")
+         * followed by the string representation of this entry's value.
+         *
+         * @return a String representation of this map entry
+         */
+        public String toString() {
+            return key + "=" + value;
+        }
+
+    }
+
+    /**
+     * An Entry maintaining an immutable key and value.  This class
+     * does not support method <tt>setValue</tt>.  This class may be
+     * convenient in methods that return thread-safe snapshots of
+     * key-value mappings.
+     *
+     * @since 1.6
+     */
+    public static class SimpleImmutableEntry<K,V>
+        implements Entry<K,V>, java.io.Serializable
+    {
+        private static final long serialVersionUID = 7138329143949025153L;
+
+        private final K key;
+        private final V value;
+
+        /**
+         * Creates an entry representing a mapping from the specified
+         * key to the specified value.
+         *
+         * @param key the key represented by this entry
+         * @param value the value represented by this entry
+         */
+        public SimpleImmutableEntry(K key, V value) {
+            this.key   = key;
+            this.value = value;
+        }
+
+        /**
+         * Creates an entry representing the same mapping as the
+         * specified entry.
+         *
+         * @param entry the entry to copy
+         */
+        public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) {
+            this.key   = entry.getKey();
+            this.value = entry.getValue();
+        }
+
+        /**
+         * Returns the key corresponding to this entry.
+         *
+         * @return the key corresponding to this entry
+         */
+        public K getKey() {
+            return key;
+        }
+
+        /**
+         * Returns the value corresponding to this entry.
+         *
+         * @return the value corresponding to this entry
+         */
+        public V getValue() {
+            return value;
+        }
+
+        /**
+         * Replaces the value corresponding to this entry with the specified
+         * value (optional operation).  This implementation simply throws
+         * <tt>UnsupportedOperationException</tt>, as this class implements
+         * an <i>immutable</i> map entry.
+         *
+         * @param value new value to be stored in this entry
+         * @return (Does not return)
+         * @throws UnsupportedOperationException always
+         */
+        public V setValue(V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Compares the specified object with this entry for equality.
+         * Returns {@code true} if the given object is also a map entry and
+         * the two entries represent the same mapping.  More formally, two
+         * entries {@code e1} and {@code e2} represent the same mapping
+         * if<pre>
+         *   (e1.getKey()==null ?
+         *    e2.getKey()==null :
+         *    e1.getKey().equals(e2.getKey()))
+         *   &amp;&amp;
+         *   (e1.getValue()==null ?
+         *    e2.getValue()==null :
+         *    e1.getValue().equals(e2.getValue()))</pre>
+         * This ensures that the {@code equals} method works properly across
+         * different implementations of the {@code Map.Entry} interface.
+         *
+         * @param o object to be compared for equality with this map entry
+         * @return {@code true} if the specified object is equal to this map
+         *         entry
+         * @see    #hashCode
+         */
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            return eq(key, e.getKey()) && eq(value, e.getValue());
+        }
+
+        /**
+         * Returns the hash code value for this map entry.  The hash code
+         * of a map entry {@code e} is defined to be: <pre>
+         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
+         * This ensures that {@code e1.equals(e2)} implies that
+         * {@code e1.hashCode()==e2.hashCode()} for any two Entries
+         * {@code e1} and {@code e2}, as required by the general
+         * contract of {@link Object#hashCode}.
+         *
+         * @return the hash code value for this map entry
+         * @see    #equals
+         */
+        public int hashCode() {
+            return (key   == null ? 0 :   key.hashCode()) ^
+                   (value == null ? 0 : value.hashCode());
+        }
+
+        /**
+         * Returns a String representation of this map entry.  This
+         * implementation returns the string representation of this
+         * entry's key followed by the equals character ("<tt>=</tt>")
+         * followed by the string representation of this entry's value.
+         *
+         * @return a String representation of this map entry
+         */
+        public String toString() {
+            return key + "=" + value;
+        }
+
+    }
+
+}
diff --git a/java/util/AbstractQueue.java b/java/util/AbstractQueue.java
new file mode 100644
index 0000000..dd31ed2
--- /dev/null
+++ b/java/util/AbstractQueue.java
@@ -0,0 +1,192 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * This class provides skeletal implementations of some {@link Queue}
+ * operations. The implementations in this class are appropriate when
+ * the base implementation does <em>not</em> allow {@code null}
+ * elements.  Methods {@link #add add}, {@link #remove remove}, and
+ * {@link #element element} are based on {@link #offer offer}, {@link
+ * #poll poll}, and {@link #peek peek}, respectively, but throw
+ * exceptions instead of indicating failure via {@code false} or
+ * {@code null} returns.
+ *
+ * <p>A {@code Queue} implementation that extends this class must
+ * minimally define a method {@link Queue#offer} which does not permit
+ * insertion of {@code null} elements, along with methods {@link
+ * Queue#peek}, {@link Queue#poll}, {@link Collection#size}, and
+ * {@link Collection#iterator}.  Typically, additional methods will be
+ * overridden as well.  If these requirements cannot be met, consider
+ * instead subclassing {@link AbstractCollection}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public abstract class AbstractQueue<E>
+    extends AbstractCollection<E>
+    implements Queue<E> {
+
+    /**
+     * Constructor for use by subclasses.
+     */
+    protected AbstractQueue() {
+    }
+
+    /**
+     * Inserts the specified element into this queue if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an {@code IllegalStateException}
+     * if no space is currently available.
+     *
+     * <p>This implementation returns {@code true} if {@code offer} succeeds,
+     * else throws an {@code IllegalStateException}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null and
+     *         this queue does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this queue
+     */
+    public boolean add(E e) {
+        if (offer(e))
+            return true;
+        else
+            throw new IllegalStateException("Queue full");
+    }
+
+    /**
+     * Retrieves and removes the head of this queue.  This method differs
+     * from {@link #poll poll} only in that it throws an exception if this
+     * queue is empty.
+     *
+     * <p>This implementation returns the result of {@code poll}
+     * unless the queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    public E remove() {
+        E x = poll();
+        if (x != null)
+            return x;
+        else
+            throw new NoSuchElementException();
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of this queue.  This method
+     * differs from {@link #peek peek} only in that it throws an exception if
+     * this queue is empty.
+     *
+     * <p>This implementation returns the result of {@code peek}
+     * unless the queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    public E element() {
+        E x = peek();
+        if (x != null)
+            return x;
+        else
+            throw new NoSuchElementException();
+    }
+
+    /**
+     * Removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     *
+     * <p>This implementation repeatedly invokes {@link #poll poll} until it
+     * returns {@code null}.
+     */
+    public void clear() {
+        while (poll() != null)
+            ;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this
+     * queue.  Attempts to addAll of a queue to itself result in
+     * {@code IllegalArgumentException}. Further, the behavior of
+     * this operation is undefined if the specified collection is
+     * modified while the operation is in progress.
+     *
+     * <p>This implementation iterates over the specified collection,
+     * and adds each element returned by the iterator to this
+     * queue, in turn.  A runtime exception encountered while
+     * trying to add an element (including, in particular, a
+     * {@code null} element) may result in only some of the elements
+     * having been successfully added when the associated exception is
+     * thrown.
+     *
+     * @param c collection containing elements to be added to this queue
+     * @return {@code true} if this queue changed as a result of the call
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this queue
+     * @throws NullPointerException if the specified collection contains a
+     *         null element and this queue does not permit null elements,
+     *         or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this
+     *         queue, or if the specified collection is this queue
+     * @throws IllegalStateException if not all the elements can be added at
+     *         this time due to insertion restrictions
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        boolean modified = false;
+        for (E e : c)
+            if (add(e))
+                modified = true;
+        return modified;
+    }
+
+}
diff --git a/java/util/AbstractSequentialList.annotated.java b/java/util/AbstractSequentialList.annotated.java
new file mode 100644
index 0000000..42c8127
--- /dev/null
+++ b/java/util/AbstractSequentialList.annotated.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class AbstractSequentialList<E> extends java.util.AbstractList<E> {
+
+protected AbstractSequentialList() { throw new RuntimeException("Stub!"); }
+
[email protected] public E get(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public abstract java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index);
+}
diff --git a/java/util/AbstractSequentialList.java b/java/util/AbstractSequentialList.java
new file mode 100644
index 0000000..36a91da
--- /dev/null
+++ b/java/util/AbstractSequentialList.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class provides a skeletal implementation of the <tt>List</tt>
+ * interface to minimize the effort required to implement this interface
+ * backed by a "sequential access" data store (such as a linked list).  For
+ * random access data (such as an array), <tt>AbstractList</tt> should be used
+ * in preference to this class.<p>
+ *
+ * This class is the opposite of the <tt>AbstractList</tt> class in the sense
+ * that it implements the "random access" methods (<tt>get(int index)</tt>,
+ * <tt>set(int index, E element)</tt>, <tt>add(int index, E element)</tt> and
+ * <tt>remove(int index)</tt>) on top of the list's list iterator, instead of
+ * the other way around.<p>
+ *
+ * To implement a list the programmer needs only to extend this class and
+ * provide implementations for the <tt>listIterator</tt> and <tt>size</tt>
+ * methods.  For an unmodifiable list, the programmer need only implement the
+ * list iterator's <tt>hasNext</tt>, <tt>next</tt>, <tt>hasPrevious</tt>,
+ * <tt>previous</tt> and <tt>index</tt> methods.<p>
+ *
+ * For a modifiable list the programmer should additionally implement the list
+ * iterator's <tt>set</tt> method.  For a variable-size list the programmer
+ * should additionally implement the list iterator's <tt>remove</tt> and
+ * <tt>add</tt> methods.<p>
+ *
+ * The programmer should generally provide a void (no argument) and collection
+ * constructor, as per the recommendation in the <tt>Collection</tt> interface
+ * specification.<p>
+ *
+ * This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see List
+ * @see AbstractList
+ * @see AbstractCollection
+ * @since 1.2
+ */
+
+public abstract class AbstractSequentialList<E> extends AbstractList<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractSequentialList() {
+    }
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with <tt>listIterator(index)</tt>).  Then, it gets
+     * the element using <tt>ListIterator.next</tt> and returns it.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        try {
+            return listIterator(index).next();
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element (optional operation).
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with <tt>listIterator(index)</tt>).  Then, it gets
+     * the current element using <tt>ListIterator.next</tt> and replaces it
+     * with <tt>ListIterator.set</tt>.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the list iterator does not
+     * implement the <tt>set</tt> operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        try {
+            ListIterator<E> e = listIterator(index);
+            E oldVal = e.next();
+            e.set(element);
+            return oldVal;
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this list
+     * (optional operation).  Shifts the element currently at that position
+     * (if any) and any subsequent elements to the right (adds one to their
+     * indices).
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with <tt>listIterator(index)</tt>).  Then, it
+     * inserts the specified element with <tt>ListIterator.add</tt>.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the list iterator does not
+     * implement the <tt>add</tt> operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        try {
+            listIterator(index).add(element);
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+    /**
+     * Removes the element at the specified position in this list (optional
+     * operation).  Shifts any subsequent elements to the left (subtracts one
+     * from their indices).  Returns the element that was removed from the
+     * list.
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with <tt>listIterator(index)</tt>).  Then, it removes
+     * the element with <tt>ListIterator.remove</tt>.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the list iterator does not
+     * implement the <tt>remove</tt> operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E remove(int index) {
+        try {
+            ListIterator<E> e = listIterator(index);
+            E outCast = e.next();
+            e.remove();
+            return outCast;
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list at the specified position (optional operation).  Shifts the
+     * element currently at that position (if any) and any subsequent
+     * elements to the right (increases their indices).  The new elements
+     * will appear in this list in the order that they are returned by the
+     * specified collection's iterator.  The behavior of this operation is
+     * undefined if the specified collection is modified while the
+     * operation is in progress.  (Note that this will occur if the specified
+     * collection is this list, and it's nonempty.)
+     *
+     * <p>This implementation gets an iterator over the specified collection and
+     * a list iterator over this list pointing to the indexed element (with
+     * <tt>listIterator(index)</tt>).  Then, it iterates over the specified
+     * collection, inserting the elements obtained from the iterator into this
+     * list, one at a time, using <tt>ListIterator.add</tt> followed by
+     * <tt>ListIterator.next</tt> (to skip over the added element).
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the list iterator returned by
+     * the <tt>listIterator</tt> method does not implement the <tt>add</tt>
+     * operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        try {
+            boolean modified = false;
+            ListIterator<E> e1 = listIterator(index);
+            Iterator<? extends E> e2 = c.iterator();
+            while (e2.hasNext()) {
+                e1.add(e2.next());
+                modified = true;
+            }
+            return modified;
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+
+    // Iterators
+
+    /**
+     * Returns an iterator over the elements in this list (in proper
+     * sequence).<p>
+     *
+     * This implementation merely returns a list iterator over the list.
+     *
+     * @return an iterator over the elements in this list (in proper sequence)
+     */
+    public Iterator<E> iterator() {
+        return listIterator();
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * @param  index index of first element to be returned from the list
+     *         iterator (by a call to the <code>next</code> method)
+     * @return a list iterator over the elements in this list (in proper
+     *         sequence)
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public abstract ListIterator<E> listIterator(int index);
+}
diff --git a/java/util/AbstractSet.annotated.java b/java/util/AbstractSet.annotated.java
new file mode 100644
index 0000000..2281ee0
--- /dev/null
+++ b/java/util/AbstractSet.annotated.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class AbstractSet<E> extends java.util.AbstractCollection<E> implements java.util.Set<E> {
+
+protected AbstractSet() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/AbstractSet.java b/java/util/AbstractSet.java
new file mode 100644
index 0000000..b3fe0dc
--- /dev/null
+++ b/java/util/AbstractSet.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class provides a skeletal implementation of the <tt>Set</tt>
+ * interface to minimize the effort required to implement this
+ * interface. <p>
+ *
+ * The process of implementing a set by extending this class is identical
+ * to that of implementing a Collection by extending AbstractCollection,
+ * except that all of the methods and constructors in subclasses of this
+ * class must obey the additional constraints imposed by the <tt>Set</tt>
+ * interface (for instance, the add method must not permit addition of
+ * multiple instances of an object to a set).<p>
+ *
+ * Note that this class does not override any of the implementations from
+ * the <tt>AbstractCollection</tt> class.  It merely adds implementations
+ * for <tt>equals</tt> and <tt>hashCode</tt>.<p>
+ *
+ * This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see AbstractCollection
+ * @see Set
+ * @since 1.2
+ */
+
+public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractSet() {
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * <tt>true</tt> if the given object is also a set, the two sets have
+     * the same size, and every member of the given set is contained in
+     * this set.  This ensures that the <tt>equals</tt> method works
+     * properly across different implementations of the <tt>Set</tt>
+     * interface.<p>
+     *
+     * This implementation first checks if the specified object is this
+     * set; if so it returns <tt>true</tt>.  Then, it checks if the
+     * specified object is a set whose size is identical to the size of
+     * this set; if not, it returns false.  If so, it returns
+     * <tt>containsAll((Collection) o)</tt>.
+     *
+     * @param o object to be compared for equality with this set
+     * @return <tt>true</tt> if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+
+        if (!(o instanceof Set))
+            return false;
+        Collection<?> c = (Collection<?>) o;
+        if (c.size() != size())
+            return false;
+        try {
+            return containsAll(c);
+        } catch (ClassCastException unused)   {
+            return false;
+        } catch (NullPointerException unused) {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the hash code value for this set.  The hash code of a set is
+     * defined to be the sum of the hash codes of the elements in the set,
+     * where the hash code of a <tt>null</tt> element is defined to be zero.
+     * This ensures that <tt>s1.equals(s2)</tt> implies that
+     * <tt>s1.hashCode()==s2.hashCode()</tt> for any two sets <tt>s1</tt>
+     * and <tt>s2</tt>, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * <p>This implementation iterates over the set, calling the
+     * <tt>hashCode</tt> method on each element in the set, and adding up
+     * the results.
+     *
+     * @return the hash code value for this set
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     */
+    public int hashCode() {
+        int h = 0;
+        Iterator<E> i = iterator();
+        while (i.hasNext()) {
+            E obj = i.next();
+            if (obj != null)
+                h += obj.hashCode();
+        }
+        return h;
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in the
+     * specified collection (optional operation).  If the specified
+     * collection is also a set, this operation effectively modifies this
+     * set so that its value is the <i>asymmetric set difference</i> of
+     * the two sets.
+     *
+     * <p>This implementation determines which is the smaller of this set
+     * and the specified collection, by invoking the <tt>size</tt>
+     * method on each.  If this set has fewer elements, then the
+     * implementation iterates over this set, checking each element
+     * returned by the iterator in turn to see if it is contained in
+     * the specified collection.  If it is so contained, it is removed
+     * from this set with the iterator's <tt>remove</tt> method.  If
+     * the specified collection has fewer elements, then the
+     * implementation iterates over the specified collection, removing
+     * from this set each element returned by the iterator, using this
+     * set's <tt>remove</tt> method.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the iterator returned by the
+     * <tt>iterator</tt> method does not implement the <tt>remove</tt> method.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the <tt>removeAll</tt> operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        boolean modified = false;
+
+        if (size() > c.size()) {
+            for (Iterator<?> i = c.iterator(); i.hasNext(); )
+                modified |= remove(i.next());
+        } else {
+            for (Iterator<?> i = iterator(); i.hasNext(); ) {
+                if (c.contains(i.next())) {
+                    i.remove();
+                    modified = true;
+                }
+            }
+        }
+        return modified;
+    }
+
+}
diff --git a/java/util/ArrayDeque.annotated.java b/java/util/ArrayDeque.annotated.java
new file mode 100644
index 0000000..014b99c
--- /dev/null
+++ b/java/util/ArrayDeque.annotated.java
@@ -0,0 +1,113 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Josh Bloch of Google Inc. and released to the public domain,
+ * as explained at http://creativecommons.org/publicdomain/zero/1.0/.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ArrayDeque<@libcore.util.NonNull E> extends java.util.AbstractCollection<E> implements java.util.Deque<E>, java.lang.Cloneable, java.io.Serializable {
+
+public ArrayDeque() { throw new RuntimeException("Stub!"); }
+
+public ArrayDeque(int numElements) { throw new RuntimeException("Stub!"); }
+
+public ArrayDeque(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void addFirst(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public void addLast(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean offerFirst(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean offerLast(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public E removeFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E removeLast() { throw new RuntimeException("Stub!"); }
+
[email protected] public E pollFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E pollLast() { throw new RuntimeException("Stub!"); }
+
[email protected] public E getFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E getLast() { throw new RuntimeException("Stub!"); }
+
[email protected] public E peekFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E peekLast() { throw new RuntimeException("Stub!"); }
+
+public boolean removeFirstOccurrence(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean removeLastOccurrence(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean offer(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove() { throw new RuntimeException("Stub!"); }
+
[email protected] public E poll() { throw new RuntimeException("Stub!"); }
+
[email protected] public E element() { throw new RuntimeException("Stub!"); }
+
[email protected] public E peek() { throw new RuntimeException("Stub!"); }
+
+public void push(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public E pop() { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> descendingIterator() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ArrayDeque<@libcore.util.NullFromTypeParam E> clone() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/ArrayDeque.java b/java/util/ArrayDeque.java
new file mode 100644
index 0000000..b1fb41e
--- /dev/null
+++ b/java/util/ArrayDeque.java
@@ -0,0 +1,997 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Josh Bloch of Google Inc. and released to the public domain,
+ * as explained at http://creativecommons.org/publicdomain/zero/1.0/.
+ */
+
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * Resizable-array implementation of the {@link Deque} interface.  Array
+ * deques have no capacity restrictions; they grow as necessary to support
+ * usage.  They are not thread-safe; in the absence of external
+ * synchronization, they do not support concurrent access by multiple threads.
+ * Null elements are prohibited.  This class is likely to be faster than
+ * {@link Stack} when used as a stack, and faster than {@link LinkedList}
+ * when used as a queue.
+ *
+ * <p>Most {@code ArrayDeque} operations run in amortized constant time.
+ * Exceptions include
+ * {@link #remove(Object) remove},
+ * {@link #removeFirstOccurrence removeFirstOccurrence},
+ * {@link #removeLastOccurrence removeLastOccurrence},
+ * {@link #contains contains},
+ * {@link #iterator iterator.remove()},
+ * and the bulk operations, all of which run in linear time.
+ *
+ * <p>The iterators returned by this class's {@link #iterator() iterator}
+ * method are <em>fail-fast</em>: If the deque is modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * {@code remove} method, the iterator will generally 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 time in the
+ * future.
+ *
+ * <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 {@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>
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * @author  Josh Bloch and Doug Lea
+ * @since   1.6
+ * @param <E> the type of elements held in this deque
+ */
+public class ArrayDeque<E> extends AbstractCollection<E>
+                           implements Deque<E>, Cloneable, Serializable
+{
+    /**
+     * The array in which the elements of the deque are stored.
+     * The capacity of the deque is the length of this array, which is
+     * always a power of two. The array is never allowed to become
+     * full, except transiently within an addX method where it is
+     * resized (see doubleCapacity) immediately upon becoming full,
+     * thus avoiding head and tail wrapping around to equal each
+     * other.  We also guarantee that all array cells not holding
+     * deque elements are always null.
+     */
+    transient Object[] elements; // non-private to simplify nested class access
+
+    /**
+     * The index of the element at the head of the deque (which is the
+     * element that would be removed by remove() or pop()); or an
+     * arbitrary number equal to tail if the deque is empty.
+     */
+    transient int head;
+
+    /**
+     * The index at which the next element would be added to the tail
+     * of the deque (via addLast(E), add(E), or push(E)).
+     */
+    transient int tail;
+
+    /**
+     * The minimum capacity that we'll use for a newly created deque.
+     * Must be a power of 2.
+     */
+    private static final int MIN_INITIAL_CAPACITY = 8;
+
+    // ******  Array allocation and resizing utilities ******
+
+    /**
+     * Allocates empty array to hold the given number of elements.
+     *
+     * @param numElements  the number of elements to hold
+     */
+    private void allocateElements(int numElements) {
+        int initialCapacity = MIN_INITIAL_CAPACITY;
+        // Find the best power of two to hold elements.
+        // Tests "<=" because arrays aren't kept full.
+        if (numElements >= initialCapacity) {
+            initialCapacity = numElements;
+            initialCapacity |= (initialCapacity >>>  1);
+            initialCapacity |= (initialCapacity >>>  2);
+            initialCapacity |= (initialCapacity >>>  4);
+            initialCapacity |= (initialCapacity >>>  8);
+            initialCapacity |= (initialCapacity >>> 16);
+            initialCapacity++;
+
+            if (initialCapacity < 0)    // Too many elements, must back off
+                initialCapacity >>>= 1; // Good luck allocating 2^30 elements
+        }
+        elements = new Object[initialCapacity];
+    }
+
+    /**
+     * Doubles the capacity of this deque.  Call only when full, i.e.,
+     * when head and tail have wrapped around to become equal.
+     */
+    private void doubleCapacity() {
+        assert head == tail;
+        int p = head;
+        int n = elements.length;
+        int r = n - p; // number of elements to the right of p
+        int newCapacity = n << 1;
+        if (newCapacity < 0)
+            throw new IllegalStateException("Sorry, deque too big");
+        Object[] a = new Object[newCapacity];
+        System.arraycopy(elements, p, a, 0, r);
+        System.arraycopy(elements, 0, a, r, p);
+        // Android-added: Clear old array instance that's about to become eligible for GC.
+        // This ensures that array elements can be eligible for garbage collection even
+        // before the array itself is recognized as being eligible; the latter might
+        // take a while in some GC implementations, if the array instance is longer lived
+        // (its liveness rarely checked) than some of its contents.
+        Arrays.fill(elements, null);
+        elements = a;
+        head = 0;
+        tail = n;
+    }
+
+    /**
+     * Constructs an empty array deque with an initial capacity
+     * sufficient to hold 16 elements.
+     */
+    public ArrayDeque() {
+        elements = new Object[16];
+    }
+
+    /**
+     * Constructs an empty array deque with an initial capacity
+     * sufficient to hold the specified number of elements.
+     *
+     * @param numElements  lower bound on initial capacity of the deque
+     */
+    public ArrayDeque(int numElements) {
+        allocateElements(numElements);
+    }
+
+    /**
+     * Constructs a deque containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.  (The first element returned by the collection's
+     * iterator becomes the first element, or <i>front</i> of the
+     * deque.)
+     *
+     * @param c the collection whose elements are to be placed into the deque
+     * @throws NullPointerException if the specified collection is null
+     */
+    public ArrayDeque(Collection<? extends E> c) {
+        allocateElements(c.size());
+        addAll(c);
+    }
+
+    // The main insertion and extraction methods are addFirst,
+    // addLast, pollFirst, pollLast. The other methods are defined in
+    // terms of these.
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     *
+     * @param e the element to add
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addFirst(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        elements[head = (head - 1) & (elements.length - 1)] = e;
+        if (head == tail)
+            doubleCapacity();
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @param e the element to add
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addLast(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        elements[tail] = e;
+        if ( (tail = (tail + 1) & (elements.length - 1)) == head)
+            doubleCapacity();
+    }
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Deque#offerFirst})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerFirst(E e) {
+        addFirst(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Deque#offerLast})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerLast(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeFirst() {
+        E x = pollFirst();
+        if (x == null)
+            throw new NoSuchElementException();
+        return x;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeLast() {
+        E x = pollLast();
+        if (x == null)
+            throw new NoSuchElementException();
+        return x;
+    }
+
+    public E pollFirst() {
+        final Object[] elements = this.elements;
+        final int h = head;
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[h];
+        // Element is null if deque empty
+        if (result != null) {
+            elements[h] = null; // Must null out slot
+            head = (h + 1) & (elements.length - 1);
+        }
+        return result;
+    }
+
+    public E pollLast() {
+        final Object[] elements = this.elements;
+        final int t = (tail - 1) & (elements.length - 1);
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[t];
+        if (result != null) {
+            elements[t] = null;
+            tail = t;
+        }
+        return result;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getFirst() {
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[head];
+        if (result == null)
+            throw new NoSuchElementException();
+        return result;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getLast() {
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[(tail - 1) & (elements.length - 1)];
+        if (result == null)
+            throw new NoSuchElementException();
+        return result;
+    }
+
+    @SuppressWarnings("unchecked")
+    public E peekFirst() {
+        // elements[head] is null if deque empty
+        return (E) elements[head];
+    }
+
+    @SuppressWarnings("unchecked")
+    public E peekLast() {
+        return (E) elements[(tail - 1) & (elements.length - 1)];
+    }
+
+    /**
+     * Removes the first occurrence of the specified element in this
+     * deque (when traversing the deque from head to tail).
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     */
+    public boolean removeFirstOccurrence(Object o) {
+        if (o != null) {
+            int mask = elements.length - 1;
+            int i = head;
+            for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
+                if (o.equals(x)) {
+                    delete(i);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes the last occurrence of the specified element in this
+     * deque (when traversing the deque from head to tail).
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     */
+    public boolean removeLastOccurrence(Object o) {
+        if (o != null) {
+            int mask = elements.length - 1;
+            int i = (tail - 1) & mask;
+            for (Object x; (x = elements[i]) != null; i = (i - 1) & mask) {
+                if (o.equals(x)) {
+                    delete(i);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    // *** Queue methods ***
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * <p>This method is equivalent to {@link #offerLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        return offerLast(e);
+    }
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque.
+     *
+     * This method differs from {@link #poll poll} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E remove() {
+        return removeFirst();
+    }
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), or returns
+     * {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #pollFirst}.
+     *
+     * @return the head of the queue represented by this deque, or
+     *         {@code null} if this deque is empty
+     */
+    public E poll() {
+        return pollFirst();
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque.  This method differs from {@link #peek peek} only in
+     * that it throws an exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E element() {
+        return getFirst();
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque, or returns {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #peekFirst}.
+     *
+     * @return the head of the queue represented by this deque, or
+     *         {@code null} if this deque is empty
+     */
+    public E peek() {
+        return peekFirst();
+    }
+
+    // *** Stack methods ***
+
+    /**
+     * Pushes an element onto the stack represented by this deque.  In other
+     * words, inserts the element at the front of this deque.
+     *
+     * <p>This method is equivalent to {@link #addFirst}.
+     *
+     * @param e the element to push
+     * @throws NullPointerException if the specified element is null
+     */
+    public void push(E e) {
+        addFirst(e);
+    }
+
+    /**
+     * Pops an element from the stack represented by this deque.  In other
+     * words, removes and returns the first element of this deque.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the element at the front of this deque (which is the top
+     *         of the stack represented by this deque)
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E pop() {
+        return removeFirst();
+    }
+
+    private void checkInvariants() {
+        assert elements[tail] == null;
+        assert head == tail ? elements[head] == null :
+            (elements[head] != null &&
+             elements[(tail - 1) & (elements.length - 1)] != null);
+        assert elements[(head - 1) & (elements.length - 1)] == null;
+    }
+
+    /**
+     * Removes the element at the specified position in the elements array,
+     * adjusting head and tail as necessary.  This can result in motion of
+     * elements backwards or forwards in the array.
+     *
+     * <p>This method is called delete rather than remove to emphasize
+     * that its semantics differ from those of {@link List#remove(int)}.
+     *
+     * @return true if elements moved backwards
+     */
+    boolean delete(int i) {
+        checkInvariants();
+        final Object[] elements = this.elements;
+        final int mask = elements.length - 1;
+        final int h = head;
+        final int t = tail;
+        final int front = (i - h) & mask;
+        final int back  = (t - i) & mask;
+
+        // Invariant: head <= i < tail mod circularity
+        if (front >= ((t - h) & mask))
+            throw new ConcurrentModificationException();
+
+        // Optimize for least element motion
+        if (front < back) {
+            if (h <= i) {
+                System.arraycopy(elements, h, elements, h + 1, front);
+            } else { // Wrap around
+                System.arraycopy(elements, 0, elements, 1, i);
+                elements[0] = elements[mask];
+                System.arraycopy(elements, h, elements, h + 1, mask - h);
+            }
+            elements[h] = null;
+            head = (h + 1) & mask;
+            return false;
+        } else {
+            if (i < t) { // Copy the null tail as well
+                System.arraycopy(elements, i + 1, elements, i, back);
+                tail = t - 1;
+            } else { // Wrap around
+                System.arraycopy(elements, i + 1, elements, i, mask - i);
+                elements[mask] = elements[0];
+                System.arraycopy(elements, 1, elements, 0, t);
+                tail = (t - 1) & mask;
+            }
+            return true;
+        }
+    }
+
+    // *** Collection Methods ***
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    public int size() {
+        return (tail - head) & (elements.length - 1);
+    }
+
+    /**
+     * Returns {@code true} if this deque contains no elements.
+     *
+     * @return {@code true} if this deque contains no elements
+     */
+    public boolean isEmpty() {
+        return head == tail;
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque.  The elements
+     * will be ordered from first (head) to last (tail).  This is the same
+     * order that elements would be dequeued (via successive calls to
+     * {@link #remove} or popped (via successive calls to {@link #pop}).
+     *
+     * @return an iterator over the elements in this deque
+     */
+    public Iterator<E> iterator() {
+        return new DeqIterator();
+    }
+
+    public Iterator<E> descendingIterator() {
+        return new DescendingIterator();
+    }
+
+    private class DeqIterator implements Iterator<E> {
+        /**
+         * Index of element to be returned by subsequent call to next.
+         */
+        private int cursor = head;
+
+        /**
+         * Tail recorded at construction (also in remove), to stop
+         * iterator and also to check for comodification.
+         */
+        private int fence = tail;
+
+        /**
+         * Index of element returned by most recent call to next.
+         * Reset to -1 if element is deleted by a call to remove.
+         */
+        private int lastRet = -1;
+
+        public boolean hasNext() {
+            return cursor != fence;
+        }
+
+        public E next() {
+            if (cursor == fence)
+                throw new NoSuchElementException();
+            @SuppressWarnings("unchecked")
+            E result = (E) elements[cursor];
+            // This check doesn't catch all possible comodifications,
+            // but does catch the ones that corrupt traversal
+            if (tail != fence || result == null)
+                throw new ConcurrentModificationException();
+            lastRet = cursor;
+            cursor = (cursor + 1) & (elements.length - 1);
+            return result;
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            if (delete(lastRet)) { // if left-shifted, undo increment in next()
+                cursor = (cursor - 1) & (elements.length - 1);
+                fence = tail;
+            }
+            lastRet = -1;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            Object[] a = elements;
+            int m = a.length - 1, f = fence, i = cursor;
+            cursor = f;
+            while (i != f) {
+                @SuppressWarnings("unchecked") E e = (E)a[i];
+                i = (i + 1) & m;
+                // Android-note: This uses a different heuristic for detecting
+                // concurrent modification exceptions than next(). As such, this is a less
+                // precise test.
+                if (e == null)
+                    throw new ConcurrentModificationException();
+                action.accept(e);
+            }
+        }
+    }
+
+    /**
+     * This class is nearly a mirror-image of DeqIterator, using tail
+     * instead of head for initial cursor, and head instead of tail
+     * for fence.
+     */
+    private class DescendingIterator implements Iterator<E> {
+        private int cursor = tail;
+        private int fence = head;
+        private int lastRet = -1;
+
+        public boolean hasNext() {
+            return cursor != fence;
+        }
+
+        public E next() {
+            if (cursor == fence)
+                throw new NoSuchElementException();
+            cursor = (cursor - 1) & (elements.length - 1);
+            @SuppressWarnings("unchecked")
+            E result = (E) elements[cursor];
+            if (head != fence || result == null)
+                throw new ConcurrentModificationException();
+            lastRet = cursor;
+            return result;
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            if (!delete(lastRet)) {
+                cursor = (cursor + 1) & (elements.length - 1);
+                fence = head;
+            }
+            lastRet = -1;
+        }
+    }
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this deque
+     * @return {@code true} if this deque contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o != null) {
+            int mask = elements.length - 1;
+            int i = head;
+            for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
+                if (o.equals(x))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes a single instance of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if this deque contained the specified element
+     */
+    public boolean remove(Object o) {
+        return removeFirstOccurrence(o);
+    }
+
+    /**
+     * Removes all of the elements from this deque.
+     * The deque will be empty after this call returns.
+     */
+    public void clear() {
+        int h = head;
+        int t = tail;
+        if (h != t) { // clear all cells
+            head = tail = 0;
+            int i = h;
+            int mask = elements.length - 1;
+            do {
+                elements[i] = null;
+                i = (i + 1) & mask;
+            } while (i != t);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this deque.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this deque
+     */
+    public Object[] toArray() {
+        final int head = this.head;
+        final int tail = this.tail;
+        boolean wrap = (tail < head);
+        int end = wrap ? tail + elements.length : tail;
+        Object[] a = Arrays.copyOfRange(elements, head, end);
+        if (wrap)
+            System.arraycopy(elements, 0, a, elements.length - head, tail);
+        return a;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque in
+     * proper sequence (from first to last element); the runtime type of the
+     * returned array is that of the specified array.  If the deque fits in
+     * the specified array, it is returned therein.  Otherwise, a new array
+     * is allocated with the runtime type of the specified array and the
+     * size of this deque.
+     *
+     * <p>If this deque fits in the specified array with room to spare
+     * (i.e., the array has more elements than this deque), the element in
+     * the array immediately following the end of the deque is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a deque known to contain only strings.
+     * The following code can be used to dump the deque into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the deque are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this deque
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this deque
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        final int head = this.head;
+        final int tail = this.tail;
+        boolean wrap = (tail < head);
+        int size = (tail - head) + (wrap ? elements.length : 0);
+        int firstLeg = size - (wrap ? tail : 0);
+        int len = a.length;
+        if (size > len) {
+            a = (T[]) Arrays.copyOfRange(elements, head, head + size,
+                                         a.getClass());
+        } else {
+            System.arraycopy(elements, head, a, 0, firstLeg);
+            if (size < len)
+                a[size] = null;
+        }
+        if (wrap)
+            System.arraycopy(elements, 0, a, firstLeg, tail);
+        return a;
+    }
+
+    // *** Object methods ***
+
+    /**
+     * Returns a copy of this deque.
+     *
+     * @return a copy of this deque
+     */
+    public ArrayDeque<E> clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            ArrayDeque<E> result = (ArrayDeque<E>) super.clone();
+            result.elements = Arrays.copyOf(elements, elements.length);
+            return result;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError();
+        }
+    }
+
+    private static final long serialVersionUID = 2340985798034038923L;
+
+    /**
+     * Saves this deque to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The current size ({@code int}) of the deque,
+     * followed by all of its elements (each an object reference) in
+     * first-to-last order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+            throws java.io.IOException {
+        s.defaultWriteObject();
+
+        // Write out size
+        s.writeInt(size());
+
+        // Write out elements in order.
+        int mask = elements.length - 1;
+        for (int i = head; i != tail; i = (i + 1) & mask)
+            s.writeObject(elements[i]);
+    }
+
+    /**
+     * Reconstitutes this deque from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+            throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+
+        // Read in size and allocate array
+        int size = s.readInt();
+        allocateElements(size);
+        head = 0;
+        tail = size;
+
+        // Read in all elements in the proper order.
+        for (int i = 0; i < size; i++)
+            elements[i] = s.readObject();
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * deque.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#NONNULL}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new DeqSpliterator<>(this, -1, -1);
+    }
+
+    static final class DeqSpliterator<E> implements Spliterator<E> {
+        private final ArrayDeque<E> deq;
+        private int fence;  // -1 until first use
+        private int index;  // current index, modified on traverse/split
+
+        /** Creates new spliterator covering the given array and range. */
+        DeqSpliterator(ArrayDeque<E> deq, int origin, int fence) {
+            this.deq = deq;
+            this.index = origin;
+            this.fence = fence;
+        }
+
+        private int getFence() { // force initialization
+            int t;
+            if ((t = fence) < 0) {
+                t = fence = deq.tail;
+                index = deq.head;
+            }
+            return t;
+        }
+
+        public DeqSpliterator<E> trySplit() {
+            int t = getFence(), h = index, n = deq.elements.length;
+            if (h != t && ((h + 1) & (n - 1)) != t) {
+                if (h > t)
+                    t += n;
+                int m = ((h + t) >>> 1) & (n - 1);
+                return new DeqSpliterator<E>(deq, h, index = m);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> consumer) {
+            if (consumer == null)
+                throw new NullPointerException();
+            Object[] a = deq.elements;
+            int m = a.length - 1, f = getFence(), i = index;
+            index = f;
+            while (i != f) {
+                @SuppressWarnings("unchecked") E e = (E)a[i];
+                i = (i + 1) & m;
+                if (e == null)
+                    throw new ConcurrentModificationException();
+                consumer.accept(e);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> consumer) {
+            if (consumer == null)
+                throw new NullPointerException();
+            Object[] a = deq.elements;
+            int m = a.length - 1, f = getFence(), i = index;
+            if (i != f) {
+                @SuppressWarnings("unchecked") E e = (E)a[i];
+                index = (i + 1) & m;
+                if (e == null)
+                    throw new ConcurrentModificationException();
+                consumer.accept(e);
+                return true;
+            }
+            return false;
+        }
+
+        public long estimateSize() {
+            int n = getFence() - index;
+            if (n < 0)
+                n += deq.elements.length;
+            return (long) n;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED |
+                Spliterator.NONNULL | Spliterator.SUBSIZED;
+        }
+    }
+
+}
diff --git a/java/util/ArrayList.annotated.java b/java/util/ArrayList.annotated.java
new file mode 100644
index 0000000..255c4be
--- /dev/null
+++ b/java/util/ArrayList.annotated.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ArrayList<E> extends java.util.AbstractList<E> implements java.util.List<E>, java.util.RandomAccess, java.lang.Cloneable, java.io.Serializable {
+
+public ArrayList(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+public ArrayList() { throw new RuntimeException("Stub!"); }
+
+public ArrayList(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void trimToSize() { throw new RuntimeException("Stub!"); }
+
+public void ensureCapacity(int minCapacity) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+// TODO: Make param and return types @Nullable T @NonNull [] once metalava supports TYPE_USE.
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public E get(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+protected void removeRange(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public void forEach(@libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NullFromTypeParam E> action) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
+public boolean removeIf(@libcore.util.NonNull java.util.function.Predicate<? super @libcore.util.NullFromTypeParam E> filter) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(@libcore.util.NonNull java.util.function.UnaryOperator<@libcore.util.NullFromTypeParam E> operator) { throw new RuntimeException("Stub!"); }
+
+public void sort(@libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/ArrayList.java b/java/util/ArrayList.java
new file mode 100644
index 0000000..20c623a
--- /dev/null
+++ b/java/util/ArrayList.java
@@ -0,0 +1,1476 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+/**
+ * Resizable-array implementation of the <tt>List</tt> interface.  Implements
+ * all optional list operations, and permits all elements, including
+ * <tt>null</tt>.  In addition to implementing the <tt>List</tt> interface,
+ * this class provides methods to manipulate the size of the array that is
+ * used internally to store the list.  (This class is roughly equivalent to
+ * <tt>Vector</tt>, except that it is unsynchronized.)
+ *
+ * <p>The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,
+ * <tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant
+ * time.  The <tt>add</tt> operation runs in <i>amortized constant time</i>,
+ * that is, adding n elements requires O(n) time.  All of the other operations
+ * run in linear time (roughly speaking).  The constant factor is low compared
+ * to that for the <tt>LinkedList</tt> implementation.
+ *
+ * <p>Each <tt>ArrayList</tt> instance has a <i>capacity</i>.  The capacity is
+ * the size of the array used to store the elements in the list.  It is always
+ * at least as large as the list size.  As elements are added to an ArrayList,
+ * its capacity grows automatically.  The details of the growth policy are not
+ * specified beyond the fact that adding an element has constant amortized
+ * time cost.
+ *
+ * <p>An application can increase the capacity of an <tt>ArrayList</tt> instance
+ * before adding a large number of elements using the <tt>ensureCapacity</tt>
+ * operation.  This may reduce the amount of incremental reallocation.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
+ * and at least one of the threads modifies the list structurally, it
+ * <i>must</i> be synchronized externally.  (A structural modification is
+ * any operation that adds or deletes one or more elements, or explicitly
+ * resizes the backing array; merely setting the value of an element is not
+ * a structural modification.)  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the list.
+ *
+ * If no such object exists, the list should be "wrapped" using the
+ * {@link Collections#synchronizedList Collections.synchronizedList}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the list:<pre>
+ *   List list = Collections.synchronizedList(new ArrayList(...));</pre>
+ *
+ * <p><a name="fail-fast">
+ * The iterators returned by this class's {@link #iterator() iterator} and
+ * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:</a>
+ * if the list is structurally modified at any time after the iterator is
+ * created, in any way except through the iterator's own
+ * {@link ListIterator#remove() remove} or
+ * {@link ListIterator#add(Object) 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
+ * time in the future.
+ *
+ * <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 {@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>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Collection
+ * @see     List
+ * @see     LinkedList
+ * @see     Vector
+ * @since   1.2
+ */
+// Android-changed: Inlined methods; CME in iterators; throw AIOOBE when toIndex < fromIndex.
+/*
+ * - AOSP commit 3be987f0f18648b3c532c8b89d09505e18594241
+ *   Inline for improved performance:
+ *   - checkForComodification
+ *   - elementData()
+ *   - rangeCheck()
+ *   - rangeCheckForAdd()
+ * - AOSP commit b10b2a3ab693cfd6156d06ffe4e00ce69b9c9194
+ *   Fix ConcurrentModificationException in ArrayList iterators.
+ * - AOSP commit a68b1a5ba82ef8cc19aafdce7d9c7f9631943f84
+ *   Throw AIOOBE when toIndex < fromIndex.
+ */
+public class ArrayList<E> extends AbstractList<E>
+        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
+{
+    private static final long serialVersionUID = 8683452581122892189L;
+
+    /**
+     * Default initial capacity.
+     */
+    private static final int DEFAULT_CAPACITY = 10;
+
+    /**
+     * Shared empty array instance used for empty instances.
+     */
+    private static final Object[] EMPTY_ELEMENTDATA = {};
+
+    /**
+     * Shared empty array instance used for default sized empty instances. We
+     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
+     * first element is added.
+     */
+    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
+
+    /**
+     * The array buffer into which the elements of the ArrayList are stored.
+     * The capacity of the ArrayList is the length of this array buffer. Any
+     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
+     * will be expanded to DEFAULT_CAPACITY when the first element is added.
+     */
+    // Android-note: Also accessed from java.util.Collections
+    transient Object[] elementData; // non-private to simplify nested class access
+
+    /**
+     * The size of the ArrayList (the number of elements it contains).
+     *
+     * @serial
+     */
+    private int size;
+
+    /**
+     * Constructs an empty list with the specified initial capacity.
+     *
+     * @param  initialCapacity  the initial capacity of the list
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    public ArrayList(int initialCapacity) {
+        if (initialCapacity > 0) {
+            this.elementData = new Object[initialCapacity];
+        } else if (initialCapacity == 0) {
+            this.elementData = EMPTY_ELEMENTDATA;
+        } else {
+            throw new IllegalArgumentException("Illegal Capacity: "+
+                                               initialCapacity);
+        }
+    }
+
+    /**
+     * Constructs an empty list with an initial capacity of ten.
+     */
+    public ArrayList() {
+        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
+    }
+
+    /**
+     * Constructs a list containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param c the collection whose elements are to be placed into this list
+     * @throws NullPointerException if the specified collection is null
+     */
+    public ArrayList(Collection<? extends E> c) {
+        elementData = c.toArray();
+        if ((size = elementData.length) != 0) {
+            // c.toArray might (incorrectly) not return Object[] (see 6260652)
+            if (elementData.getClass() != Object[].class)
+                elementData = Arrays.copyOf(elementData, size, Object[].class);
+        } else {
+            // replace with empty array.
+            this.elementData = EMPTY_ELEMENTDATA;
+        }
+    }
+
+    /**
+     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
+     * list's current size.  An application can use this operation to minimize
+     * the storage of an <tt>ArrayList</tt> instance.
+     */
+    public void trimToSize() {
+        modCount++;
+        if (size < elementData.length) {
+            elementData = (size == 0)
+              ? EMPTY_ELEMENTDATA
+              : Arrays.copyOf(elementData, size);
+        }
+    }
+
+    /**
+     * Increases the capacity of this <tt>ArrayList</tt> instance, if
+     * necessary, to ensure that it can hold at least the number of elements
+     * specified by the minimum capacity argument.
+     *
+     * @param   minCapacity   the desired minimum capacity
+     */
+    public void ensureCapacity(int minCapacity) {
+        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
+            // any size if not default element table
+            ? 0
+            // larger than default for default empty table. It's already
+            // supposed to be at default size.
+            : DEFAULT_CAPACITY;
+
+        if (minCapacity > minExpand) {
+            ensureExplicitCapacity(minCapacity);
+        }
+    }
+
+    private void ensureCapacityInternal(int minCapacity) {
+        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
+            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
+        }
+
+        ensureExplicitCapacity(minCapacity);
+    }
+
+    private void ensureExplicitCapacity(int minCapacity) {
+        modCount++;
+
+        // overflow-conscious code
+        if (minCapacity - elementData.length > 0)
+            grow(minCapacity);
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Increases the capacity to ensure that it can hold at least the
+     * number of elements specified by the minimum capacity argument.
+     *
+     * @param minCapacity the desired minimum capacity
+     */
+    private void grow(int minCapacity) {
+        // overflow-conscious code
+        int oldCapacity = elementData.length;
+        int newCapacity = oldCapacity + (oldCapacity >> 1);
+        if (newCapacity - minCapacity < 0)
+            newCapacity = minCapacity;
+        if (newCapacity - MAX_ARRAY_SIZE > 0)
+            newCapacity = hugeCapacity(minCapacity);
+        // minCapacity is usually close to size, so this is a win:
+        elementData = Arrays.copyOf(elementData, newCapacity);
+    }
+
+    private static int hugeCapacity(int minCapacity) {
+        if (minCapacity < 0) // overflow
+            throw new OutOfMemoryError();
+        return (minCapacity > MAX_ARRAY_SIZE) ?
+            Integer.MAX_VALUE :
+            MAX_ARRAY_SIZE;
+    }
+
+    /**
+     * Returns the number of elements in this list.
+     *
+     * @return the number of elements in this list
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this list contains no elements.
+     *
+     * @return <tt>true</tt> if this list contains no elements
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * 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
+     * <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
+     */
+    public boolean contains(Object o) {
+        return indexOf(o) >= 0;
+    }
+
+    /**
+     * 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
+     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * or -1 if there is no such index.
+     */
+    public int indexOf(Object o) {
+        if (o == null) {
+            for (int i = 0; i < size; i++)
+                if (elementData[i]==null)
+                    return i;
+        } else {
+            for (int i = 0; i < size; i++)
+                if (o.equals(elementData[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * 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
+     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * or -1 if there is no such index.
+     */
+    public int lastIndexOf(Object o) {
+        if (o == null) {
+            for (int i = size-1; i >= 0; i--)
+                if (elementData[i]==null)
+                    return i;
+        } else {
+            for (int i = size-1; i >= 0; i--)
+                if (o.equals(elementData[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
+     * elements themselves are not copied.)
+     *
+     * @return a clone of this <tt>ArrayList</tt> instance
+     */
+    public Object clone() {
+        try {
+            ArrayList<?> v = (ArrayList<?>) super.clone();
+            v.elementData = Arrays.copyOf(elementData, size);
+            v.modCount = 0;
+            return v;
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this list in
+     *         proper sequence
+     */
+    public Object[] toArray() {
+        return Arrays.copyOf(elementData, size);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list in proper
+     * sequence (from first to last element); the runtime type of the returned
+     * array is that of the specified array.  If the list fits in the
+     * specified array, it is returned therein.  Otherwise, a new array is
+     * allocated with the runtime type of the specified array and the size of
+     * this list.
+     *
+     * <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 collection is set to
+     * <tt>null</tt>.  (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.)
+     *
+     * @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
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of the list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this list
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a.length < size)
+            // Make a new array of a's runtime type, but my contents:
+            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
+        System.arraycopy(elementData, 0, a, 0, size);
+        if (a.length > size)
+            a[size] = null;
+        return a;
+    }
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * @param  index index of the element to return
+     * @return the element at the specified position in this list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        if (index >= size)
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+
+        return (E) elementData[index];
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with
+     * the specified element.
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        if (index >= size)
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+
+        E oldValue = (E) elementData[index];
+        elementData[index] = element;
+        return oldValue;
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * @param e element to be appended to this list
+     * @return <tt>true</tt> (as specified by {@link Collection#add})
+     */
+    public boolean add(E e) {
+        ensureCapacityInternal(size + 1);  // Increments modCount!!
+        elementData[size++] = e;
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this
+     * list. Shifts the element currently at that position (if any) and
+     * any subsequent elements to the right (adds one to their indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        if (index > size || index < 0)
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+
+        ensureCapacityInternal(size + 1);  // Increments modCount!!
+        System.arraycopy(elementData, index, elementData, index + 1,
+                         size - index);
+        elementData[index] = element;
+        size++;
+    }
+
+    /**
+     * Removes the element at the specified position in this list.
+     * Shifts any subsequent elements to the left (subtracts one from their
+     * indices).
+     *
+     * @param index the index of the element to be removed
+     * @return the element that was removed from the list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E remove(int index) {
+        if (index >= size)
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+
+        modCount++;
+        E oldValue = (E) elementData[index];
+
+        int numMoved = size - index - 1;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index+1, elementData, index,
+                             numMoved);
+        elementData[--size] = null; // clear to let GC do its work
+
+        return oldValue;
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this list,
+     * if it is present.  If the list does not contain the element, it is
+     * unchanged.  More formally, removes the element with the lowest index
+     * <tt>i</tt> 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
+     * 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
+     */
+    public boolean remove(Object o) {
+        if (o == null) {
+            for (int index = 0; index < size; index++)
+                if (elementData[index] == null) {
+                    fastRemove(index);
+                    return true;
+                }
+        } else {
+            for (int index = 0; index < size; index++)
+                if (o.equals(elementData[index])) {
+                    fastRemove(index);
+                    return true;
+                }
+        }
+        return false;
+    }
+
+    /*
+     * Private remove method that skips bounds checking and does not
+     * return the value removed.
+     */
+    private void fastRemove(int index) {
+        modCount++;
+        int numMoved = size - index - 1;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index+1, elementData, index,
+                             numMoved);
+        elementData[--size] = null; // clear to let GC do its work
+    }
+
+    /**
+     * Removes all of the elements from this list.  The list will
+     * be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+
+        // clear to let GC do its work
+        for (int i = 0; i < size; i++)
+            elementData[i] = null;
+
+        size = 0;
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this list, in the order that they are returned by the
+     * specified collection's Iterator.  The behavior of this operation is
+     * undefined if the specified collection is modified while the operation
+     * is in progress.  (This implies that the behavior of this call is
+     * undefined if the specified collection is this list, and this
+     * list is 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
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        Object[] a = c.toArray();
+        int numNew = a.length;
+        ensureCapacityInternal(size + numNew);  // Increments modCount
+        System.arraycopy(a, 0, elementData, size, numNew);
+        size += numNew;
+        return numNew != 0;
+    }
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list, starting at the specified position.  Shifts the element
+     * currently at that position (if any) and any subsequent elements to
+     * the right (increases their indices).  The new elements will appear
+     * in the list in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @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
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        if (index > size || index < 0)
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+
+        Object[] a = c.toArray();
+        int numNew = a.length;
+        ensureCapacityInternal(size + numNew);  // Increments modCount
+
+        int numMoved = size - index;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index, elementData, index + numNew,
+                             numMoved);
+
+        System.arraycopy(a, 0, elementData, index, numNew);
+        size += numNew;
+        return numNew != 0;
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     *
+     * @throws IndexOutOfBoundsException if {@code fromIndex} or
+     *         {@code toIndex} is out of range
+     *         ({@code fromIndex < 0 ||
+     *          fromIndex >= size() ||
+     *          toIndex > size() ||
+     *          toIndex < fromIndex})
+     */
+    protected void removeRange(int fromIndex, int toIndex) {
+        // Android-changed: Throw an IOOBE if toIndex < fromIndex as documented.
+        // All the other cases (negative indices, or indices greater than the size
+        // will be thrown by System#arrayCopy.
+        if (toIndex < fromIndex) {
+            throw new IndexOutOfBoundsException("toIndex < fromIndex");
+        }
+
+        modCount++;
+        int numMoved = size - toIndex;
+        System.arraycopy(elementData, toIndex, elementData, fromIndex,
+                         numMoved);
+
+        // clear to let GC do its work
+        int newSize = size - (toIndex-fromIndex);
+        for (int i = newSize; i < size; i++) {
+            elementData[i] = null;
+        }
+        size = newSize;
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * Removes from this list all of its elements that are contained in the
+     * specified collection.
+     *
+     * @param c collection containing elements to be removed from this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see Collection#contains(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return batchRemove(c, false);
+    }
+
+    /**
+     * Retains only the elements in this list that are contained in the
+     * specified collection.  In other words, removes from this list all
+     * of its elements that are not contained in the specified collection.
+     *
+     * @param c collection containing elements to be retained in this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see Collection#contains(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return batchRemove(c, true);
+    }
+
+    private boolean batchRemove(Collection<?> c, boolean complement) {
+        final Object[] elementData = this.elementData;
+        int r = 0, w = 0;
+        boolean modified = false;
+        try {
+            for (; r < size; r++)
+                if (c.contains(elementData[r]) == complement)
+                    elementData[w++] = elementData[r];
+        } finally {
+            // Preserve behavioral compatibility with AbstractCollection,
+            // even if c.contains() throws.
+            if (r != size) {
+                System.arraycopy(elementData, r,
+                                 elementData, w,
+                                 size - r);
+                w += size - r;
+            }
+            if (w != size) {
+                // clear to let GC do its work
+                for (int i = w; i < size; i++)
+                    elementData[i] = null;
+                modCount += size - w;
+                size = w;
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    /**
+     * Save the state of the <tt>ArrayList</tt> instance to a stream (that
+     * is, serialize it).
+     *
+     * @serialData The length of the array backing the <tt>ArrayList</tt>
+     *             instance is emitted (int), followed by all of its elements
+     *             (each an <tt>Object</tt>) in the proper order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException{
+        // Write out element count, and any hidden stuff
+        int expectedModCount = modCount;
+        s.defaultWriteObject();
+
+        // Write out size as capacity for behavioural compatibility with clone()
+        s.writeInt(size);
+
+        // Write out all elements in the proper order.
+        for (int i=0; i<size; i++) {
+            s.writeObject(elementData[i]);
+        }
+
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        elementData = EMPTY_ELEMENTDATA;
+
+        // Read in size, and any hidden stuff
+        s.defaultReadObject();
+
+        // Read in capacity
+        s.readInt(); // ignored
+
+        if (size > 0) {
+            // be like clone(), allocate array based upon size not capacity
+            ensureCapacityInternal(size);
+
+            Object[] a = elementData;
+            // Read in all elements in the proper order.
+            for (int i=0; i<size; i++) {
+                a[i] = s.readObject();
+            }
+        }
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence), starting at the specified position in the list.
+     * The specified index indicates the first element that would be
+     * returned by an initial call to {@link ListIterator#next next}.
+     * An initial call to {@link ListIterator#previous previous} would
+     * return the element with the specified index minus one.
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public ListIterator<E> listIterator(int index) {
+        if (index < 0 || index > size)
+            throw new IndexOutOfBoundsException("Index: "+index);
+        return new ListItr(index);
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @see #listIterator(int)
+     */
+    public ListIterator<E> listIterator() {
+        return new ListItr(0);
+    }
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * An optimized version of AbstractList.Itr
+     */
+    private class Itr implements Iterator<E> {
+        // Android-changed: Add "limit" field to detect end of iteration.
+        // The "limit" of this iterator. This is the size of the list at the time the
+        // iterator was created. Adding & removing elements will invalidate the iteration
+        // anyway (and cause next() to throw) so saving this value will guarantee that the
+        // value of hasNext() remains stable and won't flap between true and false when elements
+        // are added and removed from the list.
+        protected int limit = ArrayList.this.size;
+
+        int cursor;       // index of next element to return
+        int lastRet = -1; // index of last element returned; -1 if no such
+        int expectedModCount = modCount;
+
+        public boolean hasNext() {
+            return cursor < limit;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            int i = cursor;
+            if (i >= limit)
+                throw new NoSuchElementException();
+            Object[] elementData = ArrayList.this.elementData;
+            if (i >= elementData.length)
+                throw new ConcurrentModificationException();
+            cursor = i + 1;
+            return (E) elementData[lastRet = i];
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            try {
+                ArrayList.this.remove(lastRet);
+                cursor = lastRet;
+                lastRet = -1;
+                expectedModCount = modCount;
+                limit--;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> consumer) {
+            Objects.requireNonNull(consumer);
+            final int size = ArrayList.this.size;
+            int i = cursor;
+            if (i >= size) {
+                return;
+            }
+            final Object[] elementData = ArrayList.this.elementData;
+            if (i >= elementData.length) {
+                throw new ConcurrentModificationException();
+            }
+            while (i != size && modCount == expectedModCount) {
+                consumer.accept((E) elementData[i++]);
+            }
+            // update once at end of iteration to reduce heap write traffic
+            cursor = i;
+            lastRet = i - 1;
+
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * An optimized version of AbstractList.ListItr
+     */
+    private class ListItr extends Itr implements ListIterator<E> {
+        ListItr(int index) {
+            super();
+            cursor = index;
+        }
+
+        public boolean hasPrevious() {
+            return cursor != 0;
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor - 1;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E previous() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            int i = cursor - 1;
+            if (i < 0)
+                throw new NoSuchElementException();
+            Object[] elementData = ArrayList.this.elementData;
+            if (i >= elementData.length)
+                throw new ConcurrentModificationException();
+            cursor = i;
+            return (E) elementData[lastRet = i];
+        }
+
+        public void set(E e) {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            try {
+                ArrayList.this.set(lastRet, e);
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        public void add(E e) {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            try {
+                int i = cursor;
+                ArrayList.this.add(i, e);
+                cursor = i + 1;
+                lastRet = -1;
+                expectedModCount = modCount;
+                limit++;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Returns a view of the portion of this list between the specified
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
+     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
+     * empty.)  The returned list is backed by this list, so non-structural
+     * changes in the returned list are reflected in this list, and vice-versa.
+     * The returned list supports all of the optional list operations.
+     *
+     * <p>This method eliminates the need for explicit range operations (of
+     * the sort that commonly exist for arrays).  Any operation that expects
+     * a list can be used as a range operation by passing a subList view
+     * instead of a whole list.  For example, the following idiom
+     * removes a range of elements from a list:
+     * <pre>
+     *      list.subList(from, to).clear();
+     * </pre>
+     * Similar idioms may be constructed for {@link #indexOf(Object)} and
+     * {@link #lastIndexOf(Object)}, and all of the algorithms in the
+     * {@link Collections} class can be applied to a subList.
+     *
+     * <p>The semantics of the list returned by this method become undefined if
+     * the backing list (i.e., this list) is <i>structurally modified</i> in
+     * any way other than via the returned list.  (Structural modifications are
+     * those that change the size of this list, or otherwise perturb it in such
+     * a fashion that iterations in progress may yield incorrect results.)
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public List<E> subList(int fromIndex, int toIndex) {
+        subListRangeCheck(fromIndex, toIndex, size);
+        return new SubList(this, 0, fromIndex, toIndex);
+    }
+
+    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        if (toIndex > size)
+            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+        if (fromIndex > toIndex)
+            throw new IllegalArgumentException("fromIndex(" + fromIndex +
+                                               ") > toIndex(" + toIndex + ")");
+    }
+
+    private class SubList extends AbstractList<E> implements RandomAccess {
+        private final AbstractList<E> parent;
+        private final int parentOffset;
+        private final int offset;
+        int size;
+
+        SubList(AbstractList<E> parent,
+                int offset, int fromIndex, int toIndex) {
+            this.parent = parent;
+            this.parentOffset = fromIndex;
+            this.offset = offset + fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = ArrayList.this.modCount;
+        }
+
+        public E set(int index, E e) {
+            if (index < 0 || index >= this.size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            E oldValue = (E) ArrayList.this.elementData[offset + index];
+            ArrayList.this.elementData[offset + index] = e;
+            return oldValue;
+        }
+
+        public E get(int index) {
+            if (index < 0 || index >= this.size)
+              throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            return (E) ArrayList.this.elementData[offset + index];
+        }
+
+        public int size() {
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            return this.size;
+        }
+
+        public void add(int index, E e) {
+            if (index < 0 || index > this.size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            parent.add(parentOffset + index, e);
+            this.modCount = parent.modCount;
+            this.size++;
+        }
+
+        public E remove(int index) {
+            if (index < 0 || index >= this.size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            E result = parent.remove(parentOffset + index);
+            this.modCount = parent.modCount;
+            this.size--;
+            return result;
+        }
+
+        protected void removeRange(int fromIndex, int toIndex) {
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            parent.removeRange(parentOffset + fromIndex,
+                               parentOffset + toIndex);
+            this.modCount = parent.modCount;
+            this.size -= toIndex - fromIndex;
+        }
+
+        public boolean addAll(Collection<? extends E> c) {
+            return addAll(this.size, c);
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            if (index < 0 || index > this.size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            int cSize = c.size();
+            if (cSize==0)
+                return false;
+
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            parent.addAll(parentOffset + index, c);
+            this.modCount = parent.modCount;
+            this.size += cSize;
+            return true;
+        }
+
+        public Iterator<E> iterator() {
+            return listIterator();
+        }
+
+        public ListIterator<E> listIterator(final int index) {
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            if (index < 0 || index > this.size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            final int offset = this.offset;
+
+            return new ListIterator<E>() {
+                int cursor = index;
+                int lastRet = -1;
+                int expectedModCount = ArrayList.this.modCount;
+
+                public boolean hasNext() {
+                    return cursor != SubList.this.size;
+                }
+
+                @SuppressWarnings("unchecked")
+                public E next() {
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+                    int i = cursor;
+                    if (i >= SubList.this.size)
+                        throw new NoSuchElementException();
+                    Object[] elementData = ArrayList.this.elementData;
+                    if (offset + i >= elementData.length)
+                        throw new ConcurrentModificationException();
+                    cursor = i + 1;
+                    return (E) elementData[offset + (lastRet = i)];
+                }
+
+                public boolean hasPrevious() {
+                    return cursor != 0;
+                }
+
+                @SuppressWarnings("unchecked")
+                public E previous() {
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+                    int i = cursor - 1;
+                    if (i < 0)
+                        throw new NoSuchElementException();
+                    Object[] elementData = ArrayList.this.elementData;
+                    if (offset + i >= elementData.length)
+                        throw new ConcurrentModificationException();
+                    cursor = i;
+                    return (E) elementData[offset + (lastRet = i)];
+                }
+
+                @SuppressWarnings("unchecked")
+                public void forEachRemaining(Consumer<? super E> consumer) {
+                    Objects.requireNonNull(consumer);
+                    final int size = SubList.this.size;
+                    int i = cursor;
+                    if (i >= size) {
+                        return;
+                    }
+                    final Object[] elementData = ArrayList.this.elementData;
+                    if (offset + i >= elementData.length) {
+                        throw new ConcurrentModificationException();
+                    }
+                    while (i != size && modCount == expectedModCount) {
+                        consumer.accept((E) elementData[offset + (i++)]);
+                    }
+                    // update once at end of iteration to reduce heap write traffic
+                    lastRet = cursor = i;
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+                }
+
+                public int nextIndex() {
+                    return cursor;
+                }
+
+                public int previousIndex() {
+                    return cursor - 1;
+                }
+
+                public void remove() {
+                    if (lastRet < 0)
+                        throw new IllegalStateException();
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+
+                    try {
+                        SubList.this.remove(lastRet);
+                        cursor = lastRet;
+                        lastRet = -1;
+                        expectedModCount = ArrayList.this.modCount;
+                    } catch (IndexOutOfBoundsException ex) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+
+                public void set(E e) {
+                    if (lastRet < 0)
+                        throw new IllegalStateException();
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+
+                    try {
+                        ArrayList.this.set(offset + lastRet, e);
+                    } catch (IndexOutOfBoundsException ex) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+
+                public void add(E e) {
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+
+                    try {
+                        int i = cursor;
+                        SubList.this.add(i, e);
+                        cursor = i + 1;
+                        lastRet = -1;
+                        expectedModCount = ArrayList.this.modCount;
+                    } catch (IndexOutOfBoundsException ex) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new SubList(this, offset, fromIndex, toIndex);
+        }
+
+        private String outOfBoundsMsg(int index) {
+            return "Index: "+index+", Size: "+this.size;
+        }
+
+        public Spliterator<E> spliterator() {
+            if (modCount != ArrayList.this.modCount)
+                throw new ConcurrentModificationException();
+            return new ArrayListSpliterator<E>(ArrayList.this, offset,
+                                               offset + this.size, this.modCount);
+        }
+    }
+
+    @Override
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final int expectedModCount = modCount;
+        @SuppressWarnings("unchecked")
+        final E[] elementData = (E[]) this.elementData;
+        final int size = this.size;
+        for (int i=0; modCount == expectedModCount && i < size; i++) {
+            action.accept(elementData[i]);
+        }
+        // Android-note:
+        // Iterator will not throw a CME if we add something while iterating over the *last* element
+        // forEach will throw a CME in this case.
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new ArrayListSpliterator<>(this, 0, -1, 0);
+    }
+
+    /** Index-based split-by-two, lazily initialized Spliterator */
+    static final class ArrayListSpliterator<E> implements Spliterator<E> {
+
+        /*
+         * If ArrayLists were immutable, or structurally immutable (no
+         * adds, removes, etc), we could implement their spliterators
+         * with Arrays.spliterator. Instead we detect as much
+         * interference during traversal as practical without
+         * sacrificing much performance. We rely primarily on
+         * modCounts. These are not guaranteed to detect concurrency
+         * violations, and are sometimes overly conservative about
+         * within-thread interference, but detect enough problems to
+         * be worthwhile in practice. To carry this out, we (1) lazily
+         * initialize fence and expectedModCount until the latest
+         * point that we need to commit to the state we are checking
+         * against; thus improving precision.  (This doesn't apply to
+         * SubLists, that create spliterators with current non-lazy
+         * values).  (2) We perform only a single
+         * ConcurrentModificationException check at the end of forEach
+         * (the most performance-sensitive method). When using forEach
+         * (as opposed to iterators), we can normally only detect
+         * interference after actions, not before. Further
+         * CME-triggering checks apply to all other possible
+         * violations of assumptions for example null or too-small
+         * elementData array given its size(), that could only have
+         * occurred due to interference.  This allows the inner loop
+         * of forEach to run without any further checks, and
+         * simplifies lambda-resolution. While this does entail a
+         * number of checks, note that in the common case of
+         * list.stream().forEach(a), no checks or other computation
+         * occur anywhere other than inside forEach itself.  The other
+         * less-often-used methods cannot take advantage of most of
+         * these streamlinings.
+         */
+
+        private final ArrayList<E> list;
+        private int index; // current index, modified on advance/split
+        private int fence; // -1 until used; then one past last index
+        private int expectedModCount; // initialized when fence set
+
+        /** Create new spliterator covering the given  range */
+        ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
+                             int expectedModCount) {
+            this.list = list; // OK if null unless traversed
+            this.index = origin;
+            this.fence = fence;
+            this.expectedModCount = expectedModCount;
+        }
+
+        private int getFence() { // initialize fence to size on first use
+            int hi; // (a specialized variant appears in method forEach)
+            ArrayList<E> lst;
+            if ((hi = fence) < 0) {
+                if ((lst = list) == null)
+                    hi = fence = 0;
+                else {
+                    expectedModCount = lst.modCount;
+                    hi = fence = lst.size;
+                }
+            }
+            return hi;
+        }
+
+        public ArrayListSpliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null : // divide range in half unless too small
+                new ArrayListSpliterator<E>(list, lo, index = mid,
+                                            expectedModCount);
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int hi = getFence(), i = index;
+            if (i < hi) {
+                index = i + 1;
+                @SuppressWarnings("unchecked") E e = (E)list.elementData[i];
+                action.accept(e);
+                if (list.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            int i, hi, mc; // hoist accesses and checks from loop
+            ArrayList<E> lst; Object[] a;
+            if (action == null)
+                throw new NullPointerException();
+            if ((lst = list) != null && (a = lst.elementData) != null) {
+                if ((hi = fence) < 0) {
+                    mc = lst.modCount;
+                    hi = lst.size;
+                }
+                else
+                    mc = expectedModCount;
+                if ((i = index) >= 0 && (index = hi) <= a.length) {
+                    for (; i < hi; ++i) {
+                        @SuppressWarnings("unchecked") E e = (E) a[i];
+                        action.accept(e);
+                    }
+                    if (lst.modCount == mc)
+                        return;
+                }
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public long estimateSize() {
+            return (long) (getFence() - index);
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+    }
+
+    @Override
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        // figure out which elements are to be removed
+        // any exception thrown from the filter predicate at this stage
+        // will leave the collection unmodified
+        int removeCount = 0;
+        final BitSet removeSet = new BitSet(size);
+        final int expectedModCount = modCount;
+        final int size = this.size;
+        for (int i=0; modCount == expectedModCount && i < size; i++) {
+            @SuppressWarnings("unchecked")
+            final E element = (E) elementData[i];
+            if (filter.test(element)) {
+                removeSet.set(i);
+                removeCount++;
+            }
+        }
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+
+        // shift surviving elements left over the spaces left by removed elements
+        final boolean anyToRemove = removeCount > 0;
+        if (anyToRemove) {
+            final int newSize = size - removeCount;
+            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
+                i = removeSet.nextClearBit(i);
+                elementData[j] = elementData[i];
+            }
+            for (int k=newSize; k < size; k++) {
+                elementData[k] = null;  // Let gc do its work
+            }
+            this.size = newSize;
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+            modCount++;
+        }
+
+        return anyToRemove;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void replaceAll(UnaryOperator<E> operator) {
+        Objects.requireNonNull(operator);
+        final int expectedModCount = modCount;
+        final int size = this.size;
+        for (int i=0; modCount == expectedModCount && i < size; i++) {
+            elementData[i] = operator.apply((E) elementData[i]);
+        }
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+        modCount++;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void sort(Comparator<? super E> c) {
+        final int expectedModCount = modCount;
+        Arrays.sort((E[]) elementData, 0, size, c);
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+        modCount++;
+    }
+}
diff --git a/java/util/ArrayPrefixHelpers.java b/java/util/ArrayPrefixHelpers.java
new file mode 100644
index 0000000..87c04d1
--- /dev/null
+++ b/java/util/ArrayPrefixHelpers.java
@@ -0,0 +1,706 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinPool;
+import java.util.function.BinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.LongBinaryOperator;
+
+/**
+ * ForkJoin tasks to perform Arrays.parallelPrefix operations.
+ *
+ * @author Doug Lea
+ * @since 1.8
+ */
+class ArrayPrefixHelpers {
+    private ArrayPrefixHelpers() {} // non-instantiable
+
+    /*
+     * Parallel prefix (aka cumulate, scan) task classes
+     * are based loosely on Guy Blelloch's original
+     * algorithm (http://www.cs.cmu.edu/~scandal/alg/scan.html):
+     *  Keep dividing by two to threshold segment size, and then:
+     *   Pass 1: Create tree of partial sums for each segment
+     *   Pass 2: For each segment, cumulate with offset of left sibling
+     *
+     * This version improves performance within FJ framework mainly by
+     * allowing the second pass of ready left-hand sides to proceed
+     * even if some right-hand side first passes are still executing.
+     * It also combines first and second pass for leftmost segment,
+     * and skips the first pass for rightmost segment (whose result is
+     * not needed for second pass).  It similarly manages to avoid
+     * requiring that users supply an identity basis for accumulations
+     * by tracking those segments/subtasks for which the first
+     * existing element is used as base.
+     *
+     * Managing this relies on ORing some bits in the pendingCount for
+     * phases/states: CUMULATE, SUMMED, and FINISHED. CUMULATE is the
+     * main phase bit. When false, segments compute only their sum.
+     * When true, they cumulate array elements. CUMULATE is set at
+     * root at beginning of second pass and then propagated down. But
+     * it may also be set earlier for subtrees with lo==0 (the left
+     * spine of tree). SUMMED is a one bit join count. For leafs, it
+     * is set when summed. For internal nodes, it becomes true when
+     * one child is summed.  When the second child finishes summing,
+     * we then moves up tree to trigger the cumulate phase. FINISHED
+     * is also a one bit join count. For leafs, it is set when
+     * cumulated. For internal nodes, it becomes true when one child
+     * is cumulated.  When the second child finishes cumulating, it
+     * then moves up tree, completing at the root.
+     *
+     * To better exploit locality and reduce overhead, the compute
+     * method loops starting with the current task, moving if possible
+     * to one of its subtasks rather than forking.
+     *
+     * As usual for this sort of utility, there are 4 versions, that
+     * are simple copy/paste/adapt variants of each other.  (The
+     * double and int versions differ from long version solely by
+     * replacing "long" (with case-matching)).
+     */
+
+    // see above
+    static final int CUMULATE = 1;
+    static final int SUMMED   = 2;
+    static final int FINISHED = 4;
+
+    /** The smallest subtask array partition size to use as threshold */
+    static final int MIN_PARTITION = 16;
+
+    static final class CumulateTask<T> extends CountedCompleter<Void> {
+        final T[] array;
+        final BinaryOperator<T> function;
+        CumulateTask<T> left, right;
+        T in, out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public CumulateTask(CumulateTask<T> parent,
+                            BinaryOperator<T> function,
+                            T[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        CumulateTask(CumulateTask<T> parent, BinaryOperator<T> function,
+                     T[] array, int origin, int fence, int threshold,
+                     int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final BinaryOperator<T> fn;
+            final T[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            CumulateTask<T> t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    CumulateTask<T> lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new CumulateTask<T>(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new CumulateTask<T>(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        T pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            T lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.apply(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    T sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.apply(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.apply(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (CumulateTask<T> par;;) {             // propagate
+                        @SuppressWarnings("unchecked") CumulateTask<T> partmp
+                            = (CumulateTask<T>)t.getCompleter();
+                        if ((par = partmp) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; CumulateTask<T> lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                T lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.apply(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        private static final long serialVersionUID = 5293554502939613543L;
+    }
+
+    static final class LongCumulateTask extends CountedCompleter<Void> {
+        final long[] array;
+        final LongBinaryOperator function;
+        LongCumulateTask left, right;
+        long in, out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public LongCumulateTask(LongCumulateTask parent,
+                                LongBinaryOperator function,
+                                long[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        LongCumulateTask(LongCumulateTask parent, LongBinaryOperator function,
+                         long[] array, int origin, int fence, int threshold,
+                         int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final LongBinaryOperator fn;
+            final long[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            LongCumulateTask t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    LongCumulateTask lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new LongCumulateTask(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new LongCumulateTask(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        long pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            long lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.applyAsLong(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    long sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.applyAsLong(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.applyAsLong(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (LongCumulateTask par;;) {            // propagate
+                        if ((par = (LongCumulateTask)t.getCompleter()) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; LongCumulateTask lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                long lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.applyAsLong(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        private static final long serialVersionUID = -5074099945909284273L;
+    }
+
+    static final class DoubleCumulateTask extends CountedCompleter<Void> {
+        final double[] array;
+        final DoubleBinaryOperator function;
+        DoubleCumulateTask left, right;
+        double in, out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public DoubleCumulateTask(DoubleCumulateTask parent,
+                                  DoubleBinaryOperator function,
+                                  double[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        DoubleCumulateTask(DoubleCumulateTask parent, DoubleBinaryOperator function,
+                           double[] array, int origin, int fence, int threshold,
+                           int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final DoubleBinaryOperator fn;
+            final double[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            DoubleCumulateTask t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    DoubleCumulateTask lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new DoubleCumulateTask(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new DoubleCumulateTask(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        double pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            double lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.applyAsDouble(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    double sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.applyAsDouble(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.applyAsDouble(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (DoubleCumulateTask par;;) {            // propagate
+                        if ((par = (DoubleCumulateTask)t.getCompleter()) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; DoubleCumulateTask lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                double lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.applyAsDouble(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        private static final long serialVersionUID = -586947823794232033L;
+    }
+
+    static final class IntCumulateTask extends CountedCompleter<Void> {
+        final int[] array;
+        final IntBinaryOperator function;
+        IntCumulateTask left, right;
+        int in, out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public IntCumulateTask(IntCumulateTask parent,
+                               IntBinaryOperator function,
+                               int[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        IntCumulateTask(IntCumulateTask parent, IntBinaryOperator function,
+                        int[] array, int origin, int fence, int threshold,
+                        int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final IntBinaryOperator fn;
+            final int[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            IntCumulateTask t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    IntCumulateTask lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new IntCumulateTask(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new IntCumulateTask(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        int pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            int lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.applyAsInt(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    int sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.applyAsInt(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.applyAsInt(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (IntCumulateTask par;;) {            // propagate
+                        if ((par = (IntCumulateTask)t.getCompleter()) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; IntCumulateTask lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                int lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.applyAsInt(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        private static final long serialVersionUID = 3731755594596840961L;
+    }
+}
diff --git a/java/util/Arrays.annotated.java b/java/util/Arrays.annotated.java
new file mode 100644
index 0000000..99dec24
--- /dev/null
+++ b/java/util/Arrays.annotated.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.lang.reflect.Array;
+import java.util.concurrent.ForkJoinPool;
+import java.util.function.BinaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.stream.Stream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.DoubleStream;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Arrays {
+
+Arrays() { throw new RuntimeException("Stub!"); }
+
+public static void sort(int @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(int @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(long @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(long @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(short @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(short @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(char @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(char @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(byte @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(byte @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(float @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(float @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(double @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(double @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(byte @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(byte @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(char @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(char @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(short @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(short @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(int @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(int @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(long @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(long @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(float @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(float @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(double @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(double @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T extends java.lang.Comparable<? super T>> void parallelSort(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static <T extends java.lang.Comparable<? super T>> void parallelSort(T @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T> void parallelSort(T @libcore.util.NonNull [] a, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static <T> void parallelSort(T @libcore.util.NonNull [] a, int fromIndex, int toIndex, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static void sort([email protected] Object @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort([email protected] Object @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T> void sort(T @libcore.util.NonNull [] a, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static <T> void sort(T @libcore.util.NonNull [] a, int fromIndex, int toIndex, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static <T> void parallelPrefix(T @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.BinaryOperator<@libcore.util.NullFromTypeParam T> op) { throw new RuntimeException("Stub!"); }
+
+public static <T> void parallelPrefix(T @libcore.util.NonNull [] array, int fromIndex, int toIndex, @libcore.util.NonNull java.util.function.BinaryOperator<@libcore.util.NullFromTypeParam T> op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(long @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.LongBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(long @libcore.util.NonNull [] array, int fromIndex, int toIndex, @libcore.util.NonNull java.util.function.LongBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(double @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.DoubleBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(double @libcore.util.NonNull [] array, int fromIndex, int toIndex, @libcore.util.NonNull java.util.function.DoubleBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(int @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(int @libcore.util.NonNull [] array, int fromIndex, int toIndex, @libcore.util.NonNull java.util.function.IntBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(long @libcore.util.NonNull [] a, long key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(long @libcore.util.NonNull [] a, int fromIndex, int toIndex, long key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(int @libcore.util.NonNull [] a, int key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(int @libcore.util.NonNull [] a, int fromIndex, int toIndex, int key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(short @libcore.util.NonNull [] a, short key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(short @libcore.util.NonNull [] a, int fromIndex, int toIndex, short key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(char @libcore.util.NonNull [] a, char key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(char @libcore.util.NonNull [] a, int fromIndex, int toIndex, char key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(byte @libcore.util.NonNull [] a, byte key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(byte @libcore.util.NonNull [] a, int fromIndex, int toIndex, byte key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(double @libcore.util.NonNull [] a, double key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(double @libcore.util.NonNull [] a, int fromIndex, int toIndex, double key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(float @libcore.util.NonNull [] a, float key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(float @libcore.util.NonNull [] a, int fromIndex, int toIndex, float key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch([email protected] Object @libcore.util.NonNull [] a, @libcore.util.NonNull java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch([email protected] Object @libcore.util.NonNull [] a, int fromIndex, int toIndex, @libcore.util.NonNull java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public static <T> int binarySearch(T @libcore.util.NonNull [] a, @libcore.util.NullFromTypeParam T key, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static <T> int binarySearch(T @libcore.util.NonNull [] a, int fromIndex, int toIndex, @libcore.util.NullFromTypeParam T key, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(long @libcore.util.Nullable [] a, long @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(int @libcore.util.Nullable [] a, int @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(short @libcore.util.Nullable [] a, short @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(char @libcore.util.Nullable [] a, char @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(byte @libcore.util.Nullable [] a, byte @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(boolean @libcore.util.Nullable [] a, boolean @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(double @libcore.util.Nullable [] a, double @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(float @libcore.util.Nullable [] a, float @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals([email protected] Object @libcore.util.Nullable [] a, [email protected] Object @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static void fill(long @libcore.util.NonNull [] a, long val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(long @libcore.util.NonNull [] a, int fromIndex, int toIndex, long val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(int @libcore.util.NonNull [] a, int val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(int @libcore.util.NonNull [] a, int fromIndex, int toIndex, int val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(short @libcore.util.NonNull [] a, short val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(short @libcore.util.NonNull [] a, int fromIndex, int toIndex, short val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(char @libcore.util.NonNull [] a, char val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(char @libcore.util.NonNull [] a, int fromIndex, int toIndex, char val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(byte @libcore.util.NonNull [] a, byte val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(byte @libcore.util.NonNull [] a, int fromIndex, int toIndex, byte val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(boolean @libcore.util.NonNull [] a, boolean val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(boolean @libcore.util.NonNull [] a, int fromIndex, int toIndex, boolean val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(double @libcore.util.NonNull [] a, double val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(double @libcore.util.NonNull [] a, int fromIndex, int toIndex, double val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(float @libcore.util.NonNull [] a, float val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(float @libcore.util.NonNull [] a, int fromIndex, int toIndex, float val) { throw new RuntimeException("Stub!"); }
+
+public static void fill([email protected] Object @libcore.util.NonNull [] a, @libcore.util.Nullable java.lang.Object val) { throw new RuntimeException("Stub!"); }
+
+public static void fill([email protected] Object @libcore.util.NonNull [] a, int fromIndex, int toIndex, @libcore.util.Nullable java.lang.Object val) { throw new RuntimeException("Stub!"); }
+
+public static <T> T @libcore.util.NonNull [] copyOf(T @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static <T, U> T @libcore.util.NonNull [] copyOf(U @libcore.util.NonNull [] original, int newLength, @libcore.util.NonNull java.lang.Class<? extends T[]> newType) { throw new RuntimeException("Stub!"); }
+
+public static byte @libcore.util.NonNull [] copyOf(byte @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static short @libcore.util.NonNull [] copyOf(short @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static int @libcore.util.NonNull [] copyOf(int @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static long @libcore.util.NonNull [] copyOf(long @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static char @libcore.util.NonNull [] copyOf(char @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static float @libcore.util.NonNull [] copyOf(float @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static double @libcore.util.NonNull [] copyOf(double @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static boolean @libcore.util.NonNull [] copyOf(boolean @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static <T> T @libcore.util.NonNull [] copyOfRange(T @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static <T, U> T @libcore.util.NonNull [] copyOfRange(U @libcore.util.NonNull [] original, int from, int to, @libcore.util.NonNull java.lang.Class<? extends T[]> newType) { throw new RuntimeException("Stub!"); }
+
+public static byte @libcore.util.NonNull [] copyOfRange(byte @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static short @libcore.util.NonNull [] copyOfRange(short @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static int @libcore.util.NonNull [] copyOfRange(int @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static long @libcore.util.NonNull [] copyOfRange(long @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static char @libcore.util.NonNull [] copyOfRange(char @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static float @libcore.util.NonNull [] copyOfRange(float @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static double @libcore.util.NonNull [] copyOfRange(double @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static boolean @libcore.util.NonNull [] copyOfRange(boolean @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
[email protected]
[email protected] public static <T> java.util.List<@libcore.util.NullFromTypeParam T> asList(T @libcore.util.NonNull ... a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(long @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(int @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(short @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(char @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(byte @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(boolean @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(float @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(double @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode([email protected] Object @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int deepHashCode([email protected] Object @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static boolean deepEquals([email protected] Object @libcore.util.Nullable [] a1, [email protected] Object @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(long @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(int @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(short @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(char @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(byte @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(boolean @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(float @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(double @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString([email protected] Object @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String deepToString([email protected] Object @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static <T> void setAll(T @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntFunction<? extends @libcore.util.NullFromTypeParam T> generator) { throw new RuntimeException("Stub!"); }
+
+public static <T> void parallelSetAll(T @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntFunction<? extends @libcore.util.NullFromTypeParam T> generator) { throw new RuntimeException("Stub!"); }
+
+public static void setAll(int @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntUnaryOperator generator) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSetAll(int @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntUnaryOperator generator) { throw new RuntimeException("Stub!"); }
+
+public static void setAll(long @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntToLongFunction generator) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSetAll(long @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntToLongFunction generator) { throw new RuntimeException("Stub!"); }
+
+public static void setAll(double @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntToDoubleFunction generator) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSetAll(double @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntToDoubleFunction generator) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Spliterator<@libcore.util.NullFromTypeParam T> spliterator(T @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Spliterator<@libcore.util.NullFromTypeParam T> spliterator(T @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfInt spliterator(int @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfInt spliterator(int @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfLong spliterator(long @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfLong spliterator(long @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfDouble spliterator(double @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfDouble spliterator(double @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.stream.Stream<@libcore.util.NullFromTypeParam T> stream(T @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.stream.Stream<@libcore.util.NullFromTypeParam T> stream(T @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.IntStream stream(int @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.IntStream stream(int @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.LongStream stream(long @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.LongStream stream(long @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.DoubleStream stream(double @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.DoubleStream stream(double @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/Arrays.java b/java/util/Arrays.java
new file mode 100644
index 0000000..6da3e5d
--- /dev/null
+++ b/java/util/Arrays.java
@@ -0,0 +1,5046 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.lang.reflect.Array;
+import java.util.concurrent.ForkJoinPool;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntFunction;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.UnaryOperator;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * This class contains various methods for manipulating arrays (such as
+ * sorting and searching). This class also contains a static factory
+ * that allows arrays to be viewed as lists.
+ *
+ * <p>The methods in this class all throw a {@code NullPointerException},
+ * if the specified array reference is null, except where noted.
+ *
+ * <p>The documentation for the methods contained in this class includes
+ * briefs description of the <i>implementations</i>. Such descriptions should
+ * be regarded as <i>implementation notes</i>, rather than parts of the
+ * <i>specification</i>. Implementors should feel free to substitute other
+ * algorithms, so long as the specification itself is adhered to. (For
+ * example, the algorithm used by {@code sort(Object[])} does not have to be
+ * a MergeSort, but it does have to be <i>stable</i>.)
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author Josh Bloch
+ * @author Neal Gafter
+ * @author John Rose
+ * @since  1.2
+ */
+public class Arrays {
+
+    /**
+     * The minimum array length below which a parallel sorting
+     * algorithm will not further partition the sorting task. Using
+     * smaller sizes typically results in memory contention across
+     * tasks that makes parallel speedups unlikely.
+     * @hide
+     */
+    // Android-changed: Make MIN_ARRAY_SORT_GRAN public and @hide (used by harmony ArraysTest)
+    public static final int MIN_ARRAY_SORT_GRAN = 1 << 13;
+
+    // Suppresses default constructor, ensuring non-instantiability.
+    private Arrays() {}
+
+    /**
+     * A comparator that implements the natural ordering of a group of
+     * mutually comparable elements. May be used when a supplied
+     * comparator is null. To simplify code-sharing within underlying
+     * implementations, the compare method only declares type Object
+     * for its second argument.
+     *
+     * Arrays class implementor's note: It is an empirical matter
+     * whether ComparableTimSort offers any performance benefit over
+     * TimSort used with this comparator.  If not, you are better off
+     * deleting or bypassing ComparableTimSort.  There is currently no
+     * empirical case for separating them for parallel sorting, so all
+     * public Object parallelSort methods use the same comparator
+     * based implementation.
+     */
+    static final class NaturalOrder implements Comparator<Object> {
+        @SuppressWarnings("unchecked")
+        public int compare(Object first, Object second) {
+            return ((Comparable<Object>)first).compareTo(second);
+        }
+        static final NaturalOrder INSTANCE = new NaturalOrder();
+    }
+
+    /**
+     * Checks that {@code fromIndex} and {@code toIndex} are in
+     * the range and throws an exception if they aren't.
+     */
+    private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
+        if (fromIndex > toIndex) {
+            throw new IllegalArgumentException(
+                    "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+        }
+        if (fromIndex < 0) {
+            throw new ArrayIndexOutOfBoundsException(fromIndex);
+        }
+        if (toIndex > arrayLength) {
+            throw new ArrayIndexOutOfBoundsException(toIndex);
+        }
+    }
+
+    /*
+     * Sorting methods. Note that all public "sort" methods take the
+     * same form: Performing argument checks if necessary, and then
+     * expanding arguments into those required for the internal
+     * implementation methods residing in other package-private
+     * classes (except for legacyMergeSort, included in this class).
+     */
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(int[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(int[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(long[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(long[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(short[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(short[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(char[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(char[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(byte[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(byte[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(float[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(float[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(double[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(double[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(byte[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1);
+        else
+            new ArraysParallelSortHelpers.FJByte.Sorter
+                (null, a, new byte[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(byte[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+        else
+            new ArraysParallelSortHelpers.FJByte.Sorter
+                (null, a, new byte[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(char[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJChar.Sorter
+                (null, a, new char[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+      @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(char[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJChar.Sorter
+                (null, a, new char[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(short[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJShort.Sorter
+                (null, a, new short[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(short[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJShort.Sorter
+                (null, a, new short[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(int[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJInt.Sorter
+                (null, a, new int[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(int[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJInt.Sorter
+                (null, a, new int[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(long[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJLong.Sorter
+                (null, a, new long[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(long[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJLong.Sorter
+                (null, a, new long[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(float[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJFloat.Sorter
+                (null, a, new float[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(float[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJFloat.Sorter
+                (null, a, new float[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(double[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJDouble.Sorter
+                (null, a, new double[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(double[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJDouble.Sorter
+                (null, a, new double[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array of objects into ascending order, according
+     * to the {@linkplain Comparable natural ordering} of its elements.
+     * All elements in the array must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in the array must be
+     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)} must
+     * not throw a {@code ClassCastException} for any elements {@code e1}
+     * and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     *
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and integers)
+     * @throws IllegalArgumentException (optional) if the natural
+     *         ordering of the array elements is found to violate the
+     *         {@link Comparable} contract
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>> void parallelSort(T[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, 0, n, NaturalOrder.INSTANCE, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the specified array of objects into
+     * ascending order, according to the
+     * {@linkplain Comparable natural ordering} of its
+     * elements.  The range to be sorted extends from index
+     * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
+     * (If {@code fromIndex==toIndex}, the range to be sorted is empty.)  All
+     * elements in this range must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in this range must be <i>mutually
+     * comparable</i> (that is, {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>>
+    void parallelSort(T[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, fromIndex, toIndex, NaturalOrder.INSTANCE, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke();
+    }
+
+    /**
+     * Sorts the specified array of objects according to the order induced by
+     * the specified comparator.  All elements in the array must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param cmp the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator
+     * @throws IllegalArgumentException (optional) if the comparator is
+     *         found to violate the {@link java.util.Comparator} contract
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> void parallelSort(T[] a, Comparator<? super T> cmp) {
+        if (cmp == null)
+            cmp = NaturalOrder.INSTANCE;
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, 0, n, cmp, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the specified array of objects according
+     * to the order induced by the specified comparator.  The range to be
+     * sorted extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be sorted is empty.)  All elements in the range must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the range).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @param cmp the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> void parallelSort(T[] a, int fromIndex, int toIndex,
+                                        Comparator<? super T> cmp) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        if (cmp == null)
+            cmp = NaturalOrder.INSTANCE;
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, fromIndex, toIndex, cmp, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
+    }
+
+    /*
+     * Sorting of complex type arrays.
+     */
+
+    // Android-removed: LegacyMergeSort class (unused on Android).
+
+    /**
+     * Sorts the specified array of objects into ascending order, according
+     * to the {@linkplain Comparable natural ordering} of its elements.
+     * All elements in the array must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in the array must be
+     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)} must
+     * not throw a {@code ClassCastException} for any elements {@code e1}
+     * and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param a the array to be sorted
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and integers)
+     * @throws IllegalArgumentException (optional) if the natural
+     *         ordering of the array elements is found to violate the
+     *         {@link Comparable} contract
+     */
+    public static void sort(Object[] a) {
+        // Android-removed: LegacyMergeSort support
+        // if (LegacyMergeSort.userRequested)
+        //     legacyMergeSort(a);
+        // else
+            ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
+    }
+
+    // Android-removed: legacyMergeSort() (unused on Android)
+
+    /**
+     * Sorts the specified range of the specified array of objects into
+     * ascending order, according to the
+     * {@linkplain Comparable natural ordering} of its
+     * elements.  The range to be sorted extends from index
+     * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
+     * (If {@code fromIndex==toIndex}, the range to be sorted is empty.)  All
+     * elements in this range must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in this range must be <i>mutually
+     * comparable</i> (that is, {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     */
+    public static void sort(Object[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        // Android-removed: LegacyMergeSort support
+        // if (LegacyMergeSort.userRequested)
+        //     legacyMergeSort(a, fromIndex, toIndex);
+        // else
+            ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0);
+    }
+
+    // Android-removed: legacyMergeSort() (unused on Android)
+
+    /**
+     * Tuning parameter: list size at or below which insertion sort will be
+     * used in preference to mergesort.
+     * To be removed in a future release.
+     */
+    private static final int INSERTIONSORT_THRESHOLD = 7;
+
+    /**
+     * Src is the source array that starts at index 0
+     * Dest is the (possibly larger) array destination with a possible offset
+     * low is the index in dest to start sorting
+     * high is the end index in dest to end sorting
+     * off is the offset to generate corresponding low, high in src
+     * To be removed in a future release.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private static void mergeSort(Object[] src,
+                                  Object[] dest,
+                                  int low,
+                                  int high,
+                                  int off) {
+        int length = high - low;
+
+        // Insertion sort on smallest arrays
+        if (length < INSERTIONSORT_THRESHOLD) {
+            for (int i=low; i<high; i++)
+                for (int j=i; j>low &&
+                         ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
+                    swap(dest, j, j-1);
+            return;
+        }
+
+        // Recursively sort halves of dest into src
+        int destLow  = low;
+        int destHigh = high;
+        low  += off;
+        high += off;
+        int mid = (low + high) >>> 1;
+        mergeSort(dest, src, low, mid, -off);
+        mergeSort(dest, src, mid, high, -off);
+
+        // If list is already sorted, just copy from src to dest.  This is an
+        // optimization that results in faster sorts for nearly ordered lists.
+        if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
+            System.arraycopy(src, low, dest, destLow, length);
+            return;
+        }
+
+        // Merge sorted halves (now in src) into dest
+        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
+            if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
+                dest[i] = src[p++];
+            else
+                dest[i] = src[q++];
+        }
+    }
+
+    /**
+     * Swaps x[a] with x[b].
+     */
+    private static void swap(Object[] x, int a, int b) {
+        Object t = x[a];
+        x[a] = x[b];
+        x[b] = t;
+    }
+
+    /**
+     * Sorts the specified array of objects according to the order induced by
+     * the specified comparator.  All elements in the array must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param c the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator
+     * @throws IllegalArgumentException (optional) if the comparator is
+     *         found to violate the {@link Comparator} contract
+     */
+    public static <T> void sort(T[] a, Comparator<? super T> c) {
+        if (c == null) {
+            sort(a);
+        } else {
+        // Android-removed: LegacyMergeSort support
+            // if (LegacyMergeSort.userRequested)
+            //     legacyMergeSort(a, c);
+            // else
+                TimSort.sort(a, 0, a.length, c, null, 0, 0);
+        }
+    }
+
+    // Android-removed: legacyMergeSort() (unused on Android)
+
+    /**
+     * Sorts the specified range of the specified array of objects according
+     * to the order induced by the specified comparator.  The range to be
+     * sorted extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be sorted is empty.)  All elements in the range must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the range).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @param c the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator.
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the comparator is found to violate the
+     *         {@link Comparator} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     */
+    public static <T> void sort(T[] a, int fromIndex, int toIndex,
+                                Comparator<? super T> c) {
+        if (c == null) {
+            sort(a, fromIndex, toIndex);
+        } else {
+            rangeCheck(a.length, fromIndex, toIndex);
+            // Android-removed: LegacyMergeSort support
+            // if (LegacyMergeSort.userRequested)
+            //     legacyMergeSort(a, fromIndex, toIndex, c);
+            // else
+                TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
+        }
+    }
+
+    // Android-removed: legacyMergeSort() (unused on Android)
+    // Android-removed: mergeSort() (unused on Android)
+
+    // Parallel prefix
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+     * then upon return the array holds {@code [2, 3, 3, 6]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * @param <T> the class of the objects in the array
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static <T> void parallelPrefix(T[] array, BinaryOperator<T> op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.CumulateTask<>
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(Object[], BinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param <T> the class of the objects in the array
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static <T> void parallelPrefix(T[] array, int fromIndex,
+                                          int toIndex, BinaryOperator<T> op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.CumulateTask<>
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+     * then upon return the array holds {@code [2, 3, 3, 6]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(long[] array, LongBinaryOperator op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.LongCumulateTask
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(long[], LongBinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(long[] array, int fromIndex,
+                                      int toIndex, LongBinaryOperator op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.LongCumulateTask
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2.0, 1.0, 0.0, 3.0]} and the operation performs addition,
+     * then upon return the array holds {@code [2.0, 3.0, 3.0, 6.0]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * <p> Because floating-point operations may not be strictly associative,
+     * the returned result may not be identical to the value that would be
+     * obtained if the operation was performed sequentially.
+     *
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free function to perform the cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(double[] array, DoubleBinaryOperator op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.DoubleCumulateTask
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(double[], DoubleBinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(double[] array, int fromIndex,
+                                      int toIndex, DoubleBinaryOperator op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.DoubleCumulateTask
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+     * then upon return the array holds {@code [2, 3, 3, 6]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(int[] array, IntBinaryOperator op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.IntCumulateTask
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(int[], IntBinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(int[] array, int fromIndex,
+                                      int toIndex, IntBinaryOperator op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.IntCumulateTask
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    // Searching
+
+    /**
+     * Searches the specified array of longs for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(long[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(long[] a, long key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of longs for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(long[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(long[] a, int fromIndex, int toIndex,
+                                   long key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(long[] a, int fromIndex, int toIndex,
+                                     long key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            long midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of ints for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(int[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(int[] a, int key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of ints for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(int[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(int[] a, int fromIndex, int toIndex,
+                                   int key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(int[] a, int fromIndex, int toIndex,
+                                     int key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            int midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of shorts for the specified value using
+     * the binary search algorithm.  The array must be sorted
+     * (as by the {@link #sort(short[])} method) prior to making this call.  If
+     * it is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(short[] a, short key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of shorts for the specified value using
+     * the binary search algorithm.
+     * The range must be sorted
+     * (as by the {@link #sort(short[], int, int)} method)
+     * prior to making this call.  If
+     * it is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(short[] a, int fromIndex, int toIndex,
+                                   short key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(short[] a, int fromIndex, int toIndex,
+                                     short key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            short midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of chars for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(char[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(char[] a, char key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of chars for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(char[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(char[] a, int fromIndex, int toIndex,
+                                   char key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(char[] a, int fromIndex, int toIndex,
+                                     char key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            char midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of bytes for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(byte[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(byte[] a, byte key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of bytes for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(byte[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(byte[] a, int fromIndex, int toIndex,
+                                   byte key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(byte[] a, int fromIndex, int toIndex,
+                                     byte key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            byte midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of doubles for the specified value using
+     * the binary search algorithm.  The array must be sorted
+     * (as by the {@link #sort(double[])} method) prior to making this call.
+     * If it is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.  This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(double[] a, double key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of doubles for the specified value using
+     * the binary search algorithm.
+     * The range must be sorted
+     * (as by the {@link #sort(double[], int, int)} method)
+     * prior to making this call.
+     * If it is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.  This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(double[] a, int fromIndex, int toIndex,
+                                   double key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(double[] a, int fromIndex, int toIndex,
+                                     double key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            double midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;  // Neither val is NaN, thisVal is smaller
+            else if (midVal > key)
+                high = mid - 1; // Neither val is NaN, thisVal is larger
+            else {
+                long midBits = Double.doubleToLongBits(midVal);
+                long keyBits = Double.doubleToLongBits(key);
+                if (midBits == keyBits)     // Values are equal
+                    return mid;             // Key found
+                else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN)
+                    low = mid + 1;
+                else                        // (0.0, -0.0) or (NaN, !NaN)
+                    high = mid - 1;
+            }
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of floats for the specified value using
+     * the binary search algorithm. The array must be sorted
+     * (as by the {@link #sort(float[])} method) prior to making this call. If
+     * it is not sorted, the results are undefined. If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found. This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key. Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(float[] a, float key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of floats for the specified value using
+     * the binary search algorithm.
+     * The range must be sorted
+     * (as by the {@link #sort(float[], int, int)} method)
+     * prior to making this call. If
+     * it is not sorted, the results are undefined. If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found. This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key. Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(float[] a, int fromIndex, int toIndex,
+                                   float key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(float[] a, int fromIndex, int toIndex,
+                                     float key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            float midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;  // Neither val is NaN, thisVal is smaller
+            else if (midVal > key)
+                high = mid - 1; // Neither val is NaN, thisVal is larger
+            else {
+                int midBits = Float.floatToIntBits(midVal);
+                int keyBits = Float.floatToIntBits(key);
+                if (midBits == keyBits)     // Values are equal
+                    return mid;             // Key found
+                else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN)
+                    low = mid + 1;
+                else                        // (0.0, -0.0) or (NaN, !NaN)
+                    high = mid - 1;
+            }
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array for the specified object using the binary
+     * search algorithm. The array must be sorted into ascending order
+     * according to the
+     * {@linkplain Comparable natural ordering}
+     * of its elements (as by the
+     * {@link #sort(Object[])} method) prior to making this call.
+     * If it is not sorted, the results are undefined.
+     * (If the array contains elements that are not mutually comparable (for
+     * example, strings and integers), it <i>cannot</i> be sorted according
+     * to the natural ordering of its elements, hence results are undefined.)
+     * If the array contains multiple
+     * elements equal to the specified object, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the search key is not comparable to the
+     *         elements of the array.
+     */
+    public static int binarySearch(Object[] a, Object key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array for the specified object using the binary
+     * search algorithm.
+     * The range must be sorted into ascending order
+     * according to the
+     * {@linkplain Comparable natural ordering}
+     * of its elements (as by the
+     * {@link #sort(Object[], int, int)} method) prior to making this
+     * call.  If it is not sorted, the results are undefined.
+     * (If the range contains elements that are not mutually comparable (for
+     * example, strings and integers), it <i>cannot</i> be sorted according
+     * to the natural ordering of its elements, hence results are undefined.)
+     * If the range contains multiple
+     * elements equal to the specified object, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the search key is not comparable to the
+     *         elements of the array within the specified range.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(Object[] a, int fromIndex, int toIndex,
+                                   Object key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(Object[] a, int fromIndex, int toIndex,
+                                     Object key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            @SuppressWarnings("rawtypes")
+            Comparable midVal = (Comparable)a[mid];
+            @SuppressWarnings("unchecked")
+            int cmp = midVal.compareTo(key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array for the specified object using the binary
+     * search algorithm.  The array must be sorted into ascending order
+     * according to the specified comparator (as by the
+     * {@link #sort(Object[], Comparator) sort(T[], Comparator)}
+     * method) prior to making this call.  If it is
+     * not sorted, the results are undefined.
+     * If the array contains multiple
+     * elements equal to the specified object, there is no guarantee which one
+     * will be found.
+     *
+     * @param <T> the class of the objects in the array
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @param c the comparator by which the array is ordered.  A
+     *        <tt>null</tt> value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator,
+     *         or the search key is not comparable to the
+     *         elements of the array using this comparator.
+     */
+    public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c) {
+        return binarySearch0(a, 0, a.length, key, c);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array for the specified object using the binary
+     * search algorithm.
+     * The range must be sorted into ascending order
+     * according to the specified comparator (as by the
+     * {@link #sort(Object[], int, int, Comparator)
+     * sort(T[], int, int, Comparator)}
+     * method) prior to making this call.
+     * If it is not sorted, the results are undefined.
+     * If the range contains multiple elements equal to the specified object,
+     * there is no guarantee which one will be found.
+     *
+     * @param <T> the class of the objects in the array
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @param c the comparator by which the array is ordered.  A
+     *        <tt>null</tt> value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the range contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator,
+     *         or the search key is not comparable to the
+     *         elements in the range using this comparator.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static <T> int binarySearch(T[] a, int fromIndex, int toIndex,
+                                       T key, Comparator<? super T> c) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key, c);
+    }
+
+    // Like public version, but without range checks.
+    private static <T> int binarySearch0(T[] a, int fromIndex, int toIndex,
+                                         T key, Comparator<? super T> c) {
+        if (c == null) {
+            return binarySearch0(a, fromIndex, toIndex, key);
+        }
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            T midVal = a[mid];
+            int cmp = c.compare(midVal, key);
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    // Equality Testing
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of longs are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(long[] a, long[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of ints are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(int[] a, int[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of shorts are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(short[] a, short a2[]) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of chars are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(char[] a, char[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of bytes are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(byte[] a, byte[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of booleans are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(boolean[] a, boolean[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of doubles are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * Two doubles <tt>d1</tt> and <tt>d2</tt> are considered equal if:
+     * <pre>    <tt>new Double(d1).equals(new Double(d2))</tt></pre>
+     * (Unlike the <tt>==</tt> operator, this method considers
+     * <tt>NaN</tt> equals to itself, and 0.0d unequal to -0.0d.)
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     * @see Double#equals(Object)
+     */
+    public static boolean equals(double[] a, double[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (Double.doubleToLongBits(a[i])!=Double.doubleToLongBits(a2[i]))
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of floats are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * Two floats <tt>f1</tt> and <tt>f2</tt> are considered equal if:
+     * <pre>    <tt>new Float(f1).equals(new Float(f2))</tt></pre>
+     * (Unlike the <tt>==</tt> operator, this method considers
+     * <tt>NaN</tt> equals to itself, and 0.0f unequal to -0.0f.)
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     * @see Float#equals(Object)
+     */
+    public static boolean equals(float[] a, float[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (Float.floatToIntBits(a[i])!=Float.floatToIntBits(a2[i]))
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of Objects are
+     * <i>equal</i> to one another.  The two arrays are considered equal if
+     * both arrays contain the same number of elements, and all corresponding
+     * pairs of elements in the two arrays are equal.  Two objects <tt>e1</tt>
+     * and <tt>e2</tt> are considered <i>equal</i> if <tt>(e1==null ? e2==null
+     * : e1.equals(e2))</tt>.  In other words, the two arrays are equal if
+     * they contain the same elements in the same order.  Also, two array
+     * references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(Object[] a, Object[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++) {
+            Object o1 = a[i];
+            Object o2 = a2[i];
+            if (!(o1==null ? o2==null : o1.equals(o2)))
+                return false;
+        }
+
+        return true;
+    }
+
+    // Filling
+
+    /**
+     * Assigns the specified long value to each element of the specified array
+     * of longs.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(long[] a, long val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified long value to each element of the specified
+     * range of the specified array of longs.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(long[] a, int fromIndex, int toIndex, long val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified int value to each element of the specified array
+     * of ints.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(int[] a, int val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified int value to each element of the specified
+     * range of the specified array of ints.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(int[] a, int fromIndex, int toIndex, int val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified short value to each element of the specified array
+     * of shorts.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(short[] a, short val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified short value to each element of the specified
+     * range of the specified array of shorts.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(short[] a, int fromIndex, int toIndex, short val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified char value to each element of the specified array
+     * of chars.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(char[] a, char val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified char value to each element of the specified
+     * range of the specified array of chars.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(char[] a, int fromIndex, int toIndex, char val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified byte value to each element of the specified array
+     * of bytes.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(byte[] a, byte val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified byte value to each element of the specified
+     * range of the specified array of bytes.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(byte[] a, int fromIndex, int toIndex, byte val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified boolean value to each element of the specified
+     * array of booleans.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(boolean[] a, boolean val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified boolean value to each element of the specified
+     * range of the specified array of booleans.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(boolean[] a, int fromIndex, int toIndex,
+                            boolean val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified double value to each element of the specified
+     * array of doubles.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(double[] a, double val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified double value to each element of the specified
+     * range of the specified array of doubles.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(double[] a, int fromIndex, int toIndex,double val){
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified float value to each element of the specified array
+     * of floats.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(float[] a, float val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified float value to each element of the specified
+     * range of the specified array of floats.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(float[] a, int fromIndex, int toIndex, float val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified Object reference to each element of the specified
+     * array of Objects.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     * @throws ArrayStoreException if the specified value is not of a
+     *         runtime type that can be stored in the specified array
+     */
+    public static void fill(Object[] a, Object val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified Object reference to each element of the specified
+     * range of the specified array of Objects.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     * @throws ArrayStoreException if the specified value is not of a
+     *         runtime type that can be stored in the specified array
+     */
+    public static void fill(Object[] a, int fromIndex, int toIndex, Object val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    // Cloning
+
+    /**
+     * Copies the specified array, truncating or padding with nulls (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>null</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     * The resulting array is of exactly the same class as the original array.
+     *
+     * @param <T> the class of the objects in the array
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with nulls
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] copyOf(T[] original, int newLength) {
+        return (T[]) copyOf(original, newLength, original.getClass());
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with nulls (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>null</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     * The resulting array is of the class <tt>newType</tt>.
+     *
+     * @param <U> the class of the objects in the original array
+     * @param <T> the class of the objects in the returned array
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @param newType the class of the copy to be returned
+     * @return a copy of the original array, truncated or padded with nulls
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws ArrayStoreException if an element copied from
+     *     <tt>original</tt> is not of a runtime type that can be stored in
+     *     an array of class <tt>newType</tt>
+     * @since 1.6
+     */
+    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
+        @SuppressWarnings("unchecked")
+        T[] copy = ((Object)newType == (Object)Object[].class)
+            ? (T[]) new Object[newLength]
+            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>(byte)0</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static byte[] copyOf(byte[] original, int newLength) {
+        byte[] copy = new byte[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>(short)0</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static short[] copyOf(short[] original, int newLength) {
+        short[] copy = new short[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>0</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static int[] copyOf(int[] original, int newLength) {
+        int[] copy = new int[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>0L</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static long[] copyOf(long[] original, int newLength) {
+        long[] copy = new long[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with null characters (if necessary)
+     * so the copy has the specified length.  For all indices that are valid
+     * in both the original array and the copy, the two arrays will contain
+     * identical values.  For any indices that are valid in the copy but not
+     * the original, the copy will contain <tt>'\\u000'</tt>.  Such indices
+     * will exist if and only if the specified length is greater than that of
+     * the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with null characters
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static char[] copyOf(char[] original, int newLength) {
+        char[] copy = new char[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>0f</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static float[] copyOf(float[] original, int newLength) {
+        float[] copy = new float[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>0d</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static double[] copyOf(double[] original, int newLength) {
+        double[] copy = new double[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with <tt>false</tt> (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>false</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with false elements
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static boolean[] copyOf(boolean[] original, int newLength) {
+        boolean[] copy = new boolean[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>null</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     * <p>
+     * The resulting array is of exactly the same class as the original array.
+     *
+     * @param <T> the class of the objects in the array
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with nulls to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] copyOfRange(T[] original, int from, int to) {
+        return copyOfRange(original, from, to, (Class<? extends T[]>) original.getClass());
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>null</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     * The resulting array is of the class <tt>newType</tt>.
+     *
+     * @param <U> the class of the objects in the original array
+     * @param <T> the class of the objects in the returned array
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @param newType the class of the copy to be returned
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with nulls to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws ArrayStoreException if an element copied from
+     *     <tt>original</tt> is not of a runtime type that can be stored in
+     *     an array of class <tt>newType</tt>.
+     * @since 1.6
+     */
+    public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        @SuppressWarnings("unchecked")
+        T[] copy = ((Object)newType == (Object)Object[].class)
+            ? (T[]) new Object[newLength]
+            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>(byte)0</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static byte[] copyOfRange(byte[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        byte[] copy = new byte[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>(short)0</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static short[] copyOfRange(short[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        short[] copy = new short[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>0</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static int[] copyOfRange(int[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        int[] copy = new int[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>0L</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static long[] copyOfRange(long[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        long[] copy = new long[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>'\\u000'</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with null characters to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static char[] copyOfRange(char[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        char[] copy = new char[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>0f</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static float[] copyOfRange(float[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        float[] copy = new float[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>0d</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static double[] copyOfRange(double[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        double[] copy = new double[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>false</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with false elements to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static boolean[] copyOfRange(boolean[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        boolean[] copy = new boolean[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    // Misc
+
+    /**
+     * Returns a fixed-size list backed by the specified array.  (Changes to
+     * the returned list "write through" to the array.)  This method acts
+     * as bridge between array-based and collection-based APIs, in
+     * combination with {@link Collection#toArray}.  The returned list is
+     * serializable and implements {@link RandomAccess}.
+     *
+     * <p>This method also provides a convenient way to create a fixed-size
+     * list initialized to contain several elements:
+     * <pre>
+     *     List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly");
+     * </pre>
+     *
+     * @param <T> the class of the objects in the array
+     * @param a the array by which the list will be backed
+     * @return a list view of the specified array
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    public static <T> List<T> asList(T... a) {
+        return new ArrayList<>(a);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class ArrayList<E> extends AbstractList<E>
+        implements RandomAccess, java.io.Serializable
+    {
+        private static final long serialVersionUID = -2764017481108945198L;
+        private final E[] a;
+
+        ArrayList(E[] array) {
+            a = Objects.requireNonNull(array);
+        }
+
+        @Override
+        public int size() {
+            return a.length;
+        }
+
+        @Override
+        public Object[] toArray() {
+            return a.clone();
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int size = size();
+            if (a.length < size)
+                return Arrays.copyOf(this.a, size,
+                                     (Class<? extends T[]>) a.getClass());
+            System.arraycopy(this.a, 0, a, 0, size);
+            if (a.length > size)
+                a[size] = null;
+            return a;
+        }
+
+        @Override
+        public E get(int index) {
+            return a[index];
+        }
+
+        @Override
+        public E set(int index, E element) {
+            E oldValue = a[index];
+            a[index] = element;
+            return oldValue;
+        }
+
+        @Override
+        public int indexOf(Object o) {
+            E[] a = this.a;
+            if (o == null) {
+                for (int i = 0; i < a.length; i++)
+                    if (a[i] == null)
+                        return i;
+            } else {
+                for (int i = 0; i < a.length; i++)
+                    if (o.equals(a[i]))
+                        return i;
+            }
+            return -1;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return indexOf(o) != -1;
+        }
+
+        @Override
+        public Spliterator<E> spliterator() {
+            return Spliterators.spliterator(a, Spliterator.ORDERED);
+        }
+
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            for (E e : a) {
+                action.accept(e);
+            }
+        }
+
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            Objects.requireNonNull(operator);
+            E[] a = this.a;
+            for (int i = 0; i < a.length; i++) {
+                a[i] = operator.apply(a[i]);
+            }
+        }
+
+        @Override
+        public void sort(Comparator<? super E> c) {
+            Arrays.sort(a, c);
+        }
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>long</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Long}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(long a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (long element : a) {
+            int elementHash = (int)(element ^ (element >>> 32));
+            result = 31 * result + elementHash;
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two non-null <tt>int</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Integer}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(int a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (int element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>short</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Short}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(short a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (short element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>char</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Character}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(char a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (char element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>byte</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Byte}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(byte a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (byte element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>boolean</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Boolean}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(boolean a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (boolean element : a)
+            result = 31 * result + (element ? 1231 : 1237);
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>float</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Float}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(float a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (float element : a)
+            result = 31 * result + Float.floatToIntBits(element);
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>double</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Double}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(double a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (double element : a) {
+            long bits = Double.doubleToLongBits(element);
+            result = 31 * result + (int)(bits ^ (bits >>> 32));
+        }
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.  If
+     * the array contains other arrays as elements, the hash code is based on
+     * their identities rather than their contents.  It is therefore
+     * acceptable to invoke this method on an array that contains itself as an
+     * element,  either directly or indirectly through one or more levels of
+     * arrays.
+     *
+     * <p>For any two arrays <tt>a</tt> and <tt>b</tt> such that
+     * <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is equal to the value that would
+     * be returned by <tt>Arrays.asList(a).hashCode()</tt>, unless <tt>a</tt>
+     * is <tt>null</tt>, in which case <tt>0</tt> is returned.
+     *
+     * @param a the array whose content-based hash code to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @see #deepHashCode(Object[])
+     * @since 1.5
+     */
+    public static int hashCode(Object a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+
+        for (Object element : a)
+            result = 31 * result + (element == null ? 0 : element.hashCode());
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the "deep contents" of the specified
+     * array.  If the array contains other arrays as elements, the
+     * hash code is based on their contents and so on, ad infinitum.
+     * It is therefore unacceptable to invoke this method on an array that
+     * contains itself as an element, either directly or indirectly through
+     * one or more levels of arrays.  The behavior of such an invocation is
+     * undefined.
+     *
+     * <p>For any two arrays <tt>a</tt> and <tt>b</tt> such that
+     * <tt>Arrays.deepEquals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.deepHashCode(a) == Arrays.deepHashCode(b)</tt>.
+     *
+     * <p>The computation of the value returned by this method is similar to
+     * that of the value returned by {@link List#hashCode()} on a list
+     * containing the same elements as <tt>a</tt> in the same order, with one
+     * difference: If an element <tt>e</tt> of <tt>a</tt> is itself an array,
+     * its hash code is computed not by calling <tt>e.hashCode()</tt>, but as
+     * by calling the appropriate overloading of <tt>Arrays.hashCode(e)</tt>
+     * if <tt>e</tt> is an array of a primitive type, or as by calling
+     * <tt>Arrays.deepHashCode(e)</tt> recursively if <tt>e</tt> is an array
+     * of a reference type.  If <tt>a</tt> is <tt>null</tt>, this method
+     * returns 0.
+     *
+     * @param a the array whose deep-content-based hash code to compute
+     * @return a deep-content-based hash code for <tt>a</tt>
+     * @see #hashCode(Object[])
+     * @since 1.5
+     */
+    public static int deepHashCode(Object a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+
+        for (Object element : a) {
+            int elementHash = 0;
+            // BEGIN Android-changed: getComponentType() is faster than instanceof()
+            if (element != null) {
+                Class<?> cl = element.getClass().getComponentType();
+                if (cl == null)
+                    elementHash = element.hashCode();
+                else if (element instanceof Object[])
+                    elementHash = deepHashCode((Object[]) element);
+                else if (cl == byte.class)
+                    elementHash = hashCode((byte[]) element);
+                else if (cl == short.class)
+                    elementHash = hashCode((short[]) element);
+                else if (cl == int.class)
+                    elementHash = hashCode((int[]) element);
+                else if (cl == long.class)
+                    elementHash = hashCode((long[]) element);
+                else if (cl == char.class)
+                    elementHash = hashCode((char[]) element);
+                else if (cl == float.class)
+                    elementHash = hashCode((float[]) element);
+                else if (cl == double.class)
+                    elementHash = hashCode((double[]) element);
+                else if (cl == boolean.class)
+                    elementHash = hashCode((boolean[]) element);
+                else
+                    elementHash = element.hashCode();
+            }
+            // END Android-changed: getComponentType() is faster than instanceof()
+            result = 31 * result + elementHash;
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays are <i>deeply
+     * equal</i> to one another.  Unlike the {@link #equals(Object[],Object[])}
+     * method, this method is appropriate for use with nested arrays of
+     * arbitrary depth.
+     *
+     * <p>Two array references are considered deeply equal if both
+     * are <tt>null</tt>, or if they refer to arrays that contain the same
+     * number of elements and all corresponding pairs of elements in the two
+     * arrays are deeply equal.
+     *
+     * <p>Two possibly <tt>null</tt> elements <tt>e1</tt> and <tt>e2</tt> are
+     * deeply equal if any of the following conditions hold:
+     * <ul>
+     *    <li> <tt>e1</tt> and <tt>e2</tt> are both arrays of object reference
+     *         types, and <tt>Arrays.deepEquals(e1, e2) would return true</tt>
+     *    <li> <tt>e1</tt> and <tt>e2</tt> are arrays of the same primitive
+     *         type, and the appropriate overloading of
+     *         <tt>Arrays.equals(e1, e2)</tt> would return true.
+     *    <li> <tt>e1 == e2</tt>
+     *    <li> <tt>e1.equals(e2)</tt> would return true.
+     * </ul>
+     * Note that this definition permits <tt>null</tt> elements at any depth.
+     *
+     * <p>If either of the specified arrays contain themselves as elements
+     * either directly or indirectly through one or more levels of arrays,
+     * the behavior of this method is undefined.
+     *
+     * @param a1 one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     * @see #equals(Object[],Object[])
+     * @see Objects#deepEquals(Object, Object)
+     * @since 1.5
+     */
+    public static boolean deepEquals(Object[] a1, Object[] a2) {
+        if (a1 == a2)
+            return true;
+        if (a1 == null || a2==null)
+            return false;
+        int length = a1.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i = 0; i < length; i++) {
+            Object e1 = a1[i];
+            Object e2 = a2[i];
+
+            if (e1 == e2)
+                continue;
+            if (e1 == null)
+                return false;
+
+            // Figure out whether the two elements are equal
+            boolean eq = deepEquals0(e1, e2);
+
+            if (!eq)
+                return false;
+        }
+        return true;
+    }
+
+    static boolean deepEquals0(Object e1, Object e2) {
+        assert e1 != null;
+        boolean eq;
+        if (e1 instanceof Object[] && e2 instanceof Object[])
+            eq = deepEquals ((Object[]) e1, (Object[]) e2);
+        else if (e1 instanceof byte[] && e2 instanceof byte[])
+            eq = equals((byte[]) e1, (byte[]) e2);
+        else if (e1 instanceof short[] && e2 instanceof short[])
+            eq = equals((short[]) e1, (short[]) e2);
+        else if (e1 instanceof int[] && e2 instanceof int[])
+            eq = equals((int[]) e1, (int[]) e2);
+        else if (e1 instanceof long[] && e2 instanceof long[])
+            eq = equals((long[]) e1, (long[]) e2);
+        else if (e1 instanceof char[] && e2 instanceof char[])
+            eq = equals((char[]) e1, (char[]) e2);
+        else if (e1 instanceof float[] && e2 instanceof float[])
+            eq = equals((float[]) e1, (float[]) e2);
+        else if (e1 instanceof double[] && e2 instanceof double[])
+            eq = equals((double[]) e1, (double[]) e2);
+        else if (e1 instanceof boolean[] && e2 instanceof boolean[])
+            eq = equals((boolean[]) e1, (boolean[]) e2);
+        else
+            eq = e1.equals(e2);
+        return eq;
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(long)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(long[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(int)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt> is
+     * <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(int[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(short)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(short[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(char)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(char[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements
+     * are separated by the characters <tt>", "</tt> (a comma followed
+     * by a space).  Elements are converted to strings as by
+     * <tt>String.valueOf(byte)</tt>.  Returns <tt>"null"</tt> if
+     * <tt>a</tt> is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(byte[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(boolean)</tt>.  Returns <tt>"null"</tt> if
+     * <tt>a</tt> is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(boolean[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(float)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(float[] a) {
+        if (a == null)
+            return "null";
+
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(double)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(double[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * If the array contains other arrays as elements, they are converted to
+     * strings by the {@link Object#toString} method inherited from
+     * <tt>Object</tt>, which describes their <i>identities</i> rather than
+     * their contents.
+     *
+     * <p>The value returned by this method is equal to the value that would
+     * be returned by <tt>Arrays.asList(a).toString()</tt>, unless <tt>a</tt>
+     * is <tt>null</tt>, in which case <tt>"null"</tt> is returned.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @see #deepToString(Object[])
+     * @since 1.5
+     */
+    public static String toString(Object[] a) {
+        if (a == null)
+            return "null";
+
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(String.valueOf(a[i]));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the "deep contents" of the specified
+     * array.  If the array contains other arrays as elements, the string
+     * representation contains their contents and so on.  This method is
+     * designed for converting multidimensional arrays to strings.
+     *
+     * <p>The string representation consists of a list of the array's
+     * elements, enclosed in square brackets (<tt>"[]"</tt>).  Adjacent
+     * elements are separated by the characters <tt>", "</tt> (a comma
+     * followed by a space).  Elements are converted to strings as by
+     * <tt>String.valueOf(Object)</tt>, unless they are themselves
+     * arrays.
+     *
+     * <p>If an element <tt>e</tt> is an array of a primitive type, it is
+     * converted to a string as by invoking the appropriate overloading of
+     * <tt>Arrays.toString(e)</tt>.  If an element <tt>e</tt> is an array of a
+     * reference type, it is converted to a string as by invoking
+     * this method recursively.
+     *
+     * <p>To avoid infinite recursion, if the specified array contains itself
+     * as an element, or contains an indirect reference to itself through one
+     * or more levels of arrays, the self-reference is converted to the string
+     * <tt>"[...]"</tt>.  For example, an array containing only a reference
+     * to itself would be rendered as <tt>"[[...]]"</tt>.
+     *
+     * <p>This method returns <tt>"null"</tt> if the specified array
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @see #toString(Object[])
+     * @since 1.5
+     */
+    public static String deepToString(Object[] a) {
+        if (a == null)
+            return "null";
+
+        int bufLen = 20 * a.length;
+        if (a.length != 0 && bufLen <= 0)
+            bufLen = Integer.MAX_VALUE;
+        StringBuilder buf = new StringBuilder(bufLen);
+        deepToString(a, buf, new HashSet<Object[]>());
+        return buf.toString();
+    }
+
+    private static void deepToString(Object[] a, StringBuilder buf,
+                                     Set<Object[]> dejaVu) {
+        if (a == null) {
+            buf.append("null");
+            return;
+        }
+        int iMax = a.length - 1;
+        if (iMax == -1) {
+            buf.append("[]");
+            return;
+        }
+
+        dejaVu.add(a);
+        buf.append('[');
+        for (int i = 0; ; i++) {
+
+            Object element = a[i];
+            if (element == null) {
+                buf.append("null");
+            } else {
+                Class<?> eClass = element.getClass();
+
+                if (eClass.isArray()) {
+                    if (eClass == byte[].class)
+                        buf.append(toString((byte[]) element));
+                    else if (eClass == short[].class)
+                        buf.append(toString((short[]) element));
+                    else if (eClass == int[].class)
+                        buf.append(toString((int[]) element));
+                    else if (eClass == long[].class)
+                        buf.append(toString((long[]) element));
+                    else if (eClass == char[].class)
+                        buf.append(toString((char[]) element));
+                    else if (eClass == float[].class)
+                        buf.append(toString((float[]) element));
+                    else if (eClass == double[].class)
+                        buf.append(toString((double[]) element));
+                    else if (eClass == boolean[].class)
+                        buf.append(toString((boolean[]) element));
+                    else { // element is an array of object references
+                        if (dejaVu.contains(element))
+                            buf.append("[...]");
+                        else
+                            deepToString((Object[])element, buf, dejaVu);
+                    }
+                } else {  // element is non-null and not an array
+                    buf.append(element.toString());
+                }
+            }
+            if (i == iMax)
+                break;
+            buf.append(", ");
+        }
+        buf.append(']');
+        dejaVu.remove(a);
+    }
+
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param <T> type of elements of the array
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static <T> void setAll(T[] array, IntFunction<? extends T> generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.apply(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param <T> type of elements of the array
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static <T> void parallelSetAll(T[] array, IntFunction<? extends T> generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.apply(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(int[] array, IntUnaryOperator generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsInt(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     * value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(int[] array, IntUnaryOperator generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsInt(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(long[] array, IntToLongFunction generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsLong(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(long[] array, IntToLongFunction generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsLong(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(double[] array, IntToDoubleFunction generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsDouble(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(double[] array, IntToDoubleFunction generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsDouble(i); });
+    }
+
+    /**
+     * Returns a {@link Spliterator} covering all of the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param <T> type of elements
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
+     * @since 1.8
+     */
+    public static <T> Spliterator<T> spliterator(T[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator} covering the specified range of the
+     * specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param <T> type of elements
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static <T> Spliterator<T> spliterator(T[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfInt} covering all of the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
+     * @since 1.8
+     */
+    public static Spliterator.OfInt spliterator(int[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfInt} covering the specified range of the
+     * specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static Spliterator.OfInt spliterator(int[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfLong} covering all of the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return the spliterator for the array elements
+     * @since 1.8
+     */
+    public static Spliterator.OfLong spliterator(long[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfLong} covering the specified range of the
+     * specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static Spliterator.OfLong spliterator(long[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfDouble} covering all of the specified
+     * array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
+     * @since 1.8
+     */
+    public static Spliterator.OfDouble spliterator(double[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfDouble} covering the specified range of
+     * the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static Spliterator.OfDouble spliterator(double[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param <T> The type of the array elements
+     * @param array The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     * @since 1.8
+     */
+    public static <T> Stream<T> stream(T[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param <T> the type of the array elements
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code Stream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.stream(spliterator(array, startInclusive, endExclusive), false);
+    }
+
+    /**
+     * Returns a sequential {@link IntStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return an {@code IntStream} for the array
+     * @since 1.8
+     */
+    public static IntStream stream(int[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link IntStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return an {@code IntStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static IntStream stream(int[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.intStream(spliterator(array, startInclusive, endExclusive), false);
+    }
+
+    /**
+     * Returns a sequential {@link LongStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a {@code LongStream} for the array
+     * @since 1.8
+     */
+    public static LongStream stream(long[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link LongStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code LongStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static LongStream stream(long[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.longStream(spliterator(array, startInclusive, endExclusive), false);
+    }
+
+    /**
+     * Returns a sequential {@link DoubleStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a {@code DoubleStream} for the array
+     * @since 1.8
+     */
+    public static DoubleStream stream(double[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link DoubleStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code DoubleStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive), false);
+    }
+}
diff --git a/java/util/ArraysParallelSortHelpers.java b/java/util/ArraysParallelSortHelpers.java
new file mode 100644
index 0000000..8fa2262
--- /dev/null
+++ b/java/util/ArraysParallelSortHelpers.java
@@ -0,0 +1,1010 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.concurrent.RecursiveAction;
+import java.util.concurrent.CountedCompleter;
+
+/**
+ * Helper utilities for the parallel sort methods in Arrays.parallelSort.
+ *
+ * For each primitive type, plus Object, we define a static class to
+ * contain the Sorter and Merger implementations for that type:
+ *
+ * Sorter classes based mainly on CilkSort
+ * <A href="http://supertech.lcs.mit.edu/cilk/"> Cilk</A>:
+ * Basic algorithm:
+ * if array size is small, just use a sequential quicksort (via Arrays.sort)
+ *         Otherwise:
+ *         1. Break array in half.
+ *         2. For each half,
+ *             a. break the half in half (i.e., quarters),
+ *             b. sort the quarters
+ *             c. merge them together
+ *         3. merge together the two halves.
+ *
+ * One reason for splitting in quarters is that this guarantees that
+ * the final sort is in the main array, not the workspace array.
+ * (workspace and main swap roles on each subsort step.)  Leaf-level
+ * sorts use the associated sequential sort.
+ *
+ * Merger classes perform merging for Sorter.  They are structured
+ * such that if the underlying sort is stable (as is true for
+ * TimSort), then so is the full sort.  If big enough, they split the
+ * largest of the two partitions in half, find the greatest point in
+ * smaller partition less than the beginning of the second half of
+ * larger via binary search; and then merge in parallel the two
+ * partitions.  In part to ensure tasks are triggered in
+ * stability-preserving order, the current CountedCompleter design
+ * requires some little tasks to serve as place holders for triggering
+ * completion tasks.  These classes (EmptyCompleter and Relay) don't
+ * need to keep track of the arrays, and are never themselves forked,
+ * so don't hold any task state.
+ *
+ * The primitive class versions (FJByte... FJDouble) are
+ * identical to each other except for type declarations.
+ *
+ * The base sequential sorts rely on non-public versions of TimSort,
+ * ComparableTimSort, and DualPivotQuicksort sort methods that accept
+ * temp workspace array slices that we will have already allocated, so
+ * avoids redundant allocation. (Except for DualPivotQuicksort byte[]
+ * sort, that does not ever use a workspace array.)
+ */
+/*package*/ class ArraysParallelSortHelpers {
+
+    /*
+     * Style note: The task classes have a lot of parameters, that are
+     * stored as task fields and copied to local variables and used in
+     * compute() methods, We pack these into as few lines as possible,
+     * and hoist consistency checks among them before main loops, to
+     * reduce distraction.
+     */
+
+    /**
+     * A placeholder task for Sorters, used for the lowest
+     * quartile task, that does not need to maintain array state.
+     */
+    static final class EmptyCompleter extends CountedCompleter<Void> {
+        static final long serialVersionUID = 2446542900576103244L;
+        EmptyCompleter(CountedCompleter<?> p) { super(p); }
+        public final void compute() { }
+    }
+
+    /**
+     * A trigger for secondary merge of two merges
+     */
+    static final class Relay extends CountedCompleter<Void> {
+        static final long serialVersionUID = 2446542900576103244L;
+        final CountedCompleter<?> task;
+        Relay(CountedCompleter<?> task) {
+            super(null, 1);
+            this.task = task;
+        }
+        public final void compute() { }
+        public final void onCompletion(CountedCompleter<?> t) {
+            task.compute();
+        }
+    }
+
+    /** Object + Comparator support class */
+    static final class FJObject {
+        static final class Sorter<T> extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final T[] a, w;
+            final int base, size, wbase, gran;
+            Comparator<? super T> comparator;
+            Sorter(CountedCompleter<?> par, T[] a, T[] w, int base, int size,
+                   int wbase, int gran,
+                   Comparator<? super T> comparator) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+                this.comparator = comparator;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                Comparator<? super T> c = this.comparator;
+                T[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger<T>(s, w, a, wb, h,
+                                                       wb+h, n-h, b, g, c));
+                    Relay rc = new Relay(new Merger<T>(fc, a, w, b+h, q,
+                                                       b+u, n-u, wb+h, g, c));
+                    new Sorter<T>(rc, a, w, b+u, n-u, wb+u, g, c).fork();
+                    new Sorter<T>(rc, a, w, b+h, q, wb+h, g, c).fork();;
+                    Relay bc = new Relay(new Merger<T>(fc, a, w, b, q,
+                                                       b+q, h-q, wb, g, c));
+                    new Sorter<T>(bc, a, w, b+q, h-q, wb+q, g, c).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                TimSort.sort(a, b, b + n, c, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger<T> extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final T[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Comparator<? super T> comparator;
+            Merger(CountedCompleter<?> par, T[] a, T[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran,
+                   Comparator<? super T> comparator) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+                this.comparator = comparator;
+            }
+
+            public final void compute() {
+                Comparator<? super T> c = this.comparator;
+                T[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0 ||
+                    c == null)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        T split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (c.compare(split, a[rm + rb]) <= 0)
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        T split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (c.compare(split, a[lm + lb]) <= 0)
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger<T> m = new Merger<T>(this, a, w, lb + lh, ln - lh,
+                                                rb + rh, rn - rh,
+                                                k + lh + rh, g, c);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    T t, al, ar;
+                    if (c.compare((al = a[lb]), (ar = a[rb])) <= 0) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+
+                tryComplete();
+            }
+
+        }
+    } // FJObject
+
+    /** byte support class */
+    static final class FJByte {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final byte[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, byte[] a, byte[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                byte[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final byte[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, byte[] a, byte[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                byte[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        byte split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        byte split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    byte t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJByte
+
+    /** char support class */
+    static final class FJChar {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final char[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, char[] a, char[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                char[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final char[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, char[] a, char[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                char[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        char split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        char split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    char t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJChar
+
+    /** short support class */
+    static final class FJShort {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final short[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, short[] a, short[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                short[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final short[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, short[] a, short[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                short[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        short split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        short split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    short t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJShort
+
+    /** int support class */
+    static final class FJInt {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final int[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, int[] a, int[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                int[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final int[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, int[] a, int[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                int[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        int split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        int split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    int t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJInt
+
+    /** long support class */
+    static final class FJLong {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final long[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, long[] a, long[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                long[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final long[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, long[] a, long[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                long[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        long split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        long split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    long t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJLong
+
+    /** float support class */
+    static final class FJFloat {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final float[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, float[] a, float[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                float[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final float[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, float[] a, float[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                float[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        float split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        float split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    float t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJFloat
+
+    /** double support class */
+    static final class FJDouble {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final double[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, double[] a, double[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                double[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final double[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, double[] a, double[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                double[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        double split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        double split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    double t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJDouble
+
+}
diff --git a/java/util/Base64.java b/java/util/Base64.java
new file mode 100644
index 0000000..be98fad
--- /dev/null
+++ b/java/util/Base64.java
@@ -0,0 +1,1001 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.FilterOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * This class consists exclusively of static methods for obtaining
+ * encoders and decoders for the Base64 encoding scheme. The
+ * implementation of this class supports the following types of Base64
+ * as specified in
+ * <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a> and
+ * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
+ *
+ * <ul>
+ * <li><a name="basic"><b>Basic</b></a>
+ * <p> Uses "The Base64 Alphabet" as specified in Table 1 of
+ *     RFC 4648 and RFC 2045 for encoding and decoding operation.
+ *     The encoder does not add any line feed (line separator)
+ *     character. The decoder rejects data that contains characters
+ *     outside the base64 alphabet.</p></li>
+ *
+ * <li><a name="url"><b>URL and Filename safe</b></a>
+ * <p> Uses the "URL and Filename safe Base64 Alphabet" as specified
+ *     in Table 2 of RFC 4648 for encoding and decoding. The
+ *     encoder does not add any line feed (line separator) character.
+ *     The decoder rejects data that contains characters outside the
+ *     base64 alphabet.</p></li>
+ *
+ * <li><a name="mime"><b>MIME</b></a>
+ * <p> Uses the "The Base64 Alphabet" as specified in Table 1 of
+ *     RFC 2045 for encoding and decoding operation. The encoded output
+ *     must be represented in lines of no more than 76 characters each
+ *     and uses a carriage return {@code '\r'} followed immediately by
+ *     a linefeed {@code '\n'} as the line separator. No line separator
+ *     is added to the end of the encoded output. All line separators
+ *     or other characters not found in the base64 alphabet table are
+ *     ignored in decoding operation.</p></li>
+ * </ul>
+ *
+ * <p> Unless otherwise noted, passing a {@code null} argument to a
+ * method of this class will cause a {@link java.lang.NullPointerException
+ * NullPointerException} to be thrown.
+ *
+ * @author  Xueming Shen
+ * @since   1.8
+ */
+
+public class Base64 {
+
+    private Base64() {}
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#basic">Basic</a> type base64 encoding scheme.
+     *
+     * @return  A Base64 encoder.
+     */
+    public static Encoder getEncoder() {
+         return Encoder.RFC4648;
+    }
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#url">URL and Filename safe</a> type base64
+     * encoding scheme.
+     *
+     * @return  A Base64 encoder.
+     */
+    public static Encoder getUrlEncoder() {
+         return Encoder.RFC4648_URLSAFE;
+    }
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#mime">MIME</a> type base64 encoding scheme.
+     *
+     * @return  A Base64 encoder.
+     */
+    public static Encoder getMimeEncoder() {
+        return Encoder.RFC2045;
+    }
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#mime">MIME</a> type base64 encoding scheme
+     * with specified line length and line separators.
+     *
+     * @param   lineLength
+     *          the length of each output line (rounded down to nearest multiple
+     *          of 4). If {@code lineLength <= 0} the output will not be separated
+     *          in lines
+     * @param   lineSeparator
+     *          the line separator for each output line
+     *
+     * @return  A Base64 encoder.
+     *
+     * @throws  IllegalArgumentException if {@code lineSeparator} includes any
+     *          character of "The Base64 Alphabet" as specified in Table 1 of
+     *          RFC 2045.
+     */
+    public static Encoder getMimeEncoder(int lineLength, byte[] lineSeparator) {
+         Objects.requireNonNull(lineSeparator);
+         int[] base64 = Decoder.fromBase64;
+         for (byte b : lineSeparator) {
+             if (base64[b & 0xff] != -1)
+                 throw new IllegalArgumentException(
+                     "Illegal base64 line separator character 0x" + Integer.toString(b, 16));
+         }
+         if (lineLength <= 0) {
+             return Encoder.RFC4648;
+         }
+         return new Encoder(false, lineSeparator, lineLength >> 2 << 2, true);
+    }
+
+    /**
+     * Returns a {@link Decoder} that decodes using the
+     * <a href="#basic">Basic</a> type base64 encoding scheme.
+     *
+     * @return  A Base64 decoder.
+     */
+    public static Decoder getDecoder() {
+         return Decoder.RFC4648;
+    }
+
+    /**
+     * Returns a {@link Decoder} that decodes using the
+     * <a href="#url">URL and Filename safe</a> type base64
+     * encoding scheme.
+     *
+     * @return  A Base64 decoder.
+     */
+    public static Decoder getUrlDecoder() {
+         return Decoder.RFC4648_URLSAFE;
+    }
+
+    /**
+     * Returns a {@link Decoder} that decodes using the
+     * <a href="#mime">MIME</a> type base64 decoding scheme.
+     *
+     * @return  A Base64 decoder.
+     */
+    public static Decoder getMimeDecoder() {
+         return Decoder.RFC2045;
+    }
+
+    /**
+     * This class implements an encoder for encoding byte data using
+     * the Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
+     *
+     * <p> Instances of {@link Encoder} class are safe for use by
+     * multiple concurrent threads.
+     *
+     * <p> Unless otherwise noted, passing a {@code null} argument to
+     * a method of this class will cause a
+     * {@link java.lang.NullPointerException NullPointerException} to
+     * be thrown.
+     *
+     * @see     Decoder
+     * @since   1.8
+     */
+    public static class Encoder {
+
+        private final byte[] newline;
+        private final int linemax;
+        private final boolean isURL;
+        private final boolean doPadding;
+
+        private Encoder(boolean isURL, byte[] newline, int linemax, boolean doPadding) {
+            this.isURL = isURL;
+            this.newline = newline;
+            this.linemax = linemax;
+            this.doPadding = doPadding;
+        }
+
+        /**
+         * This array is a lookup table that translates 6-bit positive integer
+         * index values into their "Base64 Alphabet" equivalents as specified
+         * in "Table 1: The Base64 Alphabet" of RFC 2045 (and RFC 4648).
+         */
+        private static final char[] toBase64 = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+        };
+
+        /**
+         * It's the lookup table for "URL and Filename safe Base64" as specified
+         * in Table 2 of the RFC 4648, with the '+' and '/' changed to '-' and
+         * '_'. This table is used when BASE64_URL is specified.
+         */
+        private static final char[] toBase64URL = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
+        };
+
+        private static final int MIMELINEMAX = 76;
+        private static final byte[] CRLF = new byte[] {'\r', '\n'};
+
+        static final Encoder RFC4648 = new Encoder(false, null, -1, true);
+        static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
+        static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
+
+        private final int outLength(int srclen) {
+            int len = 0;
+            if (doPadding) {
+                len = 4 * ((srclen + 2) / 3);
+            } else {
+                int n = srclen % 3;
+                len = 4 * (srclen / 3) + (n == 0 ? 0 : n + 1);
+            }
+            if (linemax > 0)                                  // line separators
+                len += (len - 1) / linemax * newline.length;
+            return len;
+        }
+
+        /**
+         * Encodes all bytes from the specified byte array into a newly-allocated
+         * byte array using the {@link Base64} encoding scheme. The returned byte
+         * array is of the length of the resulting bytes.
+         *
+         * @param   src
+         *          the byte array to encode
+         * @return  A newly-allocated byte array containing the resulting
+         *          encoded bytes.
+         */
+        public byte[] encode(byte[] src) {
+            int len = outLength(src.length);          // dst array size
+            byte[] dst = new byte[len];
+            int ret = encode0(src, 0, src.length, dst);
+            if (ret != dst.length)
+                 return Arrays.copyOf(dst, ret);
+            return dst;
+        }
+
+        /**
+         * Encodes all bytes from the specified byte array using the
+         * {@link Base64} encoding scheme, writing the resulting bytes to the
+         * given output byte array, starting at offset 0.
+         *
+         * <p> It is the responsibility of the invoker of this method to make
+         * sure the output byte array {@code dst} has enough space for encoding
+         * all bytes from the input byte array. No bytes will be written to the
+         * output byte array if the output byte array is not big enough.
+         *
+         * @param   src
+         *          the byte array to encode
+         * @param   dst
+         *          the output byte array
+         * @return  The number of bytes written to the output byte array
+         *
+         * @throws  IllegalArgumentException if {@code dst} does not have enough
+         *          space for encoding all input bytes.
+         */
+        public int encode(byte[] src, byte[] dst) {
+            int len = outLength(src.length);         // dst array size
+            if (dst.length < len)
+                throw new IllegalArgumentException(
+                    "Output byte array is too small for encoding all input bytes");
+            return encode0(src, 0, src.length, dst);
+        }
+
+        /**
+         * Encodes the specified byte array into a String using the {@link Base64}
+         * encoding scheme.
+         *
+         * <p> This method first encodes all input bytes into a base64 encoded
+         * byte array and then constructs a new String by using the encoded byte
+         * array and the {@link java.nio.charset.StandardCharsets#ISO_8859_1
+         * ISO-8859-1} charset.
+         *
+         * <p> In other words, an invocation of this method has exactly the same
+         * effect as invoking
+         * {@code new String(encode(src), StandardCharsets.ISO_8859_1)}.
+         *
+         * @param   src
+         *          the byte array to encode
+         * @return  A String containing the resulting Base64 encoded characters
+         */
+        @SuppressWarnings("deprecation")
+        public String encodeToString(byte[] src) {
+            byte[] encoded = encode(src);
+            return new String(encoded, 0, 0, encoded.length);
+        }
+
+        /**
+         * Encodes all remaining bytes from the specified byte buffer into
+         * a newly-allocated ByteBuffer using the {@link Base64} encoding
+         * scheme.
+         *
+         * Upon return, the source buffer's position will be updated to
+         * its limit; its limit will not have been changed. The returned
+         * output buffer's position will be zero and its limit will be the
+         * number of resulting encoded bytes.
+         *
+         * @param   buffer
+         *          the source ByteBuffer to encode
+         * @return  A newly-allocated byte buffer containing the encoded bytes.
+         */
+        public ByteBuffer encode(ByteBuffer buffer) {
+            int len = outLength(buffer.remaining());
+            byte[] dst = new byte[len];
+            int ret = 0;
+            if (buffer.hasArray()) {
+                ret = encode0(buffer.array(),
+                              buffer.arrayOffset() + buffer.position(),
+                              buffer.arrayOffset() + buffer.limit(),
+                              dst);
+                buffer.position(buffer.limit());
+            } else {
+                byte[] src = new byte[buffer.remaining()];
+                buffer.get(src);
+                ret = encode0(src, 0, src.length, dst);
+            }
+            if (ret != dst.length)
+                 dst = Arrays.copyOf(dst, ret);
+            return ByteBuffer.wrap(dst);
+        }
+
+        /**
+         * Wraps an output stream for encoding byte data using the {@link Base64}
+         * encoding scheme.
+         *
+         * <p> It is recommended to promptly close the returned output stream after
+         * use, during which it will flush all possible leftover bytes to the underlying
+         * output stream. Closing the returned output stream will close the underlying
+         * output stream.
+         *
+         * @param   os
+         *          the output stream.
+         * @return  the output stream for encoding the byte data into the
+         *          specified Base64 encoded format
+         */
+        public OutputStream wrap(OutputStream os) {
+            Objects.requireNonNull(os);
+            return new EncOutputStream(os, isURL ? toBase64URL : toBase64,
+                                       newline, linemax, doPadding);
+        }
+
+        /**
+         * Returns an encoder instance that encodes equivalently to this one,
+         * but without adding any padding character at the end of the encoded
+         * byte data.
+         *
+         * <p> The encoding scheme of this encoder instance is unaffected by
+         * this invocation. The returned encoder instance should be used for
+         * non-padding encoding operation.
+         *
+         * @return an equivalent encoder that encodes without adding any
+         *         padding character at the end
+         */
+        public Encoder withoutPadding() {
+            if (!doPadding)
+                return this;
+            return new Encoder(isURL, newline, linemax, false);
+        }
+
+        private int encode0(byte[] src, int off, int end, byte[] dst) {
+            char[] base64 = isURL ? toBase64URL : toBase64;
+            int sp = off;
+            int slen = (end - off) / 3 * 3;
+            int sl = off + slen;
+            if (linemax > 0 && slen  > linemax / 4 * 3)
+                slen = linemax / 4 * 3;
+            int dp = 0;
+            while (sp < sl) {
+                int sl0 = Math.min(sp + slen, sl);
+                for (int sp0 = sp, dp0 = dp ; sp0 < sl0; ) {
+                    int bits = (src[sp0++] & 0xff) << 16 |
+                               (src[sp0++] & 0xff) <<  8 |
+                               (src[sp0++] & 0xff);
+                    dst[dp0++] = (byte)base64[(bits >>> 18) & 0x3f];
+                    dst[dp0++] = (byte)base64[(bits >>> 12) & 0x3f];
+                    dst[dp0++] = (byte)base64[(bits >>> 6)  & 0x3f];
+                    dst[dp0++] = (byte)base64[bits & 0x3f];
+                }
+                int dlen = (sl0 - sp) / 3 * 4;
+                dp += dlen;
+                sp = sl0;
+                if (dlen == linemax && sp < end) {
+                    for (byte b : newline){
+                        dst[dp++] = b;
+                    }
+                }
+            }
+            if (sp < end) {               // 1 or 2 leftover bytes
+                int b0 = src[sp++] & 0xff;
+                dst[dp++] = (byte)base64[b0 >> 2];
+                if (sp == end) {
+                    dst[dp++] = (byte)base64[(b0 << 4) & 0x3f];
+                    if (doPadding) {
+                        dst[dp++] = '=';
+                        dst[dp++] = '=';
+                    }
+                } else {
+                    int b1 = src[sp++] & 0xff;
+                    dst[dp++] = (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)];
+                    dst[dp++] = (byte)base64[(b1 << 2) & 0x3f];
+                    if (doPadding) {
+                        dst[dp++] = '=';
+                    }
+                }
+            }
+            return dp;
+        }
+    }
+
+    /**
+     * This class implements a decoder for decoding byte data using the
+     * Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
+     *
+     * <p> The Base64 padding character {@code '='} is accepted and
+     * interpreted as the end of the encoded byte data, but is not
+     * required. So if the final unit of the encoded byte data only has
+     * two or three Base64 characters (without the corresponding padding
+     * character(s) padded), they are decoded as if followed by padding
+     * character(s). If there is a padding character present in the
+     * final unit, the correct number of padding character(s) must be
+     * present, otherwise {@code IllegalArgumentException} (
+     * {@code IOException} when reading from a Base64 stream) is thrown
+     * during decoding.
+     *
+     * <p> Instances of {@link Decoder} class are safe for use by
+     * multiple concurrent threads.
+     *
+     * <p> Unless otherwise noted, passing a {@code null} argument to
+     * a method of this class will cause a
+     * {@link java.lang.NullPointerException NullPointerException} to
+     * be thrown.
+     *
+     * @see     Encoder
+     * @since   1.8
+     */
+    public static class Decoder {
+
+        private final boolean isURL;
+        private final boolean isMIME;
+
+        private Decoder(boolean isURL, boolean isMIME) {
+            this.isURL = isURL;
+            this.isMIME = isMIME;
+        }
+
+        /**
+         * Lookup table for decoding unicode characters drawn from the
+         * "Base64 Alphabet" (as specified in Table 1 of RFC 2045) into
+         * their 6-bit positive integer equivalents.  Characters that
+         * are not in the Base64 alphabet but fall within the bounds of
+         * the array are encoded to -1.
+         *
+         */
+        private static final int[] fromBase64 = new int[256];
+        static {
+            Arrays.fill(fromBase64, -1);
+            for (int i = 0; i < Encoder.toBase64.length; i++)
+                fromBase64[Encoder.toBase64[i]] = i;
+            fromBase64['='] = -2;
+        }
+
+        /**
+         * Lookup table for decoding "URL and Filename safe Base64 Alphabet"
+         * as specified in Table2 of the RFC 4648.
+         */
+        private static final int[] fromBase64URL = new int[256];
+
+        static {
+            Arrays.fill(fromBase64URL, -1);
+            for (int i = 0; i < Encoder.toBase64URL.length; i++)
+                fromBase64URL[Encoder.toBase64URL[i]] = i;
+            fromBase64URL['='] = -2;
+        }
+
+        static final Decoder RFC4648         = new Decoder(false, false);
+        static final Decoder RFC4648_URLSAFE = new Decoder(true, false);
+        static final Decoder RFC2045         = new Decoder(false, true);
+
+        /**
+         * Decodes all bytes from the input byte array using the {@link Base64}
+         * encoding scheme, writing the results into a newly-allocated output
+         * byte array. The returned byte array is of the length of the resulting
+         * bytes.
+         *
+         * @param   src
+         *          the byte array to decode
+         *
+         * @return  A newly-allocated byte array containing the decoded bytes.
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code src} is not in valid Base64 scheme
+         */
+        public byte[] decode(byte[] src) {
+            byte[] dst = new byte[outLength(src, 0, src.length)];
+            int ret = decode0(src, 0, src.length, dst);
+            if (ret != dst.length) {
+                dst = Arrays.copyOf(dst, ret);
+            }
+            return dst;
+        }
+
+        /**
+         * Decodes a Base64 encoded String into a newly-allocated byte array
+         * using the {@link Base64} encoding scheme.
+         *
+         * <p> An invocation of this method has exactly the same effect as invoking
+         * {@code decode(src.getBytes(StandardCharsets.ISO_8859_1))}
+         *
+         * @param   src
+         *          the string to decode
+         *
+         * @return  A newly-allocated byte array containing the decoded bytes.
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code src} is not in valid Base64 scheme
+         */
+        public byte[] decode(String src) {
+            return decode(src.getBytes(StandardCharsets.ISO_8859_1));
+        }
+
+        /**
+         * Decodes all bytes from the input byte array using the {@link Base64}
+         * encoding scheme, writing the results into the given output byte array,
+         * starting at offset 0.
+         *
+         * <p> It is the responsibility of the invoker of this method to make
+         * sure the output byte array {@code dst} has enough space for decoding
+         * all bytes from the input byte array. No bytes will be be written to
+         * the output byte array if the output byte array is not big enough.
+         *
+         * <p> If the input byte array is not in valid Base64 encoding scheme
+         * then some bytes may have been written to the output byte array before
+         * IllegalargumentException is thrown.
+         *
+         * @param   src
+         *          the byte array to decode
+         * @param   dst
+         *          the output byte array
+         *
+         * @return  The number of bytes written to the output byte array
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code src} is not in valid Base64 scheme, or {@code dst}
+         *          does not have enough space for decoding all input bytes.
+         */
+        public int decode(byte[] src, byte[] dst) {
+            int len = outLength(src, 0, src.length);
+            if (dst.length < len)
+                throw new IllegalArgumentException(
+                    "Output byte array is too small for decoding all input bytes");
+            return decode0(src, 0, src.length, dst);
+        }
+
+        /**
+         * Decodes all bytes from the input byte buffer using the {@link Base64}
+         * encoding scheme, writing the results into a newly-allocated ByteBuffer.
+         *
+         * <p> Upon return, the source buffer's position will be updated to
+         * its limit; its limit will not have been changed. The returned
+         * output buffer's position will be zero and its limit will be the
+         * number of resulting decoded bytes
+         *
+         * <p> {@code IllegalArgumentException} is thrown if the input buffer
+         * is not in valid Base64 encoding scheme. The position of the input
+         * buffer will not be advanced in this case.
+         *
+         * @param   buffer
+         *          the ByteBuffer to decode
+         *
+         * @return  A newly-allocated byte buffer containing the decoded bytes
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code src} is not in valid Base64 scheme.
+         */
+        public ByteBuffer decode(ByteBuffer buffer) {
+            int pos0 = buffer.position();
+            try {
+                byte[] src;
+                int sp, sl;
+                if (buffer.hasArray()) {
+                    src = buffer.array();
+                    sp = buffer.arrayOffset() + buffer.position();
+                    sl = buffer.arrayOffset() + buffer.limit();
+                    buffer.position(buffer.limit());
+                } else {
+                    src = new byte[buffer.remaining()];
+                    buffer.get(src);
+                    sp = 0;
+                    sl = src.length;
+                }
+                byte[] dst = new byte[outLength(src, sp, sl)];
+                return ByteBuffer.wrap(dst, 0, decode0(src, sp, sl, dst));
+            } catch (IllegalArgumentException iae) {
+                buffer.position(pos0);
+                throw iae;
+            }
+        }
+
+        /**
+         * Returns an input stream for decoding {@link Base64} encoded byte stream.
+         *
+         * <p> The {@code read}  methods of the returned {@code InputStream} will
+         * throw {@code IOException} when reading bytes that cannot be decoded.
+         *
+         * <p> Closing the returned input stream will close the underlying
+         * input stream.
+         *
+         * @param   is
+         *          the input stream
+         *
+         * @return  the input stream for decoding the specified Base64 encoded
+         *          byte stream
+         */
+        public InputStream wrap(InputStream is) {
+            Objects.requireNonNull(is);
+            return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME);
+        }
+
+        private int outLength(byte[] src, int sp, int sl) {
+            int[] base64 = isURL ? fromBase64URL : fromBase64;
+            int paddings = 0;
+            int len = sl - sp;
+            if (len == 0)
+                return 0;
+            if (len < 2) {
+                if (isMIME && base64[0] == -1)
+                    return 0;
+                throw new IllegalArgumentException(
+                    "Input byte[] should at least have 2 bytes for base64 bytes");
+            }
+            if (isMIME) {
+                // scan all bytes to fill out all non-alphabet. a performance
+                // trade-off of pre-scan or Arrays.copyOf
+                int n = 0;
+                while (sp < sl) {
+                    int b = src[sp++] & 0xff;
+                    if (b == '=') {
+                        len -= (sl - sp + 1);
+                        break;
+                    }
+                    if ((b = base64[b]) == -1)
+                        n++;
+                }
+                len -= n;
+            } else {
+                if (src[sl - 1] == '=') {
+                    paddings++;
+                    if (src[sl - 2] == '=')
+                        paddings++;
+                }
+            }
+            if (paddings == 0 && (len & 0x3) !=  0)
+                paddings = 4 - (len & 0x3);
+            return 3 * ((len + 3) / 4) - paddings;
+        }
+
+        private int decode0(byte[] src, int sp, int sl, byte[] dst) {
+            int[] base64 = isURL ? fromBase64URL : fromBase64;
+            int dp = 0;
+            int bits = 0;
+            int shiftto = 18;       // pos of first byte of 4-byte atom
+            while (sp < sl) {
+                int b = src[sp++] & 0xff;
+                if ((b = base64[b]) < 0) {
+                    if (b == -2) {         // padding byte '='
+                        // =     shiftto==18 unnecessary padding
+                        // x=    shiftto==12 a dangling single x
+                        // x     to be handled together with non-padding case
+                        // xx=   shiftto==6&&sp==sl missing last =
+                        // xx=y  shiftto==6 last is not =
+                        if (shiftto == 6 && (sp == sl || src[sp++] != '=') ||
+                            shiftto == 18) {
+                            throw new IllegalArgumentException(
+                                "Input byte array has wrong 4-byte ending unit");
+                        }
+                        break;
+                    }
+                    if (isMIME)    // skip if for rfc2045
+                        continue;
+                    else
+                        throw new IllegalArgumentException(
+                            "Illegal base64 character " +
+                            Integer.toString(src[sp - 1], 16));
+                }
+                bits |= (b << shiftto);
+                shiftto -= 6;
+                if (shiftto < 0) {
+                    dst[dp++] = (byte)(bits >> 16);
+                    dst[dp++] = (byte)(bits >>  8);
+                    dst[dp++] = (byte)(bits);
+                    shiftto = 18;
+                    bits = 0;
+                }
+            }
+            // reached end of byte array or hit padding '=' characters.
+            if (shiftto == 6) {
+                dst[dp++] = (byte)(bits >> 16);
+            } else if (shiftto == 0) {
+                dst[dp++] = (byte)(bits >> 16);
+                dst[dp++] = (byte)(bits >>  8);
+            } else if (shiftto == 12) {
+                // dangling single "x", incorrectly encoded.
+                throw new IllegalArgumentException(
+                    "Last unit does not have enough valid bits");
+            }
+            // anything left is invalid, if is not MIME.
+            // if MIME, ignore all non-base64 character
+            while (sp < sl) {
+                if (isMIME && base64[src[sp++]] < 0)
+                    continue;
+                throw new IllegalArgumentException(
+                    "Input byte array has incorrect ending byte at " + sp);
+            }
+            return dp;
+        }
+    }
+
+    /*
+     * An output stream for encoding bytes into the Base64.
+     */
+    private static class EncOutputStream extends FilterOutputStream {
+
+        private int leftover = 0;
+        private int b0, b1, b2;
+        private boolean closed = false;
+
+        private final char[] base64;    // byte->base64 mapping
+        private final byte[] newline;   // line separator, if needed
+        private final int linemax;
+        private final boolean doPadding;// whether or not to pad
+        private int linepos = 0;
+
+        EncOutputStream(OutputStream os, char[] base64,
+                        byte[] newline, int linemax, boolean doPadding) {
+            super(os);
+            this.base64 = base64;
+            this.newline = newline;
+            this.linemax = linemax;
+            this.doPadding = doPadding;
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            byte[] buf = new byte[1];
+            buf[0] = (byte)(b & 0xff);
+            write(buf, 0, 1);
+        }
+
+        private void checkNewline() throws IOException {
+            if (linepos == linemax) {
+                out.write(newline);
+                linepos = 0;
+            }
+        }
+
+        @Override
+        public void write(byte[] b, int off, int len) throws IOException {
+            if (closed)
+                throw new IOException("Stream is closed");
+            // Android-changed: Upstream fix to avoid overflow.
+            // This upstream fix is from beyond OpenJDK8u121-b13. http://b/62368386
+            // if (off < 0 || len < 0 || off + len > b.length)
+            if (off < 0 || len < 0 || len > b.length - off)
+                throw new ArrayIndexOutOfBoundsException();
+            if (len == 0)
+                return;
+            if (leftover != 0) {
+                if (leftover == 1) {
+                    b1 = b[off++] & 0xff;
+                    len--;
+                    if (len == 0) {
+                        leftover++;
+                        return;
+                    }
+                }
+                b2 = b[off++] & 0xff;
+                len--;
+                checkNewline();
+                out.write(base64[b0 >> 2]);
+                out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
+                out.write(base64[(b1 << 2) & 0x3f | (b2 >> 6)]);
+                out.write(base64[b2 & 0x3f]);
+                linepos += 4;
+            }
+            int nBits24 = len / 3;
+            leftover = len - (nBits24 * 3);
+            while (nBits24-- > 0) {
+                checkNewline();
+                int bits = (b[off++] & 0xff) << 16 |
+                           (b[off++] & 0xff) <<  8 |
+                           (b[off++] & 0xff);
+                out.write(base64[(bits >>> 18) & 0x3f]);
+                out.write(base64[(bits >>> 12) & 0x3f]);
+                out.write(base64[(bits >>> 6)  & 0x3f]);
+                out.write(base64[bits & 0x3f]);
+                linepos += 4;
+           }
+            if (leftover == 1) {
+                b0 = b[off++] & 0xff;
+            } else if (leftover == 2) {
+                b0 = b[off++] & 0xff;
+                b1 = b[off++] & 0xff;
+            }
+        }
+
+        @Override
+        public void close() throws IOException {
+            if (!closed) {
+                closed = true;
+                if (leftover == 1) {
+                    checkNewline();
+                    out.write(base64[b0 >> 2]);
+                    out.write(base64[(b0 << 4) & 0x3f]);
+                    if (doPadding) {
+                        out.write('=');
+                        out.write('=');
+                    }
+                } else if (leftover == 2) {
+                    checkNewline();
+                    out.write(base64[b0 >> 2]);
+                    out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
+                    out.write(base64[(b1 << 2) & 0x3f]);
+                    if (doPadding) {
+                       out.write('=');
+                    }
+                }
+                leftover = 0;
+                out.close();
+            }
+        }
+    }
+
+    /*
+     * An input stream for decoding Base64 bytes
+     */
+    private static class DecInputStream extends InputStream {
+
+        private final InputStream is;
+        private final boolean isMIME;
+        private final int[] base64;      // base64 -> byte mapping
+        private int bits = 0;            // 24-bit buffer for decoding
+        private int nextin = 18;         // next available "off" in "bits" for input;
+                                         // -> 18, 12, 6, 0
+        private int nextout = -8;        // next available "off" in "bits" for output;
+                                         // -> 8, 0, -8 (no byte for output)
+        private boolean eof = false;
+        private boolean closed = false;
+
+        DecInputStream(InputStream is, int[] base64, boolean isMIME) {
+            this.is = is;
+            this.base64 = base64;
+            this.isMIME = isMIME;
+        }
+
+        private byte[] sbBuf = new byte[1];
+
+        @Override
+        public int read() throws IOException {
+            return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff;
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            if (closed)
+                throw new IOException("Stream is closed");
+            if (eof && nextout < 0)    // eof and no leftover
+                return -1;
+            if (off < 0 || len < 0 || len > b.length - off)
+                throw new IndexOutOfBoundsException();
+            int oldOff = off;
+            if (nextout >= 0) {       // leftover output byte(s) in bits buf
+                do {
+                    if (len == 0)
+                        return off - oldOff;
+                    b[off++] = (byte)(bits >> nextout);
+                    len--;
+                    nextout -= 8;
+                } while (nextout >= 0);
+                bits = 0;
+            }
+            while (len > 0) {
+                int v = is.read();
+                if (v == -1) {
+                    eof = true;
+                    if (nextin != 18) {
+                        if (nextin == 12)
+                            throw new IOException("Base64 stream has one un-decoded dangling byte.");
+                        // treat ending xx/xxx without padding character legal.
+                        // same logic as v == '=' below
+                        b[off++] = (byte)(bits >> (16));
+                        len--;
+                        if (nextin == 0) {           // only one padding byte
+                            if (len == 0) {          // no enough output space
+                                bits >>= 8;          // shift to lowest byte
+                                nextout = 0;
+                            } else {
+                                b[off++] = (byte) (bits >>  8);
+                            }
+                        }
+                    }
+                    if (off == oldOff)
+                        return -1;
+                    else
+                        return off - oldOff;
+                }
+                if (v == '=') {                  // padding byte(s)
+                    // =     shiftto==18 unnecessary padding
+                    // x=    shiftto==12 dangling x, invalid unit
+                    // xx=   shiftto==6 && missing last '='
+                    // xx=y  or last is not '='
+                    if (nextin == 18 || nextin == 12 ||
+                        nextin == 6 && is.read() != '=') {
+                        throw new IOException("Illegal base64 ending sequence:" + nextin);
+                    }
+                    b[off++] = (byte)(bits >> (16));
+                    len--;
+                    if (nextin == 0) {           // only one padding byte
+                        if (len == 0) {          // no enough output space
+                            bits >>= 8;          // shift to lowest byte
+                            nextout = 0;
+                        } else {
+                            b[off++] = (byte) (bits >>  8);
+                        }
+                    }
+                    eof = true;
+                    break;
+                }
+                if ((v = base64[v]) == -1) {
+                    if (isMIME)                 // skip if for rfc2045
+                        continue;
+                    else
+                        throw new IOException("Illegal base64 character " +
+                            Integer.toString(v, 16));
+                }
+                bits |= (v << nextin);
+                if (nextin == 0) {
+                    nextin = 18;    // clear for next
+                    nextout = 16;
+                    while (nextout >= 0) {
+                        b[off++] = (byte)(bits >> nextout);
+                        len--;
+                        nextout -= 8;
+                        if (len == 0 && nextout >= 0) {  // don't clean "bits"
+                            return off - oldOff;
+                        }
+                    }
+                    bits = 0;
+                } else {
+                    nextin -= 6;
+                }
+            }
+            return off - oldOff;
+        }
+
+        @Override
+        public int available() throws IOException {
+            if (closed)
+                throw new IOException("Stream is closed");
+            return is.available();   // TBD:
+        }
+
+        @Override
+        public void close() throws IOException {
+            if (!closed) {
+                closed = true;
+                is.close();
+            }
+        }
+    }
+}
diff --git a/java/util/BitSet.java b/java/util/BitSet.java
new file mode 100644
index 0000000..261a77c
--- /dev/null
+++ b/java/util/BitSet.java
@@ -0,0 +1,1248 @@
+/*
+ * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.LongBuffer;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
+
+/**
+ * This class implements a vector of bits that grows as needed. Each
+ * component of the bit set has a {@code boolean} value. The
+ * bits of a {@code BitSet} are indexed by nonnegative integers.
+ * Individual indexed bits can be examined, set, or cleared. One
+ * {@code BitSet} may be used to modify the contents of another
+ * {@code BitSet} through logical AND, logical inclusive OR, and
+ * logical exclusive OR operations.
+ *
+ * <p>By default, all bits in the set initially have the value
+ * {@code false}.
+ *
+ * <p>Every bit set has a current size, which is the number of bits
+ * of space currently in use by the bit set. Note that the size is
+ * related to the implementation of a bit set, so it may change with
+ * implementation. The length of a bit set relates to logical length
+ * of a bit set and is defined independently of implementation.
+ *
+ * <p>Unless otherwise noted, passing a null parameter to any of the
+ * methods in a {@code BitSet} will result in a
+ * {@code NullPointerException}.
+ *
+ * <p>A {@code BitSet} is not safe for multithreaded use without
+ * external synchronization.
+ *
+ * @author  Arthur van Hoff
+ * @author  Michael McCloskey
+ * @author  Martin Buchholz
+ * @since   JDK1.0
+ */
+public class BitSet implements Cloneable, java.io.Serializable {
+    /*
+     * BitSets are packed into arrays of "words."  Currently a word is
+     * a long, which consists of 64 bits, requiring 6 address bits.
+     * The choice of word size is determined purely by performance concerns.
+     */
+    private final static int ADDRESS_BITS_PER_WORD = 6;
+    private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
+    private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1;
+
+    /* Used to shift left or right for a partial word mask */
+    private static final long WORD_MASK = 0xffffffffffffffffL;
+
+    /**
+     * @serialField bits long[]
+     *
+     * The bits in this BitSet.  The ith bit is stored in bits[i/64] at
+     * bit position i % 64 (where bit position 0 refers to the least
+     * significant bit and 63 refers to the most significant bit).
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("bits", long[].class),
+    };
+
+    /**
+     * The internal field corresponding to the serialField "bits".
+     */
+    private long[] words;
+
+    /**
+     * The number of words in the logical size of this BitSet.
+     */
+    private transient int wordsInUse = 0;
+
+    /**
+     * Whether the size of "words" is user-specified.  If so, we assume
+     * the user knows what he's doing and try harder to preserve it.
+     */
+    private transient boolean sizeIsSticky = false;
+
+    /* use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = 7997698588986878753L;
+
+    /**
+     * Given a bit index, return word index containing it.
+     */
+    private static int wordIndex(int bitIndex) {
+        return bitIndex >> ADDRESS_BITS_PER_WORD;
+    }
+
+    /**
+     * Every public method must preserve these invariants.
+     */
+    private void checkInvariants() {
+        assert(wordsInUse == 0 || words[wordsInUse - 1] != 0);
+        assert(wordsInUse >= 0 && wordsInUse <= words.length);
+        assert(wordsInUse == words.length || words[wordsInUse] == 0);
+    }
+
+    /**
+     * Sets the field wordsInUse to the logical size in words of the bit set.
+     * WARNING:This method assumes that the number of words actually in use is
+     * less than or equal to the current value of wordsInUse!
+     */
+    private void recalculateWordsInUse() {
+        // Traverse the bitset until a used word is found
+        int i;
+        for (i = wordsInUse-1; i >= 0; i--)
+            if (words[i] != 0)
+                break;
+
+        wordsInUse = i+1; // The new logical size
+    }
+
+    /**
+     * Creates a new bit set. All bits are initially {@code false}.
+     */
+    public BitSet() {
+        initWords(BITS_PER_WORD);
+        sizeIsSticky = false;
+    }
+
+    /**
+     * Creates a bit set whose initial size is large enough to explicitly
+     * represent bits with indices in the range {@code 0} through
+     * {@code nbits-1}. All bits are initially {@code false}.
+     *
+     * @param  nbits the initial size of the bit set
+     * @throws NegativeArraySizeException if the specified initial size
+     *         is negative
+     */
+    public BitSet(int nbits) {
+        // nbits can't be negative; size 0 is OK
+        if (nbits < 0)
+            throw new NegativeArraySizeException("nbits < 0: " + nbits);
+
+        initWords(nbits);
+        sizeIsSticky = true;
+    }
+
+    private void initWords(int nbits) {
+        words = new long[wordIndex(nbits-1) + 1];
+    }
+
+    /**
+     * Creates a bit set using words as the internal representation.
+     * The last word (if there is one) must be non-zero.
+     */
+    private BitSet(long[] words) {
+        this.words = words;
+        this.wordsInUse = words.length;
+        checkInvariants();
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given long array.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(longs).get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
+     * <br>for all {@code n < 64 * longs.length}.
+     *
+     * <p>This method is equivalent to
+     * {@code BitSet.valueOf(LongBuffer.wrap(longs))}.
+     *
+     * @param longs a long array containing a little-endian representation
+     *        of a sequence of bits to be used as the initial bits of the
+     *        new bit set
+     * @return a {@code BitSet} containing all the bits in the long array
+     * @since 1.7
+     */
+    public static BitSet valueOf(long[] longs) {
+        int n;
+        for (n = longs.length; n > 0 && longs[n - 1] == 0; n--)
+            ;
+        return new BitSet(Arrays.copyOf(longs, n));
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given long
+     * buffer between its position and limit.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(lb).get(n) == ((lb.get(lb.position()+n/64) & (1L<<(n%64))) != 0)}
+     * <br>for all {@code n < 64 * lb.remaining()}.
+     *
+     * <p>The long buffer is not modified by this method, and no
+     * reference to the buffer is retained by the bit set.
+     *
+     * @param lb a long buffer containing a little-endian representation
+     *        of a sequence of bits between its position and limit, to be
+     *        used as the initial bits of the new bit set
+     * @return a {@code BitSet} containing all the bits in the buffer in the
+     *         specified range
+     * @since 1.7
+     */
+    public static BitSet valueOf(LongBuffer lb) {
+        lb = lb.slice();
+        int n;
+        for (n = lb.remaining(); n > 0 && lb.get(n - 1) == 0; n--)
+            ;
+        long[] words = new long[n];
+        lb.get(words);
+        return new BitSet(words);
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given byte array.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(bytes).get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
+     * <br>for all {@code n <  8 * bytes.length}.
+     *
+     * <p>This method is equivalent to
+     * {@code BitSet.valueOf(ByteBuffer.wrap(bytes))}.
+     *
+     * @param bytes a byte array containing a little-endian
+     *        representation of a sequence of bits to be used as the
+     *        initial bits of the new bit set
+     * @return a {@code BitSet} containing all the bits in the byte array
+     * @since 1.7
+     */
+    public static BitSet valueOf(byte[] bytes) {
+        return BitSet.valueOf(ByteBuffer.wrap(bytes));
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given byte
+     * buffer between its position and limit.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(bb).get(n) == ((bb.get(bb.position()+n/8) & (1<<(n%8))) != 0)}
+     * <br>for all {@code n < 8 * bb.remaining()}.
+     *
+     * <p>The byte buffer is not modified by this method, and no
+     * reference to the buffer is retained by the bit set.
+     *
+     * @param bb a byte buffer containing a little-endian representation
+     *        of a sequence of bits between its position and limit, to be
+     *        used as the initial bits of the new bit set
+     * @return a {@code BitSet} containing all the bits in the buffer in the
+     *         specified range
+     * @since 1.7
+     */
+    public static BitSet valueOf(ByteBuffer bb) {
+        bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
+        int n;
+        for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--)
+            ;
+        long[] words = new long[(n + 7) / 8];
+        bb.limit(n);
+        int i = 0;
+        while (bb.remaining() >= 8)
+            words[i++] = bb.getLong();
+        for (int remaining = bb.remaining(), j = 0; j < remaining; j++)
+            words[i] |= (bb.get() & 0xffL) << (8 * j);
+        return new BitSet(words);
+    }
+
+    /**
+     * Returns a new byte array containing all the bits in this bit set.
+     *
+     * <p>More precisely, if
+     * <br>{@code byte[] bytes = s.toByteArray();}
+     * <br>then {@code bytes.length == (s.length()+7)/8} and
+     * <br>{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
+     * <br>for all {@code n < 8 * bytes.length}.
+     *
+     * @return a byte array containing a little-endian representation
+     *         of all the bits in this bit set
+     * @since 1.7
+    */
+    public byte[] toByteArray() {
+        int n = wordsInUse;
+        if (n == 0)
+            return new byte[0];
+        int len = 8 * (n-1);
+        for (long x = words[n - 1]; x != 0; x >>>= 8)
+            len++;
+        byte[] bytes = new byte[len];
+        ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
+        for (int i = 0; i < n - 1; i++)
+            bb.putLong(words[i]);
+        for (long x = words[n - 1]; x != 0; x >>>= 8)
+            bb.put((byte) (x & 0xff));
+        return bytes;
+    }
+
+    /**
+     * Returns a new long array containing all the bits in this bit set.
+     *
+     * <p>More precisely, if
+     * <br>{@code long[] longs = s.toLongArray();}
+     * <br>then {@code longs.length == (s.length()+63)/64} and
+     * <br>{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
+     * <br>for all {@code n < 64 * longs.length}.
+     *
+     * @return a long array containing a little-endian representation
+     *         of all the bits in this bit set
+     * @since 1.7
+    */
+    public long[] toLongArray() {
+        return Arrays.copyOf(words, wordsInUse);
+    }
+
+    /**
+     * Ensures that the BitSet can hold enough words.
+     * @param wordsRequired the minimum acceptable number of words.
+     */
+    private void ensureCapacity(int wordsRequired) {
+        if (words.length < wordsRequired) {
+            // Allocate larger of doubled size or required size
+            int request = Math.max(2 * words.length, wordsRequired);
+            words = Arrays.copyOf(words, request);
+            sizeIsSticky = false;
+        }
+    }
+
+    /**
+     * Ensures that the BitSet can accommodate a given wordIndex,
+     * temporarily violating the invariants.  The caller must
+     * restore the invariants before returning to the user,
+     * possibly using recalculateWordsInUse().
+     * @param wordIndex the index to be accommodated.
+     */
+    private void expandTo(int wordIndex) {
+        int wordsRequired = wordIndex+1;
+        if (wordsInUse < wordsRequired) {
+            ensureCapacity(wordsRequired);
+            wordsInUse = wordsRequired;
+        }
+    }
+
+    /**
+     * Checks that fromIndex ... toIndex is a valid range of bit indices.
+     */
+    private static void checkRange(int fromIndex, int toIndex) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+        if (toIndex < 0)
+            throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex);
+        if (fromIndex > toIndex)
+            throw new IndexOutOfBoundsException("fromIndex: " + fromIndex +
+                                                " > toIndex: " + toIndex);
+    }
+
+    /**
+     * Sets the bit at the specified index to the complement of its
+     * current value.
+     *
+     * @param  bitIndex the index of the bit to flip
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public void flip(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        int wordIndex = wordIndex(bitIndex);
+        expandTo(wordIndex);
+
+        words[wordIndex] ^= (1L << bitIndex);
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets each bit from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to the complement of its current
+     * value.
+     *
+     * @param  fromIndex index of the first bit to flip
+     * @param  toIndex index after the last bit to flip
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void flip(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        if (fromIndex == toIndex)
+            return;
+
+        int startWordIndex = wordIndex(fromIndex);
+        int endWordIndex   = wordIndex(toIndex - 1);
+        expandTo(endWordIndex);
+
+        long firstWordMask = WORD_MASK << fromIndex;
+        long lastWordMask  = WORD_MASK >>> -toIndex;
+        if (startWordIndex == endWordIndex) {
+            // Case 1: One word
+            words[startWordIndex] ^= (firstWordMask & lastWordMask);
+        } else {
+            // Case 2: Multiple words
+            // Handle first word
+            words[startWordIndex] ^= firstWordMask;
+
+            // Handle intermediate words, if any
+            for (int i = startWordIndex+1; i < endWordIndex; i++)
+                words[i] ^= WORD_MASK;
+
+            // Handle last word
+            words[endWordIndex] ^= lastWordMask;
+        }
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bit at the specified index to {@code true}.
+     *
+     * @param  bitIndex a bit index
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  JDK1.0
+     */
+    public void set(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        int wordIndex = wordIndex(bitIndex);
+        expandTo(wordIndex);
+
+        words[wordIndex] |= (1L << bitIndex); // Restores invariants
+
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bit at the specified index to the specified value.
+     *
+     * @param  bitIndex a bit index
+     * @param  value a boolean value to set
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public void set(int bitIndex, boolean value) {
+        if (value)
+            set(bitIndex);
+        else
+            clear(bitIndex);
+    }
+
+    /**
+     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to {@code true}.
+     *
+     * @param  fromIndex index of the first bit to be set
+     * @param  toIndex index after the last bit to be set
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void set(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        if (fromIndex == toIndex)
+            return;
+
+        // Increase capacity if necessary
+        int startWordIndex = wordIndex(fromIndex);
+        int endWordIndex   = wordIndex(toIndex - 1);
+        expandTo(endWordIndex);
+
+        long firstWordMask = WORD_MASK << fromIndex;
+        long lastWordMask  = WORD_MASK >>> -toIndex;
+        if (startWordIndex == endWordIndex) {
+            // Case 1: One word
+            words[startWordIndex] |= (firstWordMask & lastWordMask);
+        } else {
+            // Case 2: Multiple words
+            // Handle first word
+            words[startWordIndex] |= firstWordMask;
+
+            // Handle intermediate words, if any
+            for (int i = startWordIndex+1; i < endWordIndex; i++)
+                words[i] = WORD_MASK;
+
+            // Handle last word (restores invariants)
+            words[endWordIndex] |= lastWordMask;
+        }
+
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to the specified value.
+     *
+     * @param  fromIndex index of the first bit to be set
+     * @param  toIndex index after the last bit to be set
+     * @param  value value to set the selected bits to
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void set(int fromIndex, int toIndex, boolean value) {
+        if (value)
+            set(fromIndex, toIndex);
+        else
+            clear(fromIndex, toIndex);
+    }
+
+    /**
+     * Sets the bit specified by the index to {@code false}.
+     *
+     * @param  bitIndex the index of the bit to be cleared
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  JDK1.0
+     */
+    public void clear(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        int wordIndex = wordIndex(bitIndex);
+        if (wordIndex >= wordsInUse)
+            return;
+
+        words[wordIndex] &= ~(1L << bitIndex);
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to {@code false}.
+     *
+     * @param  fromIndex index of the first bit to be cleared
+     * @param  toIndex index after the last bit to be cleared
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void clear(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        if (fromIndex == toIndex)
+            return;
+
+        int startWordIndex = wordIndex(fromIndex);
+        if (startWordIndex >= wordsInUse)
+            return;
+
+        int endWordIndex = wordIndex(toIndex - 1);
+        if (endWordIndex >= wordsInUse) {
+            toIndex = length();
+            endWordIndex = wordsInUse - 1;
+        }
+
+        long firstWordMask = WORD_MASK << fromIndex;
+        long lastWordMask  = WORD_MASK >>> -toIndex;
+        if (startWordIndex == endWordIndex) {
+            // Case 1: One word
+            words[startWordIndex] &= ~(firstWordMask & lastWordMask);
+        } else {
+            // Case 2: Multiple words
+            // Handle first word
+            words[startWordIndex] &= ~firstWordMask;
+
+            // Handle intermediate words, if any
+            for (int i = startWordIndex+1; i < endWordIndex; i++)
+                words[i] = 0;
+
+            // Handle last word
+            words[endWordIndex] &= ~lastWordMask;
+        }
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets all of the bits in this BitSet to {@code false}.
+     *
+     * @since 1.4
+     */
+    public void clear() {
+        while (wordsInUse > 0)
+            words[--wordsInUse] = 0;
+    }
+
+    /**
+     * Returns the value of the bit with the specified index. The value
+     * is {@code true} if the bit with the index {@code bitIndex}
+     * is currently set in this {@code BitSet}; otherwise, the result
+     * is {@code false}.
+     *
+     * @param  bitIndex   the bit index
+     * @return the value of the bit with the specified index
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     */
+    public boolean get(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        checkInvariants();
+
+        int wordIndex = wordIndex(bitIndex);
+        return (wordIndex < wordsInUse)
+            && ((words[wordIndex] & (1L << bitIndex)) != 0);
+    }
+
+    /**
+     * Returns a new {@code BitSet} composed of bits from this {@code BitSet}
+     * from {@code fromIndex} (inclusive) to {@code toIndex} (exclusive).
+     *
+     * @param  fromIndex index of the first bit to include
+     * @param  toIndex index after the last bit to include
+     * @return a new {@code BitSet} from a range of this {@code BitSet}
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public BitSet get(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        checkInvariants();
+
+        int len = length();
+
+        // If no set bits in range return empty bitset
+        if (len <= fromIndex || fromIndex == toIndex)
+            return new BitSet(0);
+
+        // An optimization
+        if (toIndex > len)
+            toIndex = len;
+
+        BitSet result = new BitSet(toIndex - fromIndex);
+        int targetWords = wordIndex(toIndex - fromIndex - 1) + 1;
+        int sourceIndex = wordIndex(fromIndex);
+        boolean wordAligned = ((fromIndex & BIT_INDEX_MASK) == 0);
+
+        // Process all words but the last word
+        for (int i = 0; i < targetWords - 1; i++, sourceIndex++)
+            result.words[i] = wordAligned ? words[sourceIndex] :
+                (words[sourceIndex] >>> fromIndex) |
+                (words[sourceIndex+1] << -fromIndex);
+
+        // Process the last word
+        long lastWordMask = WORD_MASK >>> -toIndex;
+        result.words[targetWords - 1] =
+            ((toIndex-1) & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK)
+            ? /* straddles source words */
+            ((words[sourceIndex] >>> fromIndex) |
+             (words[sourceIndex+1] & lastWordMask) << -fromIndex)
+            :
+            ((words[sourceIndex] & lastWordMask) >>> fromIndex);
+
+        // Set wordsInUse correctly
+        result.wordsInUse = targetWords;
+        result.recalculateWordsInUse();
+        result.checkInvariants();
+
+        return result;
+    }
+
+    /**
+     * Returns the index of the first bit that is set to {@code true}
+     * that occurs on or after the specified starting index. If no such
+     * bit exists then {@code -1} is returned.
+     *
+     * <p>To iterate over the {@code true} bits in a {@code BitSet},
+     * use the following loop:
+     *
+     *  <pre> {@code
+     * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
+     *     // operate on index i here
+     *     if (i == Integer.MAX_VALUE) {
+     *         break; // or (i+1) would overflow
+     *     }
+     * }}</pre>
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the next set bit, or {@code -1} if there
+     *         is no such bit
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public int nextSetBit(int fromIndex) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return -1;
+
+        long word = words[u] & (WORD_MASK << fromIndex);
+
+        while (true) {
+            if (word != 0)
+                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
+            if (++u == wordsInUse)
+                return -1;
+            word = words[u];
+        }
+    }
+
+    /**
+     * Returns the index of the first bit that is set to {@code false}
+     * that occurs on or after the specified starting index.
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the next clear bit
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public int nextClearBit(int fromIndex) {
+        // Neither spec nor implementation handle bitsets of maximal length.
+        // See 4816253.
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return fromIndex;
+
+        long word = ~words[u] & (WORD_MASK << fromIndex);
+
+        while (true) {
+            if (word != 0)
+                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
+            if (++u == wordsInUse)
+                return wordsInUse * BITS_PER_WORD;
+            word = ~words[u];
+        }
+    }
+
+    /**
+     * Returns the index of the nearest bit that is set to {@code true}
+     * that occurs on or before the specified starting index.
+     * If no such bit exists, or if {@code -1} is given as the
+     * starting index, then {@code -1} is returned.
+     *
+     * <p>To iterate over the {@code true} bits in a {@code BitSet},
+     * use the following loop:
+     *
+     *  <pre> {@code
+     * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
+     *     // operate on index i here
+     * }}</pre>
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the previous set bit, or {@code -1} if there
+     *         is no such bit
+     * @throws IndexOutOfBoundsException if the specified index is less
+     *         than {@code -1}
+     * @since  1.7
+     */
+    public int previousSetBit(int fromIndex) {
+        if (fromIndex < 0) {
+            if (fromIndex == -1)
+                return -1;
+            throw new IndexOutOfBoundsException(
+                "fromIndex < -1: " + fromIndex);
+        }
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return length() - 1;
+
+        long word = words[u] & (WORD_MASK >>> -(fromIndex+1));
+
+        while (true) {
+            if (word != 0)
+                return (u+1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word);
+            if (u-- == 0)
+                return -1;
+            word = words[u];
+        }
+    }
+
+    /**
+     * Returns the index of the nearest bit that is set to {@code false}
+     * that occurs on or before the specified starting index.
+     * If no such bit exists, or if {@code -1} is given as the
+     * starting index, then {@code -1} is returned.
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the previous clear bit, or {@code -1} if there
+     *         is no such bit
+     * @throws IndexOutOfBoundsException if the specified index is less
+     *         than {@code -1}
+     * @since  1.7
+     */
+    public int previousClearBit(int fromIndex) {
+        if (fromIndex < 0) {
+            if (fromIndex == -1)
+                return -1;
+            throw new IndexOutOfBoundsException(
+                "fromIndex < -1: " + fromIndex);
+        }
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return fromIndex;
+
+        long word = ~words[u] & (WORD_MASK >>> -(fromIndex+1));
+
+        while (true) {
+            if (word != 0)
+                return (u+1) * BITS_PER_WORD -1 - Long.numberOfLeadingZeros(word);
+            if (u-- == 0)
+                return -1;
+            word = ~words[u];
+        }
+    }
+
+    /**
+     * Returns the "logical size" of this {@code BitSet}: the index of
+     * the highest set bit in the {@code BitSet} plus one. Returns zero
+     * if the {@code BitSet} contains no set bits.
+     *
+     * @return the logical size of this {@code BitSet}
+     * @since  1.2
+     */
+    public int length() {
+        if (wordsInUse == 0)
+            return 0;
+
+        return BITS_PER_WORD * (wordsInUse - 1) +
+            (BITS_PER_WORD - Long.numberOfLeadingZeros(words[wordsInUse - 1]));
+    }
+
+    /**
+     * Returns true if this {@code BitSet} contains no bits that are set
+     * to {@code true}.
+     *
+     * @return boolean indicating whether this {@code BitSet} is empty
+     * @since  1.4
+     */
+    public boolean isEmpty() {
+        return wordsInUse == 0;
+    }
+
+    /**
+     * Returns true if the specified {@code BitSet} has any bits set to
+     * {@code true} that are also set to {@code true} in this {@code BitSet}.
+     *
+     * @param  set {@code BitSet} to intersect with
+     * @return boolean indicating whether this {@code BitSet} intersects
+     *         the specified {@code BitSet}
+     * @since  1.4
+     */
+    public boolean intersects(BitSet set) {
+        for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
+            if ((words[i] & set.words[i]) != 0)
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns the number of bits set to {@code true} in this {@code BitSet}.
+     *
+     * @return the number of bits set to {@code true} in this {@code BitSet}
+     * @since  1.4
+     */
+    public int cardinality() {
+        int sum = 0;
+        for (int i = 0; i < wordsInUse; i++)
+            sum += Long.bitCount(words[i]);
+        return sum;
+    }
+
+    /**
+     * Performs a logical <b>AND</b> of this target bit set with the
+     * argument bit set. This bit set is modified so that each bit in it
+     * has the value {@code true} if and only if it both initially
+     * had the value {@code true} and the corresponding bit in the
+     * bit set argument also had the value {@code true}.
+     *
+     * @param set a bit set
+     */
+    public void and(BitSet set) {
+        if (this == set)
+            return;
+
+        while (wordsInUse > set.wordsInUse)
+            words[--wordsInUse] = 0;
+
+        // Perform logical AND on words in common
+        for (int i = 0; i < wordsInUse; i++)
+            words[i] &= set.words[i];
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Performs a logical <b>OR</b> of this bit set with the bit set
+     * argument. This bit set is modified so that a bit in it has the
+     * value {@code true} if and only if it either already had the
+     * value {@code true} or the corresponding bit in the bit set
+     * argument has the value {@code true}.
+     *
+     * @param set a bit set
+     */
+    public void or(BitSet set) {
+        if (this == set)
+            return;
+
+        int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
+
+        if (wordsInUse < set.wordsInUse) {
+            ensureCapacity(set.wordsInUse);
+            wordsInUse = set.wordsInUse;
+        }
+
+        // Perform logical OR on words in common
+        for (int i = 0; i < wordsInCommon; i++)
+            words[i] |= set.words[i];
+
+        // Copy any remaining words
+        if (wordsInCommon < set.wordsInUse)
+            System.arraycopy(set.words, wordsInCommon,
+                             words, wordsInCommon,
+                             wordsInUse - wordsInCommon);
+
+        // recalculateWordsInUse() is unnecessary
+        checkInvariants();
+    }
+
+    /**
+     * Performs a logical <b>XOR</b> of this bit set with the bit set
+     * argument. This bit set is modified so that a bit in it has the
+     * value {@code true} if and only if one of the following
+     * statements holds:
+     * <ul>
+     * <li>The bit initially has the value {@code true}, and the
+     *     corresponding bit in the argument has the value {@code false}.
+     * <li>The bit initially has the value {@code false}, and the
+     *     corresponding bit in the argument has the value {@code true}.
+     * </ul>
+     *
+     * @param  set a bit set
+     */
+    public void xor(BitSet set) {
+        int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
+
+        if (wordsInUse < set.wordsInUse) {
+            ensureCapacity(set.wordsInUse);
+            wordsInUse = set.wordsInUse;
+        }
+
+        // Perform logical XOR on words in common
+        for (int i = 0; i < wordsInCommon; i++)
+            words[i] ^= set.words[i];
+
+        // Copy any remaining words
+        if (wordsInCommon < set.wordsInUse)
+            System.arraycopy(set.words, wordsInCommon,
+                             words, wordsInCommon,
+                             set.wordsInUse - wordsInCommon);
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Clears all of the bits in this {@code BitSet} whose corresponding
+     * bit is set in the specified {@code BitSet}.
+     *
+     * @param  set the {@code BitSet} with which to mask this
+     *         {@code BitSet}
+     * @since  1.2
+     */
+    public void andNot(BitSet set) {
+        // Perform logical (a & !b) on words in common
+        for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
+            words[i] &= ~set.words[i];
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Returns the hash code value for this bit set. The hash code depends
+     * only on which bits are set within this {@code BitSet}.
+     *
+     * <p>The hash code is defined to be the result of the following
+     * calculation:
+     *  <pre> {@code
+     * public int hashCode() {
+     *     long h = 1234;
+     *     long[] words = toLongArray();
+     *     for (int i = words.length; --i >= 0; )
+     *         h ^= words[i] * (i + 1);
+     *     return (int)((h >> 32) ^ h);
+     * }}</pre>
+     * Note that the hash code changes if the set of bits is altered.
+     *
+     * @return the hash code value for this bit set
+     */
+    public int hashCode() {
+        long h = 1234;
+        for (int i = wordsInUse; --i >= 0; )
+            h ^= words[i] * (i + 1);
+
+        return (int)((h >> 32) ^ h);
+    }
+
+    /**
+     * Returns the number of bits of space actually in use by this
+     * {@code BitSet} to represent bit values.
+     * The maximum element in the set is the size - 1st element.
+     *
+     * @return the number of bits currently in this bit set
+     */
+    public int size() {
+        return words.length * BITS_PER_WORD;
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and is a {@code Bitset} object that has
+     * exactly the same set of bits set to {@code true} as this bit
+     * set. That is, for every nonnegative {@code int} index {@code k},
+     * <pre>((BitSet)obj).get(k) == this.get(k)</pre>
+     * must be true. The current sizes of the two bit sets are not compared.
+     *
+     * @param  obj the object to compare with
+     * @return {@code true} if the objects are the same;
+     *         {@code false} otherwise
+     * @see    #size()
+     */
+    public boolean equals(Object obj) {
+        if (!(obj instanceof BitSet))
+            return false;
+        if (this == obj)
+            return true;
+
+        BitSet set = (BitSet) obj;
+
+        checkInvariants();
+        set.checkInvariants();
+
+        if (wordsInUse != set.wordsInUse)
+            return false;
+
+        // Check words in use by both BitSets
+        for (int i = 0; i < wordsInUse; i++)
+            if (words[i] != set.words[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Cloning this {@code BitSet} produces a new {@code BitSet}
+     * that is equal to it.
+     * The clone of the bit set is another bit set that has exactly the
+     * same bits set to {@code true} as this bit set.
+     *
+     * @return a clone of this bit set
+     * @see    #size()
+     */
+    public Object clone() {
+        if (! sizeIsSticky)
+            trimToSize();
+
+        try {
+            BitSet result = (BitSet) super.clone();
+            result.words = words.clone();
+            result.checkInvariants();
+            return result;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Attempts to reduce internal storage used for the bits in this bit set.
+     * Calling this method may, but is not required to, affect the value
+     * returned by a subsequent call to the {@link #size()} method.
+     */
+    private void trimToSize() {
+        if (wordsInUse != words.length) {
+            words = Arrays.copyOf(words, wordsInUse);
+            checkInvariants();
+        }
+    }
+
+    /**
+     * Save the state of the {@code BitSet} instance to a stream (i.e.,
+     * serialize it).
+     */
+    private void writeObject(ObjectOutputStream s)
+        throws IOException {
+
+        checkInvariants();
+
+        if (! sizeIsSticky)
+            trimToSize();
+
+        ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("bits", words);
+        s.writeFields();
+    }
+
+    /**
+     * Reconstitute the {@code BitSet} instance from a stream (i.e.,
+     * deserialize it).
+     */
+    private void readObject(ObjectInputStream s)
+        throws IOException, ClassNotFoundException {
+
+        ObjectInputStream.GetField fields = s.readFields();
+        words = (long[]) fields.get("bits", null);
+
+        // Assume maximum length then find real length
+        // because recalculateWordsInUse assumes maintenance
+        // or reduction in logical size
+        wordsInUse = words.length;
+        recalculateWordsInUse();
+        sizeIsSticky = (words.length > 0 && words[words.length-1] == 0L); // heuristic
+        checkInvariants();
+    }
+
+    /**
+     * Returns a string representation of this bit set. For every index
+     * for which this {@code BitSet} contains a bit in the set
+     * state, the decimal representation of that index is included in
+     * the result. Such indices are listed in order from lowest to
+     * highest, separated by ",&nbsp;" (a comma and a space) and
+     * surrounded by braces, resulting in the usual mathematical
+     * notation for a set of integers.
+     *
+     * <p>Example:
+     * <pre>
+     * BitSet drPepper = new BitSet();</pre>
+     * Now {@code drPepper.toString()} returns "{@code {}}".
+     * <pre>
+     * drPepper.set(2);</pre>
+     * Now {@code drPepper.toString()} returns "{@code {2}}".
+     * <pre>
+     * drPepper.set(4);
+     * drPepper.set(10);</pre>
+     * Now {@code drPepper.toString()} returns "{@code {2, 4, 10}}".
+     *
+     * @return a string representation of this bit set
+     */
+    public String toString() {
+        checkInvariants();
+
+        int numBits = (wordsInUse > 128) ?
+            cardinality() : wordsInUse * BITS_PER_WORD;
+        StringBuilder b = new StringBuilder(6*numBits + 2);
+        b.append('{');
+
+        int i = nextSetBit(0);
+        if (i != -1) {
+            b.append(i);
+            while (true) {
+                if (++i < 0) break;
+                if ((i = nextSetBit(i)) < 0) break;
+                int endOfRun = nextClearBit(i);
+                do { b.append(", ").append(i); }
+                while (++i != endOfRun);
+            }
+        }
+
+        b.append('}');
+        return b.toString();
+    }
+
+    /**
+     * Returns a stream of indices for which this {@code BitSet}
+     * contains a bit in the set state. The indices are returned
+     * in order, from lowest to highest. The size of the stream
+     * is the number of bits in the set state, equal to the value
+     * returned by the {@link #cardinality()} method.
+     *
+     * <p>The bit set must remain constant during the execution of the
+     * terminal stream operation.  Otherwise, the result of the terminal
+     * stream operation is undefined.
+     *
+     * @return a stream of integers representing set indices
+     * @since 1.8
+     */
+    public IntStream stream() {
+        class BitSetIterator implements PrimitiveIterator.OfInt {
+            int next = nextSetBit(0);
+
+            @Override
+            public boolean hasNext() {
+                return next != -1;
+            }
+
+            @Override
+            public int nextInt() {
+                if (next != -1) {
+                    int ret = next;
+                    next = nextSetBit(next+1);
+                    return ret;
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+        }
+
+        return StreamSupport.intStream(
+                () -> Spliterators.spliterator(
+                        new BitSetIterator(), cardinality(),
+                        Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED),
+                Spliterator.SIZED | Spliterator.SUBSIZED |
+                        Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED,
+                false);
+    }
+}
diff --git a/java/util/Calendar.annotated.java b/java/util/Calendar.annotated.java
new file mode 100644
index 0000000..73efc29
--- /dev/null
+++ b/java/util/Calendar.annotated.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+
+package java.util;
+
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.time.Instant;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class Calendar implements java.io.Serializable, java.lang.Cloneable, java.lang.Comparable<java.util.Calendar> {
+
+protected Calendar() { throw new RuntimeException("Stub!"); }
+
+protected Calendar(@libcore.util.NonNull java.util.TimeZone zone, @libcore.util.NonNull java.util.Locale aLocale) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Calendar getInstance() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Calendar getInstance(@libcore.util.NonNull java.util.TimeZone zone) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Calendar getInstance(@libcore.util.NonNull java.util.Locale aLocale) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Calendar getInstance(@libcore.util.NonNull java.util.TimeZone zone, @libcore.util.NonNull java.util.Locale aLocale) { throw new RuntimeException("Stub!"); }
+
+public static synchronized [email protected] Locale @libcore.util.NonNull [] getAvailableLocales() { throw new RuntimeException("Stub!"); }
+
+protected abstract void computeTime();
+
+protected abstract void computeFields();
+
[email protected] public final java.util.Date getTime() { throw new RuntimeException("Stub!"); }
+
+public final void setTime(@libcore.util.NonNull java.util.Date date) { throw new RuntimeException("Stub!"); }
+
+public long getTimeInMillis() { throw new RuntimeException("Stub!"); }
+
+public void setTimeInMillis(long millis) { throw new RuntimeException("Stub!"); }
+
+public int get(int field) { throw new RuntimeException("Stub!"); }
+
+protected final int internalGet(int field) { throw new RuntimeException("Stub!"); }
+
+public void set(int field, int value) { throw new RuntimeException("Stub!"); }
+
+public final void set(int year, int month, int date) { throw new RuntimeException("Stub!"); }
+
+public final void set(int year, int month, int date, int hourOfDay, int minute) { throw new RuntimeException("Stub!"); }
+
+public final void set(int year, int month, int date, int hourOfDay, int minute, int second) { throw new RuntimeException("Stub!"); }
+
+public final void clear() { throw new RuntimeException("Stub!"); }
+
+public final void clear(int field) { throw new RuntimeException("Stub!"); }
+
+public final boolean isSet(int field) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getDisplayName(int field, int style, @libcore.util.NonNull java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map<[email protected] String, [email protected] Integer> getDisplayNames(int field, int style, @libcore.util.NonNull java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
+protected void complete() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Set<[email protected] String> getAvailableCalendarTypes() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getCalendarType() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean before(@libcore.util.Nullable java.lang.Object when) { throw new RuntimeException("Stub!"); }
+
+public boolean after(@libcore.util.Nullable java.lang.Object when) { throw new RuntimeException("Stub!"); }
+
+public int compareTo(@libcore.util.NonNull java.util.Calendar anotherCalendar) { throw new RuntimeException("Stub!"); }
+
+public abstract void add(int field, int amount);
+
+public abstract void roll(int field, boolean up);
+
+public void roll(int field, int amount) { throw new RuntimeException("Stub!"); }
+
+public void setTimeZone(@libcore.util.NonNull java.util.TimeZone value) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.TimeZone getTimeZone() { throw new RuntimeException("Stub!"); }
+
+public void setLenient(boolean lenient) { throw new RuntimeException("Stub!"); }
+
+public boolean isLenient() { throw new RuntimeException("Stub!"); }
+
+public void setFirstDayOfWeek(int value) { throw new RuntimeException("Stub!"); }
+
+public int getFirstDayOfWeek() { throw new RuntimeException("Stub!"); }
+
+public void setMinimalDaysInFirstWeek(int value) { throw new RuntimeException("Stub!"); }
+
+public int getMinimalDaysInFirstWeek() { throw new RuntimeException("Stub!"); }
+
+public boolean isWeekDateSupported() { throw new RuntimeException("Stub!"); }
+
+public int getWeekYear() { throw new RuntimeException("Stub!"); }
+
+public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) { throw new RuntimeException("Stub!"); }
+
+public int getWeeksInWeekYear() { throw new RuntimeException("Stub!"); }
+
+public abstract int getMinimum(int field);
+
+public abstract int getMaximum(int field);
+
+public abstract int getGreatestMinimum(int field);
+
+public abstract int getLeastMaximum(int field);
+
+public int getActualMinimum(int field) { throw new RuntimeException("Stub!"); }
+
+public int getActualMaximum(int field) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.time.Instant toInstant() { throw new RuntimeException("Stub!"); }
+
+public static final int ALL_STYLES = 0; // 0x0
+
+public static final int AM = 0; // 0x0
+
+public static final int AM_PM = 9; // 0x9
+
+public static final int APRIL = 3; // 0x3
+
+public static final int AUGUST = 7; // 0x7
+
+public static final int DATE = 5; // 0x5
+
+public static final int DAY_OF_MONTH = 5; // 0x5
+
+public static final int DAY_OF_WEEK = 7; // 0x7
+
+public static final int DAY_OF_WEEK_IN_MONTH = 8; // 0x8
+
+public static final int DAY_OF_YEAR = 6; // 0x6
+
+public static final int DECEMBER = 11; // 0xb
+
+public static final int DST_OFFSET = 16; // 0x10
+
+public static final int ERA = 0; // 0x0
+
+public static final int FEBRUARY = 1; // 0x1
+
+public static final int FIELD_COUNT = 17; // 0x11
+
+public static final int FRIDAY = 6; // 0x6
+
+public static final int HOUR = 10; // 0xa
+
+public static final int HOUR_OF_DAY = 11; // 0xb
+
+public static final int JANUARY = 0; // 0x0
+
+public static final int JULY = 6; // 0x6
+
+public static final int JUNE = 5; // 0x5
+
+public static final int LONG = 2; // 0x2
+
+public static final int LONG_FORMAT = 2; // 0x2
+
+public static final int LONG_STANDALONE = 32770; // 0x8002
+
+public static final int MARCH = 2; // 0x2
+
+public static final int MAY = 4; // 0x4
+
+public static final int MILLISECOND = 14; // 0xe
+
+public static final int MINUTE = 12; // 0xc
+
+public static final int MONDAY = 2; // 0x2
+
+public static final int MONTH = 2; // 0x2
+
+public static final int NARROW_FORMAT = 4; // 0x4
+
+public static final int NARROW_STANDALONE = 32772; // 0x8004
+
+public static final int NOVEMBER = 10; // 0xa
+
+public static final int OCTOBER = 9; // 0x9
+
+public static final int PM = 1; // 0x1
+
+public static final int SATURDAY = 7; // 0x7
+
+public static final int SECOND = 13; // 0xd
+
+public static final int SEPTEMBER = 8; // 0x8
+
+public static final int SHORT = 1; // 0x1
+
+public static final int SHORT_FORMAT = 1; // 0x1
+
+public static final int SHORT_STANDALONE = 32769; // 0x8001
+
+public static final int SUNDAY = 1; // 0x1
+
+public static final int THURSDAY = 5; // 0x5
+
+public static final int TUESDAY = 3; // 0x3
+
+public static final int UNDECIMBER = 12; // 0xc
+
+public static final int WEDNESDAY = 4; // 0x4
+
+public static final int WEEK_OF_MONTH = 4; // 0x4
+
+public static final int WEEK_OF_YEAR = 3; // 0x3
+
+public static final int YEAR = 1; // 0x1
+
+public static final int ZONE_OFFSET = 15; // 0xf
+
+protected boolean areFieldsSet;
+
+protected int @libcore.util.NonNull [] fields;
+
+protected boolean @libcore.util.NonNull [] isSet;
+
+protected boolean isTimeSet;
+
+protected long time;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static class Builder {
+
+public Builder() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setInstant(long instant) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setInstant(@libcore.util.NonNull java.util.Date instant) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder set(int field, int value) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setFields(int @libcore.util.NonNull ... fieldValuePairs) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setDate(int year, int month, int dayOfMonth) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setTimeOfDay(int hourOfDay, int minute, int second) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setTimeOfDay(int hourOfDay, int minute, int second, int millis) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setTimeZone(@libcore.util.NonNull java.util.TimeZone zone) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setLenient(boolean lenient) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setCalendarType(@libcore.util.NonNull java.lang.String type) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setLocale(@libcore.util.NonNull java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setWeekDefinition(int firstDayOfWeek, int minimalDaysInFirstWeek) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar build() { throw new RuntimeException("Stub!"); }
+}
+
+}
diff --git a/java/util/Calendar.java b/java/util/Calendar.java
new file mode 100644
index 0000000..3a0343b
--- /dev/null
+++ b/java/util/Calendar.java
@@ -0,0 +1,3595 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.security.AccessControlContext;
+import java.security.PermissionCollection;
+import java.security.ProtectionDomain;
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.time.Instant;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import libcore.icu.LocaleData;
+import sun.util.locale.provider.CalendarDataUtility;
+
+/**
+ * The <code>Calendar</code> class is an abstract class that provides methods
+ * for converting between a specific instant in time and a set of {@link
+ * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>,
+ * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, and so on, and for
+ * manipulating the calendar fields, such as getting the date of the next
+ * week. An instant in time can be represented by a millisecond value that is
+ * an offset from the <a name="Epoch"><em>Epoch</em></a>, January 1, 1970
+ * 00:00:00.000 GMT (Gregorian).
+ *
+ * <p>The class also provides additional fields and methods for
+ * implementing a concrete calendar system outside the package. Those
+ * fields and methods are defined as <code>protected</code>.
+ *
+ * <p>
+ * Like other locale-sensitive classes, <code>Calendar</code> provides a
+ * class method, <code>getInstance</code>, for getting a generally useful
+ * object of this type. <code>Calendar</code>'s <code>getInstance</code> method
+ * returns a <code>Calendar</code> object whose
+ * calendar fields have been initialized with the current date and time:
+ * <blockquote>
+ * <pre>
+ *     Calendar rightNow = Calendar.getInstance();
+ * </pre>
+ * </blockquote>
+ *
+ * <p>A <code>Calendar</code> object can produce all the calendar field values
+ * needed to implement the date-time formatting for a particular language and
+ * calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
+ * <code>Calendar</code> defines the range of values returned by
+ * certain calendar fields, as well as their meaning.  For example,
+ * the first month of the calendar system has value <code>MONTH ==
+ * JANUARY</code> for all calendars.  Other values are defined by the
+ * concrete subclass, such as <code>ERA</code>.  See individual field
+ * documentation and subclass documentation for details.
+ *
+ * <h3>Getting and Setting Calendar Field Values</h3>
+ *
+ * <p>The calendar field values can be set by calling the <code>set</code>
+ * methods. Any field values set in a <code>Calendar</code> will not be
+ * interpreted until it needs to calculate its time value (milliseconds from
+ * the Epoch) or values of the calendar fields. Calling the
+ * <code>get</code>, <code>getTimeInMillis</code>, <code>getTime</code>,
+ * <code>add</code> and <code>roll</code> involves such calculation.
+ *
+ * <h4>Leniency</h4>
+ *
+ * <p><code>Calendar</code> has two modes for interpreting the calendar
+ * fields, <em>lenient</em> and <em>non-lenient</em>.  When a
+ * <code>Calendar</code> is in lenient mode, it accepts a wider range of
+ * calendar field values than it produces.  When a <code>Calendar</code>
+ * recomputes calendar field values for return by <code>get()</code>, all of
+ * the calendar fields are normalized. For example, a lenient
+ * <code>GregorianCalendar</code> interprets <code>MONTH == JANUARY</code>,
+ * <code>DAY_OF_MONTH == 32</code> as February 1.
+
+ * <p>When a <code>Calendar</code> is in non-lenient mode, it throws an
+ * exception if there is any inconsistency in its calendar fields. For
+ * example, a <code>GregorianCalendar</code> always produces
+ * <code>DAY_OF_MONTH</code> values between 1 and the length of the month. A
+ * non-lenient <code>GregorianCalendar</code> throws an exception upon
+ * calculating its time or calendar field values if any out-of-range field
+ * value has been set.
+ *
+ * <h4><a name="first_week">First Week</a></h4>
+ *
+ * <code>Calendar</code> defines a locale-specific seven day week using two
+ * parameters: the first day of the week and the minimal days in first week
+ * (from 1 to 7).  These numbers are taken from the locale resource data when a
+ * <code>Calendar</code> is constructed.  They may also be specified explicitly
+ * through the methods for setting their values.
+ *
+ * <p>When setting or getting the <code>WEEK_OF_MONTH</code> or
+ * <code>WEEK_OF_YEAR</code> fields, <code>Calendar</code> must determine the
+ * first week of the month or year as a reference point.  The first week of a
+ * month or year is defined as the earliest seven day period beginning on
+ * <code>getFirstDayOfWeek()</code> and containing at least
+ * <code>getMinimalDaysInFirstWeek()</code> days of that month or year.  Weeks
+ * numbered ..., -1, 0 precede the first week; weeks numbered 2, 3,... follow
+ * it.  Note that the normalized numbering returned by <code>get()</code> may be
+ * different.  For example, a specific <code>Calendar</code> subclass may
+ * designate the week before week 1 of a year as week <code><i>n</i></code> of
+ * the previous year.
+ *
+ * <h4>Calendar Fields Resolution</h4>
+ *
+ * When computing a date and time from the calendar fields, there
+ * may be insufficient information for the computation (such as only
+ * year and month with no day of month), or there may be inconsistent
+ * information (such as Tuesday, July 15, 1996 (Gregorian) -- July 15,
+ * 1996 is actually a Monday). <code>Calendar</code> will resolve
+ * calendar field values to determine the date and time in the
+ * following way.
+ *
+ * <p><a name="resolution">If there is any conflict in calendar field values,
+ * <code>Calendar</code> gives priorities to calendar fields that have been set
+ * more recently.</a> The following are the default combinations of the
+ * calendar fields. The most recent combination, as determined by the
+ * most recently set single field, will be used.
+ *
+ * <p><a name="date_resolution">For the date fields</a>:
+ * <blockquote>
+ * <pre>
+ * YEAR + MONTH + DAY_OF_MONTH
+ * YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
+ * YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
+ * YEAR + DAY_OF_YEAR
+ * YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
+ * </pre></blockquote>
+ *
+ * <a name="time_resolution">For the time of day fields</a>:
+ * <blockquote>
+ * <pre>
+ * HOUR_OF_DAY
+ * AM_PM + HOUR
+ * </pre></blockquote>
+ *
+ * <p>If there are any calendar fields whose values haven't been set in the selected
+ * field combination, <code>Calendar</code> uses their default values. The default
+ * value of each field may vary by concrete calendar systems. For example, in
+ * <code>GregorianCalendar</code>, the default of a field is the same as that
+ * of the start of the Epoch: i.e., <code>YEAR = 1970</code>, <code>MONTH =
+ * JANUARY</code>, <code>DAY_OF_MONTH = 1</code>, etc.
+ *
+ * <p>
+ * <strong>Note:</strong> There are certain possible ambiguities in
+ * interpretation of certain singular times, which are resolved in the
+ * following ways:
+ * <ol>
+ *     <li> 23:59 is the last minute of the day and 00:00 is the first
+ *          minute of the next day. Thus, 23:59 on Dec 31, 1999 &lt; 00:00 on
+ *          Jan 1, 2000 &lt; 00:01 on Jan 1, 2000.
+ *
+ *     <li> Although historically not precise, midnight also belongs to "am",
+ *          and noon belongs to "pm", so on the same day,
+ *          12:00 am (midnight) &lt; 12:01 am, and 12:00 pm (noon) &lt; 12:01 pm
+ * </ol>
+ *
+ * <p>
+ * The date or time format strings are not part of the definition of a
+ * calendar, as those must be modifiable or overridable by the user at
+ * runtime. Use {@link DateFormat}
+ * to format dates.
+ *
+ * <h4>Field Manipulation</h4>
+ *
+ * The calendar fields can be changed using three methods:
+ * <code>set()</code>, <code>add()</code>, and <code>roll()</code>.
+ *
+ * <p><strong><code>set(f, value)</code></strong> changes calendar field
+ * <code>f</code> to <code>value</code>.  In addition, it sets an
+ * internal member variable to indicate that calendar field <code>f</code> has
+ * been changed. Although calendar field <code>f</code> is changed immediately,
+ * the calendar's time value in milliseconds is not recomputed until the next call to
+ * <code>get()</code>, <code>getTime()</code>, <code>getTimeInMillis()</code>,
+ * <code>add()</code>, or <code>roll()</code> is made. Thus, multiple calls to
+ * <code>set()</code> do not trigger multiple, unnecessary
+ * computations. As a result of changing a calendar field using
+ * <code>set()</code>, other calendar fields may also change, depending on the
+ * calendar field, the calendar field value, and the calendar system. In addition,
+ * <code>get(f)</code> will not necessarily return <code>value</code> set by
+ * the call to the <code>set</code> method
+ * after the calendar fields have been recomputed. The specifics are determined by
+ * the concrete calendar class.</p>
+ *
+ * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
+ * originally set to August 31, 1999. Calling <code>set(Calendar.MONTH,
+ * Calendar.SEPTEMBER)</code> sets the date to September 31,
+ * 1999. This is a temporary internal representation that resolves to
+ * October 1, 1999 if <code>getTime()</code>is then called. However, a
+ * call to <code>set(Calendar.DAY_OF_MONTH, 30)</code> before the call to
+ * <code>getTime()</code> sets the date to September 30, 1999, since
+ * no recomputation occurs after <code>set()</code> itself.</p>
+ *
+ * <p><strong><code>add(f, delta)</code></strong> adds <code>delta</code>
+ * to field <code>f</code>.  This is equivalent to calling <code>set(f,
+ * get(f) + delta)</code> with two adjustments:</p>
+ *
+ * <blockquote>
+ *   <p><strong>Add rule 1</strong>. The value of field <code>f</code>
+ *   after the call minus the value of field <code>f</code> before the
+ *   call is <code>delta</code>, modulo any overflow that has occurred in
+ *   field <code>f</code>. Overflow occurs when a field value exceeds its
+ *   range and, as a result, the next larger field is incremented or
+ *   decremented and the field value is adjusted back into its range.</p>
+ *
+ *   <p><strong>Add rule 2</strong>. If a smaller field is expected to be
+ *   invariant, but it is impossible for it to be equal to its
+ *   prior value because of changes in its minimum or maximum after field
+ *   <code>f</code> is changed or other constraints, such as time zone
+ *   offset changes, then its value is adjusted to be as close
+ *   as possible to its expected value. A smaller field represents a
+ *   smaller unit of time. <code>HOUR</code> is a smaller field than
+ *   <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
+ *   that are not expected to be invariant. The calendar system
+ *   determines what fields are expected to be invariant.</p>
+ * </blockquote>
+ *
+ * <p>In addition, unlike <code>set()</code>, <code>add()</code> forces
+ * an immediate recomputation of the calendar's milliseconds and all
+ * fields.</p>
+ *
+ * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
+ * originally set to August 31, 1999. Calling <code>add(Calendar.MONTH,
+ * 13)</code> sets the calendar to September 30, 2000. <strong>Add rule
+ * 1</strong> sets the <code>MONTH</code> field to September, since
+ * adding 13 months to August gives September of the next year. Since
+ * <code>DAY_OF_MONTH</code> cannot be 31 in September in a
+ * <code>GregorianCalendar</code>, <strong>add rule 2</strong> sets the
+ * <code>DAY_OF_MONTH</code> to 30, the closest possible value. Although
+ * it is a smaller field, <code>DAY_OF_WEEK</code> is not adjusted by
+ * rule 2, since it is expected to change when the month changes in a
+ * <code>GregorianCalendar</code>.</p>
+ *
+ * <p><strong><code>roll(f, delta)</code></strong> adds
+ * <code>delta</code> to field <code>f</code> without changing larger
+ * fields. This is equivalent to calling <code>add(f, delta)</code> with
+ * the following adjustment:</p>
+ *
+ * <blockquote>
+ *   <p><strong>Roll rule</strong>. Larger fields are unchanged after the
+ *   call. A larger field represents a larger unit of
+ *   time. <code>DAY_OF_MONTH</code> is a larger field than
+ *   <code>HOUR</code>.</p>
+ * </blockquote>
+ *
+ * <p><em>Example</em>: See {@link java.util.GregorianCalendar#roll(int, int)}.
+ *
+ * <p><strong>Usage model</strong>. To motivate the behavior of
+ * <code>add()</code> and <code>roll()</code>, consider a user interface
+ * component with increment and decrement buttons for the month, day, and
+ * year, and an underlying <code>GregorianCalendar</code>. If the
+ * interface reads January 31, 1999 and the user presses the month
+ * increment button, what should it read? If the underlying
+ * implementation uses <code>set()</code>, it might read March 3, 1999. A
+ * better result would be February 28, 1999. Furthermore, if the user
+ * presses the month increment button again, it should read March 31,
+ * 1999, not March 28, 1999. By saving the original date and using either
+ * <code>add()</code> or <code>roll()</code>, depending on whether larger
+ * fields should be affected, the user interface can behave as most users
+ * will intuitively expect.</p>
+ *
+ * @see          java.lang.System#currentTimeMillis()
+ * @see          Date
+ * @see          GregorianCalendar
+ * @see          TimeZone
+ * @see          java.text.DateFormat
+ * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
+ * @since JDK1.1
+ */
+public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
+
+    // Data flow in Calendar
+    // ---------------------
+
+    // The current time is represented in two ways by Calendar: as UTC
+    // milliseconds from the epoch (1 January 1970 0:00 UTC), and as local
+    // fields such as MONTH, HOUR, AM_PM, etc.  It is possible to compute the
+    // millis from the fields, and vice versa.  The data needed to do this
+    // conversion is encapsulated by a TimeZone object owned by the Calendar.
+    // The data provided by the TimeZone object may also be overridden if the
+    // user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class
+    // keeps track of what information was most recently set by the caller, and
+    // uses that to compute any other information as needed.
+
+    // If the user sets the fields using set(), the data flow is as follows.
+    // This is implemented by the Calendar subclass's computeTime() method.
+    // During this process, certain fields may be ignored.  The disambiguation
+    // algorithm for resolving which fields to pay attention to is described
+    // in the class documentation.
+
+    //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
+    //           |
+    //           | Using Calendar-specific algorithm
+    //           V
+    //   local standard millis
+    //           |
+    //           | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET
+    //           V
+    //   UTC millis (in time data member)
+
+    // If the user sets the UTC millis using setTime() or setTimeInMillis(),
+    // the data flow is as follows.  This is implemented by the Calendar
+    // subclass's computeFields() method.
+
+    //   UTC millis (in time data member)
+    //           |
+    //           | Using TimeZone getOffset()
+    //           V
+    //   local standard millis
+    //           |
+    //           | Using Calendar-specific algorithm
+    //           V
+    //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
+
+    // In general, a round trip from fields, through local and UTC millis, and
+    // back out to fields is made when necessary.  This is implemented by the
+    // complete() method.  Resolving a partial set of fields into a UTC millis
+    // value allows all remaining fields to be generated from that value.  If
+    // the Calendar is lenient, the fields are also renormalized to standard
+    // ranges when they are regenerated.
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * era, e.g., AD or BC in the Julian calendar. This is a calendar-specific
+     * value; see subclass documentation.
+     *
+     * @see GregorianCalendar#AD
+     * @see GregorianCalendar#BC
+     */
+    public final static int ERA = 0;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * year. This is a calendar-specific value; see subclass documentation.
+     */
+    public final static int YEAR = 1;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * month. This is a calendar-specific value. The first month of
+     * the year in the Gregorian and Julian calendars is
+     * <code>JANUARY</code> which is 0; the last depends on the number
+     * of months in a year.
+     *
+     * @see #JANUARY
+     * @see #FEBRUARY
+     * @see #MARCH
+     * @see #APRIL
+     * @see #MAY
+     * @see #JUNE
+     * @see #JULY
+     * @see #AUGUST
+     * @see #SEPTEMBER
+     * @see #OCTOBER
+     * @see #NOVEMBER
+     * @see #DECEMBER
+     * @see #UNDECIMBER
+     */
+    public final static int MONTH = 2;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * week number within the current year.  The first week of the year, as
+     * defined by <code>getFirstDayOfWeek()</code> and
+     * <code>getMinimalDaysInFirstWeek()</code>, has value 1.  Subclasses define
+     * the value of <code>WEEK_OF_YEAR</code> for days before the first week of
+     * the year.
+     *
+     * @see #getFirstDayOfWeek
+     * @see #getMinimalDaysInFirstWeek
+     */
+    public final static int WEEK_OF_YEAR = 3;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * week number within the current month.  The first week of the month, as
+     * defined by <code>getFirstDayOfWeek()</code> and
+     * <code>getMinimalDaysInFirstWeek()</code>, has value 1.  Subclasses define
+     * the value of <code>WEEK_OF_MONTH</code> for days before the first week of
+     * the month.
+     *
+     * @see #getFirstDayOfWeek
+     * @see #getMinimalDaysInFirstWeek
+     */
+    public final static int WEEK_OF_MONTH = 4;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * day of the month. This is a synonym for <code>DAY_OF_MONTH</code>.
+     * The first day of the month has value 1.
+     *
+     * @see #DAY_OF_MONTH
+     */
+    public final static int DATE = 5;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * day of the month. This is a synonym for <code>DATE</code>.
+     * The first day of the month has value 1.
+     *
+     * @see #DATE
+     */
+    public final static int DAY_OF_MONTH = 5;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the day
+     * number within the current year.  The first day of the year has value 1.
+     */
+    public final static int DAY_OF_YEAR = 6;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the day
+     * of the week.  This field takes values <code>SUNDAY</code>,
+     * <code>MONDAY</code>, <code>TUESDAY</code>, <code>WEDNESDAY</code>,
+     * <code>THURSDAY</code>, <code>FRIDAY</code>, and <code>SATURDAY</code>.
+     *
+     * @see #SUNDAY
+     * @see #MONDAY
+     * @see #TUESDAY
+     * @see #WEDNESDAY
+     * @see #THURSDAY
+     * @see #FRIDAY
+     * @see #SATURDAY
+     */
+    public final static int DAY_OF_WEEK = 7;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * ordinal number of the day of the week within the current month. Together
+     * with the <code>DAY_OF_WEEK</code> field, this uniquely specifies a day
+     * within a month.  Unlike <code>WEEK_OF_MONTH</code> and
+     * <code>WEEK_OF_YEAR</code>, this field's value does <em>not</em> depend on
+     * <code>getFirstDayOfWeek()</code> or
+     * <code>getMinimalDaysInFirstWeek()</code>.  <code>DAY_OF_MONTH 1</code>
+     * through <code>7</code> always correspond to <code>DAY_OF_WEEK_IN_MONTH
+     * 1</code>; <code>8</code> through <code>14</code> correspond to
+     * <code>DAY_OF_WEEK_IN_MONTH 2</code>, and so on.
+     * <code>DAY_OF_WEEK_IN_MONTH 0</code> indicates the week before
+     * <code>DAY_OF_WEEK_IN_MONTH 1</code>.  Negative values count back from the
+     * end of the month, so the last Sunday of a month is specified as
+     * <code>DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1</code>.  Because
+     * negative values count backward they will usually be aligned differently
+     * within the month than positive values.  For example, if a month has 31
+     * days, <code>DAY_OF_WEEK_IN_MONTH -1</code> will overlap
+     * <code>DAY_OF_WEEK_IN_MONTH 5</code> and the end of <code>4</code>.
+     *
+     * @see #DAY_OF_WEEK
+     * @see #WEEK_OF_MONTH
+     */
+    public final static int DAY_OF_WEEK_IN_MONTH = 8;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating
+     * whether the <code>HOUR</code> is before or after noon.
+     * E.g., at 10:04:15.250 PM the <code>AM_PM</code> is <code>PM</code>.
+     *
+     * @see #AM
+     * @see #PM
+     * @see #HOUR
+     */
+    public final static int AM_PM = 9;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * hour of the morning or afternoon. <code>HOUR</code> is used for the
+     * 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12.
+     * E.g., at 10:04:15.250 PM the <code>HOUR</code> is 10.
+     *
+     * @see #AM_PM
+     * @see #HOUR_OF_DAY
+     */
+    public final static int HOUR = 10;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * hour of the day. <code>HOUR_OF_DAY</code> is used for the 24-hour clock.
+     * E.g., at 10:04:15.250 PM the <code>HOUR_OF_DAY</code> is 22.
+     *
+     * @see #HOUR
+     */
+    public final static int HOUR_OF_DAY = 11;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * minute within the hour.
+     * E.g., at 10:04:15.250 PM the <code>MINUTE</code> is 4.
+     */
+    public final static int MINUTE = 12;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * second within the minute.
+     * E.g., at 10:04:15.250 PM the <code>SECOND</code> is 15.
+     */
+    public final static int SECOND = 13;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * millisecond within the second.
+     * E.g., at 10:04:15.250 PM the <code>MILLISECOND</code> is 250.
+     */
+    public final static int MILLISECOND = 14;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code>
+     * indicating the raw offset from GMT in milliseconds.
+     * <p>
+     * This field reflects the correct GMT offset value of the time
+     * zone of this <code>Calendar</code> if the
+     * <code>TimeZone</code> implementation subclass supports
+     * historical GMT offset changes.
+     */
+    public final static int ZONE_OFFSET = 15;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * daylight saving offset in milliseconds.
+     * <p>
+     * This field reflects the correct daylight saving offset value of
+     * the time zone of this <code>Calendar</code> if the
+     * <code>TimeZone</code> implementation subclass supports
+     * historical Daylight Saving Time schedule changes.
+     */
+    public final static int DST_OFFSET = 16;
+
+    /**
+     * The number of distinct fields recognized by <code>get</code> and <code>set</code>.
+     * Field numbers range from <code>0..FIELD_COUNT-1</code>.
+     */
+    public final static int FIELD_COUNT = 17;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Sunday.
+     */
+    public final static int SUNDAY = 1;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Monday.
+     */
+    public final static int MONDAY = 2;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Tuesday.
+     */
+    public final static int TUESDAY = 3;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Wednesday.
+     */
+    public final static int WEDNESDAY = 4;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Thursday.
+     */
+    public final static int THURSDAY = 5;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Friday.
+     */
+    public final static int FRIDAY = 6;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Saturday.
+     */
+    public final static int SATURDAY = 7;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * first month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int JANUARY = 0;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * second month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int FEBRUARY = 1;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * third month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int MARCH = 2;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * fourth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int APRIL = 3;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * fifth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int MAY = 4;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * sixth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int JUNE = 5;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * seventh month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int JULY = 6;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * eighth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int AUGUST = 7;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * ninth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int SEPTEMBER = 8;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * tenth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int OCTOBER = 9;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * eleventh month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int NOVEMBER = 10;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * twelfth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int DECEMBER = 11;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * thirteenth month of the year. Although <code>GregorianCalendar</code>
+     * does not use this value, lunar calendars do.
+     */
+    public final static int UNDECIMBER = 12;
+
+    /**
+     * Value of the {@link #AM_PM} field indicating the
+     * period of the day from midnight to just before noon.
+     */
+    public final static int AM = 0;
+
+    /**
+     * Value of the {@link #AM_PM} field indicating the
+     * period of the day from noon to just before midnight.
+     */
+    public final static int PM = 1;
+
+    /**
+     * A style specifier for {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating names in all styles, such as
+     * "January" and "Jan".
+     *
+     * @see #SHORT_FORMAT
+     * @see #LONG_FORMAT
+     * @see #SHORT_STANDALONE
+     * @see #LONG_STANDALONE
+     * @see #SHORT
+     * @see #LONG
+     * @since 1.6
+     */
+    public static final int ALL_STYLES = 0;
+
+    static final int STANDALONE_MASK = 0x8000;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} equivalent to {@link #SHORT_FORMAT}.
+     *
+     * @see #SHORT_STANDALONE
+     * @see #LONG
+     * @since 1.6
+     */
+    public static final int SHORT = 1;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} equivalent to {@link #LONG_FORMAT}.
+     *
+     * @see #LONG_STANDALONE
+     * @see #SHORT
+     * @since 1.6
+     */
+    public static final int LONG = 2;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a narrow name used for format. Narrow names
+     * are typically single character strings, such as "M" for Monday.
+     *
+     * @see #NARROW_STANDALONE
+     * @see #SHORT_FORMAT
+     * @see #LONG_FORMAT
+     * @since 1.8
+     */
+    public static final int NARROW_FORMAT = 4;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a narrow name independently. Narrow names
+     * are typically single character strings, such as "M" for Monday.
+     *
+     * @see #NARROW_FORMAT
+     * @see #SHORT_STANDALONE
+     * @see #LONG_STANDALONE
+     * @since 1.8
+     */
+    public static final int NARROW_STANDALONE = NARROW_FORMAT | STANDALONE_MASK;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a short name used for format.
+     *
+     * @see #SHORT_STANDALONE
+     * @see #LONG_FORMAT
+     * @see #LONG_STANDALONE
+     * @since 1.8
+     */
+    public static final int SHORT_FORMAT = 1;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a long name used for format.
+     *
+     * @see #LONG_STANDALONE
+     * @see #SHORT_FORMAT
+     * @see #SHORT_STANDALONE
+     * @since 1.8
+     */
+    public static final int LONG_FORMAT = 2;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a short name used independently,
+     * such as a month abbreviation as calendar headers.
+     *
+     * @see #SHORT_FORMAT
+     * @see #LONG_FORMAT
+     * @see #LONG_STANDALONE
+     * @since 1.8
+     */
+    public static final int SHORT_STANDALONE = SHORT | STANDALONE_MASK;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a long name used independently,
+     * such as a month name as calendar headers.
+     *
+     * @see #LONG_FORMAT
+     * @see #SHORT_FORMAT
+     * @see #SHORT_STANDALONE
+     * @since 1.8
+     */
+    public static final int LONG_STANDALONE = LONG | STANDALONE_MASK;
+
+    // Internal notes:
+    // Calendar contains two kinds of time representations: current "time" in
+    // milliseconds, and a set of calendar "fields" representing the current time.
+    // The two representations are usually in sync, but can get out of sync
+    // as follows.
+    // 1. Initially, no fields are set, and the time is invalid.
+    // 2. If the time is set, all fields are computed and in sync.
+    // 3. If a single field is set, the time is invalid.
+    // Recomputation of the time and fields happens when the object needs
+    // to return a result to the user, or use a result for a computation.
+
+    /**
+     * The calendar field values for the currently set time for this calendar.
+     * This is an array of <code>FIELD_COUNT</code> integers, with index values
+     * <code>ERA</code> through <code>DST_OFFSET</code>.
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected int           fields[];
+
+    /**
+     * The flags which tell if a specified calendar field for the calendar is set.
+     * A new object has no fields set.  After the first call to a method
+     * which generates the fields, they all remain set after that.
+     * This is an array of <code>FIELD_COUNT</code> booleans, with index values
+     * <code>ERA</code> through <code>DST_OFFSET</code>.
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected boolean       isSet[];
+
+    /**
+     * Pseudo-time-stamps which specify when each field was set. There
+     * are two special values, UNSET and COMPUTED. Values from
+     * MINIMUM_USER_SET to Integer.MAX_VALUE are legal user set values.
+     */
+    transient private int   stamp[];
+
+    /**
+     * The currently set time for this calendar, expressed in milliseconds after
+     * January 1, 1970, 0:00:00 GMT.
+     * @see #isTimeSet
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected long          time;
+
+    /**
+     * True if then the value of <code>time</code> is valid.
+     * The time is made invalid by a change to an item of <code>field[]</code>.
+     * @see #time
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected boolean       isTimeSet;
+
+    /**
+     * True if <code>fields[]</code> are in sync with the currently set time.
+     * If false, then the next attempt to get the value of a field will
+     * force a recomputation of all fields from the current value of
+     * <code>time</code>.
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected boolean       areFieldsSet;
+
+    /**
+     * True if all fields have been set.
+     * @serial
+     */
+    transient boolean       areAllFieldsSet;
+
+    /**
+     * <code>True</code> if this calendar allows out-of-range field values during computation
+     * of <code>time</code> from <code>fields[]</code>.
+     * @see #setLenient
+     * @see #isLenient
+     * @serial
+     */
+    private boolean         lenient = true;
+
+    /**
+     * The <code>TimeZone</code> used by this calendar. <code>Calendar</code>
+     * uses the time zone data to translate between locale and GMT time.
+     * @serial
+     */
+    private TimeZone        zone;
+
+    /**
+     * <code>True</code> if zone references to a shared TimeZone object.
+     */
+    transient private boolean sharedZone = false;
+
+    /**
+     * The first day of the week, with possible values <code>SUNDAY</code>,
+     * <code>MONDAY</code>, etc.  This is a locale-dependent value.
+     * @serial
+     */
+    private int             firstDayOfWeek;
+
+    /**
+     * The number of days required for the first week in a month or year,
+     * with possible values from 1 to 7.  This is a locale-dependent value.
+     * @serial
+     */
+    private int             minimalDaysInFirstWeek;
+
+    /**
+     * Cache to hold the firstDayOfWeek and minimalDaysInFirstWeek
+     * of a Locale.
+     */
+    private static final ConcurrentMap<Locale, int[]> cachedLocaleData
+        = new ConcurrentHashMap<>(3);
+
+    // Special values of stamp[]
+    /**
+     * The corresponding fields[] has no value.
+     */
+    private static final int        UNSET = 0;
+
+    /**
+     * The value of the corresponding fields[] has been calculated internally.
+     */
+    private static final int        COMPUTED = 1;
+
+    /**
+     * The value of the corresponding fields[] has been set externally. Stamp
+     * values which are greater than 1 represents the (pseudo) time when the
+     * corresponding fields[] value was set.
+     */
+    private static final int        MINIMUM_USER_STAMP = 2;
+
+    /**
+     * The mask value that represents all of the fields.
+     */
+    static final int ALL_FIELDS = (1 << FIELD_COUNT) - 1;
+
+    /**
+     * The next available value for <code>stamp[]</code>, an internal array.
+     * This actually should not be written out to the stream, and will probably
+     * be removed from the stream in the near future.  In the meantime,
+     * a value of <code>MINIMUM_USER_STAMP</code> should be used.
+     * @serial
+     */
+    private int             nextStamp = MINIMUM_USER_STAMP;
+
+    // the internal serial version which says which version was written
+    // - 0 (default) for version up to JDK 1.1.5
+    // - 1 for version from JDK 1.1.6, which writes a correct 'time' value
+    //     as well as compatible values for other fields.  This is a
+    //     transitional format.
+    // - 2 (not implemented yet) a future version, in which fields[],
+    //     areFieldsSet, and isTimeSet become transient, and isSet[] is
+    //     removed. In JDK 1.1.6 we write a format compatible with version 2.
+    static final int        currentSerialVersion = 1;
+
+    /**
+     * The version of the serialized data on the stream.  Possible values:
+     * <dl>
+     * <dt><b>0</b> or not present on stream</dt>
+     * <dd>
+     * JDK 1.1.5 or earlier.
+     * </dd>
+     * <dt><b>1</b></dt>
+     * <dd>
+     * JDK 1.1.6 or later.  Writes a correct 'time' value
+     * as well as compatible values for other fields.  This is a
+     * transitional format.
+     * </dd>
+     * </dl>
+     * When streaming out this class, the most recent format
+     * and the highest allowable <code>serialVersionOnStream</code>
+     * is written.
+     * @serial
+     * @since JDK1.1.6
+     */
+    private int             serialVersionOnStream = currentSerialVersion;
+
+    // Proclaim serialization compatibility with JDK 1.1
+    static final long       serialVersionUID = -1807547505821590642L;
+
+    // Mask values for calendar fields
+    @SuppressWarnings("PointlessBitwiseExpression")
+    final static int ERA_MASK           = (1 << ERA);
+    final static int YEAR_MASK          = (1 << YEAR);
+    final static int MONTH_MASK         = (1 << MONTH);
+    final static int WEEK_OF_YEAR_MASK  = (1 << WEEK_OF_YEAR);
+    final static int WEEK_OF_MONTH_MASK = (1 << WEEK_OF_MONTH);
+    final static int DAY_OF_MONTH_MASK  = (1 << DAY_OF_MONTH);
+    final static int DATE_MASK          = DAY_OF_MONTH_MASK;
+    final static int DAY_OF_YEAR_MASK   = (1 << DAY_OF_YEAR);
+    final static int DAY_OF_WEEK_MASK   = (1 << DAY_OF_WEEK);
+    final static int DAY_OF_WEEK_IN_MONTH_MASK  = (1 << DAY_OF_WEEK_IN_MONTH);
+    final static int AM_PM_MASK         = (1 << AM_PM);
+    final static int HOUR_MASK          = (1 << HOUR);
+    final static int HOUR_OF_DAY_MASK   = (1 << HOUR_OF_DAY);
+    final static int MINUTE_MASK        = (1 << MINUTE);
+    final static int SECOND_MASK        = (1 << SECOND);
+    final static int MILLISECOND_MASK   = (1 << MILLISECOND);
+    final static int ZONE_OFFSET_MASK   = (1 << ZONE_OFFSET);
+    final static int DST_OFFSET_MASK    = (1 << DST_OFFSET);
+
+    /**
+     * {@code Calendar.Builder} is used for creating a {@code Calendar} from
+     * various date-time parameters.
+     *
+     * <p>There are two ways to set a {@code Calendar} to a date-time value. One
+     * is to set the instant parameter to a millisecond offset from the <a
+     * href="Calendar.html#Epoch">Epoch</a>. The other is to set individual
+     * field parameters, such as {@link Calendar#YEAR YEAR}, to their desired
+     * values. These two ways can't be mixed. Trying to set both the instant and
+     * individual fields will cause an {@link IllegalStateException} to be
+     * thrown. However, it is permitted to override previous values of the
+     * instant or field parameters.
+     *
+     * <p>If no enough field parameters are given for determining date and/or
+     * time, calendar specific default values are used when building a
+     * {@code Calendar}. For example, if the {@link Calendar#YEAR YEAR} value
+     * isn't given for the Gregorian calendar, 1970 will be used. If there are
+     * any conflicts among field parameters, the <a
+     * href="Calendar.html#resolution"> resolution rules</a> are applied.
+     * Therefore, the order of field setting matters.
+     *
+     * <p>In addition to the date-time parameters,
+     * the {@linkplain #setLocale(Locale) locale},
+     * {@linkplain #setTimeZone(TimeZone) time zone},
+     * {@linkplain #setWeekDefinition(int, int) week definition}, and
+     * {@linkplain #setLenient(boolean) leniency mode} parameters can be set.
+     *
+     * <p><b>Examples</b>
+     * <p>The following are sample usages. Sample code assumes that the
+     * {@code Calendar} constants are statically imported.
+     *
+     * <p>The following code produces a {@code Calendar} with date 2012-12-31
+     * (Gregorian) because Monday is the first day of a week with the <a
+     * href="GregorianCalendar.html#iso8601_compatible_setting"> ISO 8601
+     * compatible week parameters</a>.
+     * <pre>
+     *   Calendar cal = new Calendar.Builder().setCalendarType("iso8601")
+     *                        .setWeekDate(2013, 1, MONDAY).build();</pre>
+     * <p>The following code produces a Japanese {@code Calendar} with date
+     * 1989-01-08 (Gregorian), assuming that the default {@link Calendar#ERA ERA}
+     * is <em>Heisei</em> that started on that day.
+     * <pre>
+     *   Calendar cal = new Calendar.Builder().setCalendarType("japanese")
+     *                        .setFields(YEAR, 1, DAY_OF_YEAR, 1).build();</pre>
+     *
+     * @since 1.8
+     * @see Calendar#getInstance(TimeZone, Locale)
+     * @see Calendar#fields
+     */
+    public static class Builder {
+        private static final int NFIELDS = FIELD_COUNT + 1; // +1 for WEEK_YEAR
+        private static final int WEEK_YEAR = FIELD_COUNT;
+
+        private long instant;
+        // Calendar.stamp[] (lower half) and Calendar.fields[] (upper half) combined
+        private int[] fields;
+        // Pseudo timestamp starting from MINIMUM_USER_STAMP.
+        // (COMPUTED is used to indicate that the instant has been set.)
+        private int nextStamp;
+        // maxFieldIndex keeps the max index of fields which have been set.
+        // (WEEK_YEAR is never included.)
+        private int maxFieldIndex;
+        private String type;
+        private TimeZone zone;
+        private boolean lenient = true;
+        private Locale locale;
+        private int firstDayOfWeek, minimalDaysInFirstWeek;
+
+        /**
+         * Constructs a {@code Calendar.Builder}.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Sets the instant parameter to the given {@code instant} value that is
+         * a millisecond offset from <a href="Calendar.html#Epoch">the
+         * Epoch</a>.
+         *
+         * @param instant a millisecond offset from the Epoch
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalStateException if any of the field parameters have
+         *                               already been set
+         * @see Calendar#setTime(Date)
+         * @see Calendar#setTimeInMillis(long)
+         * @see Calendar#time
+         */
+        public Builder setInstant(long instant) {
+            if (fields != null) {
+                throw new IllegalStateException();
+            }
+            this.instant = instant;
+            nextStamp = COMPUTED;
+            return this;
+        }
+
+        /**
+         * Sets the instant parameter to the {@code instant} value given by a
+         * {@link Date}. This method is equivalent to a call to
+         * {@link #setInstant(long) setInstant(instant.getTime())}.
+         *
+         * @param instant a {@code Date} representing a millisecond offset from
+         *                the Epoch
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException  if {@code instant} is {@code null}
+         * @throws IllegalStateException if any of the field parameters have
+         *                               already been set
+         * @see Calendar#setTime(Date)
+         * @see Calendar#setTimeInMillis(long)
+         * @see Calendar#time
+         */
+        public Builder setInstant(Date instant) {
+            return setInstant(instant.getTime()); // NPE if instant == null
+        }
+
+        /**
+         * Sets the {@code field} parameter to the given {@code value}.
+         * {@code field} is an index to the {@link Calendar#fields}, such as
+         * {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH}. Field value validation is
+         * not performed in this method. Any out of range values are either
+         * normalized in lenient mode or detected as an invalid value in
+         * non-lenient mode when building a {@code Calendar}.
+         *
+         * @param field an index to the {@code Calendar} fields
+         * @param value the field value
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalArgumentException if {@code field} is invalid
+         * @throws IllegalStateException if the instant value has already been set,
+         *                      or if fields have been set too many
+         *                      (approximately {@link Integer#MAX_VALUE}) times.
+         * @see Calendar#set(int, int)
+         */
+        public Builder set(int field, int value) {
+            // Note: WEEK_YEAR can't be set with this method.
+            if (field < 0 || field >= FIELD_COUNT) {
+                throw new IllegalArgumentException("field is invalid");
+            }
+            if (isInstantSet()) {
+                throw new IllegalStateException("instant has been set");
+            }
+            allocateFields();
+            internalSet(field, value);
+            return this;
+        }
+
+        // Android-changed: fix typo in example code.
+        /**
+         * Sets field parameters to their values given by
+         * {@code fieldValuePairs} that are pairs of a field and its value.
+         * For example,
+         * <pre>
+         *   setFields(Calendar.YEAR, 2013,
+         *             Calendar.MONTH, Calendar.DECEMBER,
+         *             Calendar.DAY_OF_MONTH, 23);</pre>
+         * is equivalent to the sequence of the following
+         * {@link #set(int, int) set} calls:
+         * <pre>
+         *   set(Calendar.YEAR, 2013)
+         *   .set(Calendar.MONTH, Calendar.DECEMBER)
+         *   .set(Calendar.DAY_OF_MONTH, 23);</pre>
+         *
+         * @param fieldValuePairs field-value pairs
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code fieldValuePairs} is {@code null}
+         * @throws IllegalArgumentException if any of fields are invalid,
+         *             or if {@code fieldValuePairs.length} is an odd number.
+         * @throws IllegalStateException    if the instant value has been set,
+         *             or if fields have been set too many (approximately
+         *             {@link Integer#MAX_VALUE}) times.
+         */
+        public Builder setFields(int... fieldValuePairs) {
+            int len = fieldValuePairs.length;
+            if ((len % 2) != 0) {
+                throw new IllegalArgumentException();
+            }
+            if (isInstantSet()) {
+                throw new IllegalStateException("instant has been set");
+            }
+            if ((nextStamp + len / 2) < 0) {
+                throw new IllegalStateException("stamp counter overflow");
+            }
+            allocateFields();
+            for (int i = 0; i < len; ) {
+                int field = fieldValuePairs[i++];
+                // Note: WEEK_YEAR can't be set with this method.
+                if (field < 0 || field >= FIELD_COUNT) {
+                    throw new IllegalArgumentException("field is invalid");
+                }
+                internalSet(field, fieldValuePairs[i++]);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the date field parameters to the values given by {@code year},
+         * {@code month}, and {@code dayOfMonth}. This method is equivalent to
+         * a call to:
+         * <pre>
+         *   setFields(Calendar.YEAR, year,
+         *             Calendar.MONTH, month,
+         *             Calendar.DAY_OF_MONTH, dayOfMonth);</pre>
+         *
+         * @param year       the {@link Calendar#YEAR YEAR} value
+         * @param month      the {@link Calendar#MONTH MONTH} value
+         *                   (the month numbering is <em>0-based</em>).
+         * @param dayOfMonth the {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH} value
+         * @return this {@code Calendar.Builder}
+         */
+        public Builder setDate(int year, int month, int dayOfMonth) {
+            return setFields(YEAR, year, MONTH, month, DAY_OF_MONTH, dayOfMonth);
+        }
+
+        /**
+         * Sets the time of day field parameters to the values given by
+         * {@code hourOfDay}, {@code minute}, and {@code second}. This method is
+         * equivalent to a call to:
+         * <pre>
+         *   setTimeOfDay(hourOfDay, minute, second, 0);</pre>
+         *
+         * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value
+         *                  (24-hour clock)
+         * @param minute    the {@link Calendar#MINUTE MINUTE} value
+         * @param second    the {@link Calendar#SECOND SECOND} value
+         * @return this {@code Calendar.Builder}
+         */
+        public Builder setTimeOfDay(int hourOfDay, int minute, int second) {
+            return setTimeOfDay(hourOfDay, minute, second, 0);
+        }
+
+        /**
+         * Sets the time of day field parameters to the values given by
+         * {@code hourOfDay}, {@code minute}, {@code second}, and
+         * {@code millis}. This method is equivalent to a call to:
+         * <pre>
+         *   setFields(Calendar.HOUR_OF_DAY, hourOfDay,
+         *             Calendar.MINUTE, minute,
+         *             Calendar.SECOND, second,
+         *             Calendar.MILLISECOND, millis);</pre>
+         *
+         * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value
+         *                  (24-hour clock)
+         * @param minute    the {@link Calendar#MINUTE MINUTE} value
+         * @param second    the {@link Calendar#SECOND SECOND} value
+         * @param millis    the {@link Calendar#MILLISECOND MILLISECOND} value
+         * @return this {@code Calendar.Builder}
+         */
+        public Builder setTimeOfDay(int hourOfDay, int minute, int second, int millis) {
+            return setFields(HOUR_OF_DAY, hourOfDay, MINUTE, minute,
+                             SECOND, second, MILLISECOND, millis);
+        }
+
+        /**
+         * Sets the week-based date parameters to the values with the given
+         * date specifiers - week year, week of year, and day of week.
+         *
+         * <p>If the specified calendar doesn't support week dates, the
+         * {@link #build() build} method will throw an {@link IllegalArgumentException}.
+         *
+         * @param weekYear   the week year
+         * @param weekOfYear the week number based on {@code weekYear}
+         * @param dayOfWeek  the day of week value: one of the constants
+         *     for the {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} field:
+         *     {@link Calendar#SUNDAY SUNDAY}, ..., {@link Calendar#SATURDAY SATURDAY}.
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#setWeekDate(int, int, int)
+         * @see Calendar#isWeekDateSupported()
+         */
+        public Builder setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
+            allocateFields();
+            internalSet(WEEK_YEAR, weekYear);
+            internalSet(WEEK_OF_YEAR, weekOfYear);
+            internalSet(DAY_OF_WEEK, dayOfWeek);
+            return this;
+        }
+
+        /**
+         * Sets the time zone parameter to the given {@code zone}. If no time
+         * zone parameter is given to this {@code Caledar.Builder}, the
+         * {@linkplain TimeZone#getDefault() default
+         * <code>TimeZone</code>} will be used in the {@link #build() build}
+         * method.
+         *
+         * @param zone the {@link TimeZone}
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code zone} is {@code null}
+         * @see Calendar#setTimeZone(TimeZone)
+         */
+        public Builder setTimeZone(TimeZone zone) {
+            if (zone == null) {
+                throw new NullPointerException();
+            }
+            this.zone = zone;
+            return this;
+        }
+
+        /**
+         * Sets the lenient mode parameter to the value given by {@code lenient}.
+         * If no lenient parameter is given to this {@code Calendar.Builder},
+         * lenient mode will be used in the {@link #build() build} method.
+         *
+         * @param lenient {@code true} for lenient mode;
+         *                {@code false} for non-lenient mode
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#setLenient(boolean)
+         */
+        public Builder setLenient(boolean lenient) {
+            this.lenient = lenient;
+            return this;
+        }
+
+        /**
+         * Sets the calendar type parameter to the given {@code type}. The
+         * calendar type given by this method has precedence over any explicit
+         * or implicit calendar type given by the
+         * {@linkplain #setLocale(Locale) locale}.
+         *
+         * <p>In addition to the available calendar types returned by the
+         * {@link Calendar#getAvailableCalendarTypes() Calendar.getAvailableCalendarTypes}
+         * method, {@code "gregorian"} and {@code "iso8601"} as aliases of
+         * {@code "gregory"} can be used with this method.
+         *
+         * @param type the calendar type
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code type} is {@code null}
+         * @throws IllegalArgumentException if {@code type} is unknown
+         * @throws IllegalStateException if another calendar type has already been set
+         * @see Calendar#getCalendarType()
+         * @see Calendar#getAvailableCalendarTypes()
+         */
+        public Builder setCalendarType(String type) {
+            if (type.equals("gregorian")) { // NPE if type == null
+                type = "gregory";
+            }
+            if (!Calendar.getAvailableCalendarTypes().contains(type)
+                    && !type.equals("iso8601")) {
+                throw new IllegalArgumentException("unknown calendar type: " + type);
+            }
+            if (this.type == null) {
+                this.type = type;
+            } else {
+                if (!this.type.equals(type)) {
+                    throw new IllegalStateException("calendar type override");
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Sets the locale parameter to the given {@code locale}. If no locale
+         * is given to this {@code Calendar.Builder}, the {@linkplain
+         * Locale#getDefault(Locale.Category) default <code>Locale</code>}
+         * for {@link Locale.Category#FORMAT} will be used.
+         *
+         * <p>If no calendar type is explicitly given by a call to the
+         * {@link #setCalendarType(String) setCalendarType} method,
+         * the {@code Locale} value is used to determine what type of
+         * {@code Calendar} to be built.
+         *
+         * <p>If no week definition parameters are explicitly given by a call to
+         * the {@link #setWeekDefinition(int,int) setWeekDefinition} method, the
+         * {@code Locale}'s default values are used.
+         *
+         * @param locale the {@link Locale}
+         * @throws NullPointerException if {@code locale} is {@code null}
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#getInstance(Locale)
+         */
+        public Builder setLocale(Locale locale) {
+            if (locale == null) {
+                throw new NullPointerException();
+            }
+            this.locale = locale;
+            return this;
+        }
+
+        /**
+         * Sets the week definition parameters to the values given by
+         * {@code firstDayOfWeek} and {@code minimalDaysInFirstWeek} that are
+         * used to determine the <a href="Calendar.html#First_Week">first
+         * week</a> of a year. The parameters given by this method have
+         * precedence over the default values given by the
+         * {@linkplain #setLocale(Locale) locale}.
+         *
+         * @param firstDayOfWeek the first day of a week; one of
+         *                       {@link Calendar#SUNDAY} to {@link Calendar#SATURDAY}
+         * @param minimalDaysInFirstWeek the minimal number of days in the first
+         *                               week (1..7)
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalArgumentException if {@code firstDayOfWeek} or
+         *                                  {@code minimalDaysInFirstWeek} is invalid
+         * @see Calendar#getFirstDayOfWeek()
+         * @see Calendar#getMinimalDaysInFirstWeek()
+         */
+        public Builder setWeekDefinition(int firstDayOfWeek, int minimalDaysInFirstWeek) {
+            if (!isValidWeekParameter(firstDayOfWeek)
+                    || !isValidWeekParameter(minimalDaysInFirstWeek)) {
+                throw new IllegalArgumentException();
+            }
+            this.firstDayOfWeek = firstDayOfWeek;
+            this.minimalDaysInFirstWeek = minimalDaysInFirstWeek;
+            return this;
+        }
+
+        /**
+         * Returns a {@code Calendar} built from the parameters set by the
+         * setter methods. The calendar type given by the {@link #setCalendarType(String)
+         * setCalendarType} method or the {@linkplain #setLocale(Locale) locale} is
+         * used to determine what {@code Calendar} to be created. If no explicit
+         * calendar type is given, the locale's default calendar is created.
+         *
+         * <p>If the calendar type is {@code "iso8601"}, the
+         * {@linkplain GregorianCalendar#setGregorianChange(Date) Gregorian change date}
+         * of a {@link GregorianCalendar} is set to {@code Date(Long.MIN_VALUE)}
+         * to be the <em>proleptic</em> Gregorian calendar. Its week definition
+         * parameters are also set to be <a
+         * href="GregorianCalendar.html#iso8601_compatible_setting">compatible
+         * with the ISO 8601 standard</a>. Note that the
+         * {@link GregorianCalendar#getCalendarType() getCalendarType} method of
+         * a {@code GregorianCalendar} created with {@code "iso8601"} returns
+         * {@code "gregory"}.
+         *
+         * <p>The default values are used for locale and time zone if these
+         * parameters haven't been given explicitly.
+         *
+         * <p>Any out of range field values are either normalized in lenient
+         * mode or detected as an invalid value in non-lenient mode.
+         *
+         * @return a {@code Calendar} built with parameters of this {@code
+         *         Calendar.Builder}
+         * @throws IllegalArgumentException if the calendar type is unknown, or
+         *             if any invalid field values are given in non-lenient mode, or
+         *             if a week date is given for the calendar type that doesn't
+         *             support week dates.
+         * @see Calendar#getInstance(TimeZone, Locale)
+         * @see Locale#getDefault(Locale.Category)
+         * @see TimeZone#getDefault()
+         */
+        public Calendar build() {
+            if (locale == null) {
+                locale = Locale.getDefault();
+            }
+            if (zone == null) {
+                zone = TimeZone.getDefault();
+            }
+            Calendar cal;
+            if (type == null) {
+                type = locale.getUnicodeLocaleType("ca");
+            }
+            if (type == null) {
+                // BEGIN Android-changed: don't switch to buddhist calendar based on locale.
+                // See http://b/35138741
+                /*
+                if (locale.getCountry() == "TH"
+                        && locale.getLanguage() == "th") {
+                    type = "buddhist";
+                } else {
+                    type = "gregory";
+                }
+                */
+                type = "gregory";
+                // END Android-changed: don't switch to buddhist calendar based on locale.
+            }
+            switch (type) {
+            case "gregory":
+                cal = new GregorianCalendar(zone, locale, true);
+                break;
+            case "iso8601":
+                GregorianCalendar gcal = new GregorianCalendar(zone, locale, true);
+                // make gcal a proleptic Gregorian
+                gcal.setGregorianChange(new Date(Long.MIN_VALUE));
+                // and week definition to be compatible with ISO 8601
+                setWeekDefinition(MONDAY, 4);
+                cal = gcal;
+                break;
+// BEGIN Android-changed: removed support for "buddhist" and "japanese".
+//            case "buddhist":
+//                cal = new BuddhistCalendar(zone, locale);
+//                cal.clear();
+//                break;
+//            case "japanese":
+//                cal = new JapaneseImperialCalendar(zone, locale, true);
+//                break;
+// END Android-changed: removed support for "buddhist" and "japanese".
+            default:
+                throw new IllegalArgumentException("unknown calendar type: " + type);
+            }
+            cal.setLenient(lenient);
+            if (firstDayOfWeek != 0) {
+                cal.setFirstDayOfWeek(firstDayOfWeek);
+                cal.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
+            }
+            if (isInstantSet()) {
+                cal.setTimeInMillis(instant);
+                cal.complete();
+                return cal;
+            }
+
+            if (fields != null) {
+                boolean weekDate = isSet(WEEK_YEAR)
+                                       && fields[WEEK_YEAR] > fields[YEAR];
+                if (weekDate && !cal.isWeekDateSupported()) {
+                    throw new IllegalArgumentException("week date is unsupported by " + type);
+                }
+
+                // Set the fields from the min stamp to the max stamp so that
+                // the fields resolution works in the Calendar.
+                for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
+                    for (int index = 0; index <= maxFieldIndex; index++) {
+                        if (fields[index] == stamp) {
+                            cal.set(index, fields[NFIELDS + index]);
+                            break;
+                        }
+                    }
+                }
+
+                if (weekDate) {
+                    int weekOfYear = isSet(WEEK_OF_YEAR) ? fields[NFIELDS + WEEK_OF_YEAR] : 1;
+                    int dayOfWeek = isSet(DAY_OF_WEEK)
+                                    ? fields[NFIELDS + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
+                    cal.setWeekDate(fields[NFIELDS + WEEK_YEAR], weekOfYear, dayOfWeek);
+                }
+                cal.complete();
+            }
+
+            return cal;
+        }
+
+        private void allocateFields() {
+            if (fields == null) {
+                fields = new int[NFIELDS * 2];
+                nextStamp = MINIMUM_USER_STAMP;
+                maxFieldIndex = -1;
+            }
+        }
+
+        private void internalSet(int field, int value) {
+            fields[field] = nextStamp++;
+            if (nextStamp < 0) {
+                throw new IllegalStateException("stamp counter overflow");
+            }
+            fields[NFIELDS + field] = value;
+            if (field > maxFieldIndex && field < WEEK_YEAR) {
+                maxFieldIndex = field;
+            }
+        }
+
+        private boolean isInstantSet() {
+            return nextStamp == COMPUTED;
+        }
+
+        private boolean isSet(int index) {
+            return fields != null && fields[index] > UNSET;
+        }
+
+        private boolean isValidWeekParameter(int value) {
+            return value > 0 && value <= 7;
+        }
+    }
+
+    /**
+     * Constructs a Calendar with the default time zone
+     * and the default {@link java.util.Locale.Category#FORMAT FORMAT}
+     * locale.
+     * @see     TimeZone#getDefault
+     */
+    protected Calendar()
+    {
+        this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
+        sharedZone = true;
+    }
+
+    /**
+     * Constructs a calendar with the specified time zone and locale.
+     *
+     * @param zone the time zone to use
+     * @param aLocale the locale for the week data
+     */
+    protected Calendar(TimeZone zone, Locale aLocale)
+    {
+        // BEGIN Android-added: Allow aLocale == null
+        // http://b/16938922.
+        //
+        // TODO: This is for backwards compatibility only. Seems like a better idea to throw
+        // here. We should add a targetSdkVersion based check and throw for this case.
+        if (aLocale == null) {
+            aLocale = Locale.getDefault();
+        }
+        // END Android-added: Allow aLocale == null
+        fields = new int[FIELD_COUNT];
+        isSet = new boolean[FIELD_COUNT];
+        stamp = new int[FIELD_COUNT];
+
+        this.zone = zone;
+        setWeekCountData(aLocale);
+    }
+
+    /**
+     * Gets a calendar using the default time zone and locale. The
+     * <code>Calendar</code> returned is based on the current time
+     * in the default time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     *
+     * @return a Calendar.
+     */
+    public static Calendar getInstance()
+    {
+        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Gets a calendar using the specified time zone and default locale.
+     * The <code>Calendar</code> returned is based on the current time
+     * in the given time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     *
+     * @param zone the time zone to use
+     * @return a Calendar.
+     */
+    public static Calendar getInstance(TimeZone zone)
+    {
+        return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Gets a calendar using the default time zone and specified locale.
+     * The <code>Calendar</code> returned is based on the current time
+     * in the default time zone with the given locale.
+     *
+     * @param aLocale the locale for the week data
+     * @return a Calendar.
+     */
+    public static Calendar getInstance(Locale aLocale)
+    {
+        return createCalendar(TimeZone.getDefault(), aLocale);
+    }
+
+    /**
+     * Gets a calendar with the specified time zone and locale.
+     * The <code>Calendar</code> returned is based on the current time
+     * in the given time zone with the given locale.
+     *
+     * @param zone the time zone to use
+     * @param aLocale the locale for the week data
+     * @return a Calendar.
+     */
+    public static Calendar getInstance(TimeZone zone,
+                                       Locale aLocale)
+    {
+        return createCalendar(zone, aLocale);
+    }
+
+    // BEGIN Android-added: add getJapaneseImperialInstance()
+    /**
+     * Create a Japanese Imperial Calendar.
+     * @hide
+     */
+    public static Calendar getJapaneseImperialInstance(TimeZone zone, Locale aLocale) {
+        return new JapaneseImperialCalendar(zone, aLocale);
+    }
+    // END Android-added: add getJapaneseImperialInstance()
+
+    private static Calendar createCalendar(TimeZone zone,
+                                           Locale aLocale)
+    {
+        // BEGIN Android-changed: only support GregorianCalendar here
+        return new GregorianCalendar(zone, aLocale);
+        // END Android-changed: only support GregorianCalendar here
+    }
+
+    /**
+     * Returns an array of all locales for which the <code>getInstance</code>
+     * methods of this class can return localized instances.
+     * The array returned must contain at least a <code>Locale</code>
+     * instance equal to {@link java.util.Locale#US Locale.US}.
+     *
+     * @return An array of locales for which localized
+     *         <code>Calendar</code> instances are available.
+     */
+    public static synchronized Locale[] getAvailableLocales()
+    {
+        return DateFormat.getAvailableLocales();
+    }
+
+    /**
+     * Converts the current calendar field values in {@link #fields fields[]}
+     * to the millisecond time value
+     * {@link #time}.
+     *
+     * @see #complete()
+     * @see #computeFields()
+     */
+    protected abstract void computeTime();
+
+    /**
+     * Converts the current millisecond time value {@link #time}
+     * to calendar field values in {@link #fields fields[]}.
+     * This allows you to sync up the calendar field values with
+     * a new time that is set for the calendar.  The time is <em>not</em>
+     * recomputed first; to recompute the time, then the fields, call the
+     * {@link #complete()} method.
+     *
+     * @see #computeTime()
+     */
+    protected abstract void computeFields();
+
+    /**
+     * Returns a <code>Date</code> object representing this
+     * <code>Calendar</code>'s time value (millisecond offset from the <a
+     * href="#Epoch">Epoch</a>").
+     *
+     * @return a <code>Date</code> representing the time value.
+     * @see #setTime(Date)
+     * @see #getTimeInMillis()
+     */
+    public final Date getTime() {
+        return new Date(getTimeInMillis());
+    }
+
+    /**
+     * Sets this Calendar's time with the given <code>Date</code>.
+     * <p>
+     * Note: Calling <code>setTime()</code> with
+     * <code>Date(Long.MAX_VALUE)</code> or <code>Date(Long.MIN_VALUE)</code>
+     * may yield incorrect field values from <code>get()</code>.
+     *
+     * @param date the given Date.
+     * @see #getTime()
+     * @see #setTimeInMillis(long)
+     */
+    public final void setTime(Date date) {
+        setTimeInMillis(date.getTime());
+    }
+
+    /**
+     * Returns this Calendar's time value in milliseconds.
+     *
+     * @return the current time as UTC milliseconds from the epoch.
+     * @see #getTime()
+     * @see #setTimeInMillis(long)
+     */
+    public long getTimeInMillis() {
+        if (!isTimeSet) {
+            updateTime();
+        }
+        return time;
+    }
+
+    /**
+     * Sets this Calendar's current time from the given long value.
+     *
+     * @param millis the new time in UTC milliseconds from the epoch.
+     * @see #setTime(Date)
+     * @see #getTimeInMillis()
+     */
+    public void setTimeInMillis(long millis) {
+        // If we don't need to recalculate the calendar field values,
+        // do nothing.
+// BEGIN Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+//        if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
+//            && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
+        if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet) {
+// END Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+
+            return;
+        }
+        time = millis;
+        isTimeSet = true;
+        areFieldsSet = false;
+        computeFields();
+        areAllFieldsSet = areFieldsSet = true;
+    }
+
+    /**
+     * Returns the value of the given calendar field. In lenient mode,
+     * all calendar fields are normalized. In non-lenient mode, all
+     * calendar fields are validated and this method throws an
+     * exception if any calendar fields have out-of-range values. The
+     * normalization and validation are handled by the
+     * {@link #complete()} method, which process is calendar
+     * system dependent.
+     *
+     * @param field the given calendar field.
+     * @return the value for the given calendar field.
+     * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
+     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #set(int,int)
+     * @see #complete()
+     */
+    public int get(int field)
+    {
+        complete();
+        return internalGet(field);
+    }
+
+    /**
+     * Returns the value of the given calendar field. This method does
+     * not involve normalization or validation of the field value.
+     *
+     * @param field the given calendar field.
+     * @return the value for the given calendar field.
+     * @see #get(int)
+     */
+    protected final int internalGet(int field)
+    {
+        return fields[field];
+    }
+
+    /**
+     * Sets the value of the given calendar field. This method does
+     * not affect any setting state of the field in this
+     * <code>Calendar</code> instance.
+     *
+     * @throws IndexOutOfBoundsException if the specified field is out of range
+     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #areFieldsSet
+     * @see #isTimeSet
+     * @see #areAllFieldsSet
+     * @see #set(int,int)
+     */
+    final void internalSet(int field, int value)
+    {
+        fields[field] = value;
+    }
+
+    /**
+     * Sets the given calendar field to the given value. The value is not
+     * interpreted by this method regardless of the leniency mode.
+     *
+     * @param field the given calendar field.
+     * @param value the value to be set for the given calendar field.
+     * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
+     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * in non-lenient mode.
+     * @see #set(int,int,int)
+     * @see #set(int,int,int,int,int)
+     * @see #set(int,int,int,int,int,int)
+     * @see #get(int)
+     */
+    public void set(int field, int value)
+    {
+        // If the fields are partially normalized, calculate all the
+        // fields before changing any fields.
+        if (areFieldsSet && !areAllFieldsSet) {
+            computeFields();
+        }
+        internalSet(field, value);
+        isTimeSet = false;
+        areFieldsSet = false;
+        isSet[field] = true;
+        stamp[field] = nextStamp++;
+        if (nextStamp == Integer.MAX_VALUE) {
+            adjustStamp();
+        }
+    }
+
+    /**
+     * Sets the values for the calendar fields <code>YEAR</code>,
+     * <code>MONTH</code>, and <code>DAY_OF_MONTH</code>.
+     * Previous values of other calendar fields are retained.  If this is not desired,
+     * call {@link #clear()} first.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field.
+     * @param month the value used to set the <code>MONTH</code> calendar field.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
+     * @see #set(int,int)
+     * @see #set(int,int,int,int,int)
+     * @see #set(int,int,int,int,int,int)
+     */
+    public final void set(int year, int month, int date)
+    {
+        set(YEAR, year);
+        set(MONTH, month);
+        set(DATE, date);
+    }
+
+    /**
+     * Sets the values for the calendar fields <code>YEAR</code>,
+     * <code>MONTH</code>, <code>DAY_OF_MONTH</code>,
+     * <code>HOUR_OF_DAY</code>, and <code>MINUTE</code>.
+     * Previous values of other fields are retained.  If this is not desired,
+     * call {@link #clear()} first.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field.
+     * @param month the value used to set the <code>MONTH</code> calendar field.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
+     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
+     * @param minute the value used to set the <code>MINUTE</code> calendar field.
+     * @see #set(int,int)
+     * @see #set(int,int,int)
+     * @see #set(int,int,int,int,int,int)
+     */
+    public final void set(int year, int month, int date, int hourOfDay, int minute)
+    {
+        set(YEAR, year);
+        set(MONTH, month);
+        set(DATE, date);
+        set(HOUR_OF_DAY, hourOfDay);
+        set(MINUTE, minute);
+    }
+
+    /**
+     * Sets the values for the fields <code>YEAR</code>, <code>MONTH</code>,
+     * <code>DAY_OF_MONTH</code>, <code>HOUR_OF_DAY</code>, <code>MINUTE</code>, and
+     * <code>SECOND</code>.
+     * Previous values of other fields are retained.  If this is not desired,
+     * call {@link #clear()} first.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field.
+     * @param month the value used to set the <code>MONTH</code> calendar field.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
+     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
+     * @param minute the value used to set the <code>MINUTE</code> calendar field.
+     * @param second the value used to set the <code>SECOND</code> calendar field.
+     * @see #set(int,int)
+     * @see #set(int,int,int)
+     * @see #set(int,int,int,int,int)
+     */
+    public final void set(int year, int month, int date, int hourOfDay, int minute,
+                          int second)
+    {
+        set(YEAR, year);
+        set(MONTH, month);
+        set(DATE, date);
+        set(HOUR_OF_DAY, hourOfDay);
+        set(MINUTE, minute);
+        set(SECOND, second);
+    }
+
+    /**
+     * Sets all the calendar field values and the time value
+     * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
+     * this <code>Calendar</code> undefined. This means that {@link
+     * #isSet(int) isSet()} will return <code>false</code> for all the
+     * calendar fields, and the date and time calculations will treat
+     * the fields as if they had never been set. A
+     * <code>Calendar</code> implementation class may use its specific
+     * default field values for date/time calculations. For example,
+     * <code>GregorianCalendar</code> uses 1970 if the
+     * <code>YEAR</code> field value is undefined.
+     *
+     * @see #clear(int)
+     */
+    public final void clear()
+    {
+        for (int i = 0; i < fields.length; ) {
+            stamp[i] = fields[i] = 0; // UNSET == 0
+            isSet[i++] = false;
+        }
+        areAllFieldsSet = areFieldsSet = false;
+        isTimeSet = false;
+    }
+
+    /**
+     * Sets the given calendar field value and the time value
+     * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
+     * this <code>Calendar</code> undefined. This means that {@link
+     * #isSet(int) isSet(field)} will return <code>false</code>, and
+     * the date and time calculations will treat the field as if it
+     * had never been set. A <code>Calendar</code> implementation
+     * class may use the field's specific default value for date and
+     * time calculations.
+     *
+     * <p>The {@link #HOUR_OF_DAY}, {@link #HOUR} and {@link #AM_PM}
+     * fields are handled independently and the <a
+     * href="#time_resolution">the resolution rule for the time of
+     * day</a> is applied. Clearing one of the fields doesn't reset
+     * the hour of day value of this <code>Calendar</code>. Use {@link
+     * #set(int,int) set(Calendar.HOUR_OF_DAY, 0)} to reset the hour
+     * value.
+     *
+     * @param field the calendar field to be cleared.
+     * @see #clear()
+     */
+    public final void clear(int field)
+    {
+        fields[field] = 0;
+        stamp[field] = UNSET;
+        isSet[field] = false;
+
+        areAllFieldsSet = areFieldsSet = false;
+        isTimeSet = false;
+    }
+
+    /**
+     * Determines if the given calendar field has a value set,
+     * including cases that the value has been set by internal fields
+     * calculations triggered by a <code>get</code> method call.
+     *
+     * @param field the calendar field to test
+     * @return <code>true</code> if the given calendar field has a value set;
+     * <code>false</code> otherwise.
+     */
+    public final boolean isSet(int field)
+    {
+        return stamp[field] != UNSET;
+    }
+
+    /**
+     * Returns the string representation of the calendar
+     * <code>field</code> value in the given <code>style</code> and
+     * <code>locale</code>.  If no string representation is
+     * applicable, <code>null</code> is returned. This method calls
+     * {@link Calendar#get(int) get(field)} to get the calendar
+     * <code>field</code> value if the string representation is
+     * applicable to the given calendar <code>field</code>.
+     *
+     * <p>For example, if this <code>Calendar</code> is a
+     * <code>GregorianCalendar</code> and its date is 2005-01-01, then
+     * the string representation of the {@link #MONTH} field would be
+     * "January" in the long style in an English locale or "Jan" in
+     * the short style. However, no string representation would be
+     * available for the {@link #DAY_OF_MONTH} field, and this method
+     * would return <code>null</code>.
+     *
+     * <p>The default implementation supports the calendar fields for
+     * which a {@link DateFormatSymbols} has names in the given
+     * <code>locale</code>.
+     *
+     * @param field
+     *        the calendar field for which the string representation
+     *        is returned
+     * @param style
+     *        the style applied to the string representation; one of {@link
+     *        #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE},
+     *        {@link #LONG_FORMAT} ({@link #LONG}), {@link #LONG_STANDALONE},
+     *        {@link #NARROW_FORMAT}, or {@link #NARROW_STANDALONE}.
+     * @param locale
+     *        the locale for the string representation
+     *        (any calendar types specified by {@code locale} are ignored)
+     * @return the string representation of the given
+     *        {@code field} in the given {@code style}, or
+     *        {@code null} if no string representation is
+     *        applicable.
+     * @exception IllegalArgumentException
+     *        if {@code field} or {@code style} is invalid,
+     *        or if this {@code Calendar} is non-lenient and any
+     *        of the calendar fields have invalid values
+     * @exception NullPointerException
+     *        if {@code locale} is null
+     * @since 1.6
+     */
+    public String getDisplayName(int field, int style, Locale locale) {
+        // BEGIN Android-changed: Treat ALL_STYLES as SHORT
+        // Android has traditionally treated ALL_STYLES as SHORT, even though
+        // it's not documented to be a valid value for style.
+        if (style == ALL_STYLES) {
+            style = SHORT;
+        }
+        // END Android-changed: Treat ALL_STYLES as SHORT
+        if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
+                            ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+
+        String calendarType = getCalendarType();
+        int fieldValue = get(field);
+        // the standalone and narrow styles are supported only through CalendarDataProviders.
+        if (isStandaloneStyle(style) || isNarrowFormatStyle(style)) {
+            String val = CalendarDataUtility.retrieveFieldValueName(calendarType,
+                                                                    field, fieldValue,
+                                                                    style, locale);
+            // Perform fallback here to follow the CLDR rules
+            if (val == null) {
+                if (isNarrowFormatStyle(style)) {
+                    val = CalendarDataUtility.retrieveFieldValueName(calendarType,
+                                                                     field, fieldValue,
+                                                                     toStandaloneStyle(style),
+                                                                     locale);
+                } else if (isStandaloneStyle(style)) {
+                    val = CalendarDataUtility.retrieveFieldValueName(calendarType,
+                                                                     field, fieldValue,
+                                                                     getBaseStyle(style),
+                                                                     locale);
+                }
+            }
+            return val;
+        }
+
+        DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
+        String[] strings = getFieldStrings(field, style, symbols);
+        if (strings != null) {
+            if (fieldValue < strings.length) {
+                return strings[fieldValue];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a {@code Map} containing all names of the calendar
+     * {@code field} in the given {@code style} and
+     * {@code locale} and their corresponding field values. For
+     * example, if this {@code Calendar} is a {@link
+     * GregorianCalendar}, the returned map would contain "Jan" to
+     * {@link #JANUARY}, "Feb" to {@link #FEBRUARY}, and so on, in the
+     * {@linkplain #SHORT short} style in an English locale.
+     *
+     * <p>Narrow names may not be unique due to use of single characters,
+     * such as "S" for Sunday and Saturday. In that case narrow names are not
+     * included in the returned {@code Map}.
+     *
+     * <p>The values of other calendar fields may be taken into
+     * account to determine a set of display names. For example, if
+     * this {@code Calendar} is a lunisolar calendar system and
+     * the year value given by the {@link #YEAR} field has a leap
+     * month, this method would return month names containing the leap
+     * month name, and month names are mapped to their values specific
+     * for the year.
+     *
+     * <p>The default implementation supports display names contained in
+     * a {@link DateFormatSymbols}. For example, if {@code field}
+     * is {@link #MONTH} and {@code style} is {@link
+     * #ALL_STYLES}, this method returns a {@code Map} containing
+     * all strings returned by {@link DateFormatSymbols#getShortMonths()}
+     * and {@link DateFormatSymbols#getMonths()}.
+     *
+     * @param field
+     *        the calendar field for which the display names are returned
+     * @param style
+     *        the style applied to the string representation; one of {@link
+     *        #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE},
+     *        {@link #LONG_FORMAT} ({@link #LONG}), {@link #LONG_STANDALONE},
+     *        {@link #NARROW_FORMAT}, or {@link #NARROW_STANDALONE}
+     * @param locale
+     *        the locale for the display names
+     * @return a {@code Map} containing all display names in
+     *        {@code style} and {@code locale} and their
+     *        field values, or {@code null} if no display names
+     *        are defined for {@code field}
+     * @exception IllegalArgumentException
+     *        if {@code field} or {@code style} is invalid,
+     *        or if this {@code Calendar} is non-lenient and any
+     *        of the calendar fields have invalid values
+     * @exception NullPointerException
+     *        if {@code locale} is null
+     * @since 1.6
+     */
+    public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
+        if (!checkDisplayNameParams(field, style, ALL_STYLES, NARROW_FORMAT, locale,
+                                    ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+        // Android-added: Add complete() here to fix leniency, see http://b/35382060
+        complete();
+
+        String calendarType = getCalendarType();
+        if (style == ALL_STYLES || isStandaloneStyle(style) || isNarrowFormatStyle(style)) {
+            Map<String, Integer> map;
+            map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field, style, locale);
+
+            // Perform fallback here to follow the CLDR rules
+            if (map == null) {
+                if (isNarrowFormatStyle(style)) {
+                    map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field,
+                                                                      toStandaloneStyle(style), locale);
+                } else if (style != ALL_STYLES) {
+                    map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field,
+                                                                      getBaseStyle(style), locale);
+                }
+            }
+            return map;
+        }
+
+        // SHORT or LONG
+        return getDisplayNamesImpl(field, style, locale);
+    }
+
+    private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) {
+        DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
+        String[] strings = getFieldStrings(field, style, symbols);
+        if (strings != null) {
+            Map<String,Integer> names = new HashMap<>();
+            for (int i = 0; i < strings.length; i++) {
+                if (strings[i].length() == 0) {
+                    continue;
+                }
+                names.put(strings[i], i);
+            }
+            return names;
+        }
+        return null;
+    }
+
+    boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle,
+                                   Locale locale, int fieldMask) {
+        int baseStyle = getBaseStyle(style); // Ignore the standalone mask
+        if (field < 0 || field >= fields.length ||
+            baseStyle < minStyle || baseStyle > maxStyle) {
+            throw new IllegalArgumentException();
+        }
+        // BEGIN Android-added: Check for invalid baseStyle == 3
+        // 3 is not a valid base style (unlike 1, 2 and 4). Throw if used.
+        if (baseStyle == 3) {
+            throw new IllegalArgumentException();
+        }
+        // END Android-added: Check for invalid baseStyle == 3
+        if (locale == null) {
+            throw new NullPointerException();
+        }
+        return isFieldSet(fieldMask, field);
+    }
+
+    private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) {
+        int baseStyle = getBaseStyle(style); // ignore the standalone mask
+
+        // DateFormatSymbols doesn't support any narrow names.
+        if (baseStyle == NARROW_FORMAT) {
+            return null;
+        }
+
+        String[] strings = null;
+        switch (field) {
+        case ERA:
+            strings = symbols.getEras();
+            break;
+
+        case MONTH:
+            strings = (baseStyle == LONG) ? symbols.getMonths() : symbols.getShortMonths();
+            break;
+
+        case DAY_OF_WEEK:
+            strings = (baseStyle == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
+            break;
+
+        case AM_PM:
+            strings = symbols.getAmPmStrings();
+            break;
+        }
+        return strings;
+    }
+
+    /**
+     * Fills in any unset fields in the calendar fields. First, the {@link
+     * #computeTime()} method is called if the time value (millisecond offset
+     * from the <a href="#Epoch">Epoch</a>) has not been calculated from
+     * calendar field values. Then, the {@link #computeFields()} method is
+     * called to calculate all calendar field values.
+     */
+    protected void complete()
+    {
+        if (!isTimeSet) {
+            updateTime();
+        }
+        if (!areFieldsSet || !areAllFieldsSet) {
+            computeFields(); // fills in unset fields
+            areAllFieldsSet = areFieldsSet = true;
+        }
+    }
+
+    /**
+     * Returns whether the value of the specified calendar field has been set
+     * externally by calling one of the setter methods rather than by the
+     * internal time calculation.
+     *
+     * @return <code>true</code> if the field has been set externally,
+     * <code>false</code> otherwise.
+     * @exception IndexOutOfBoundsException if the specified
+     *                <code>field</code> is out of range
+     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #selectFields()
+     * @see #setFieldsComputed(int)
+     */
+    final boolean isExternallySet(int field) {
+        return stamp[field] >= MINIMUM_USER_STAMP;
+    }
+
+    /**
+     * Returns a field mask (bit mask) indicating all calendar fields that
+     * have the state of externally or internally set.
+     *
+     * @return a bit mask indicating set state fields
+     */
+    final int getSetStateFields() {
+        int mask = 0;
+        for (int i = 0; i < fields.length; i++) {
+            if (stamp[i] != UNSET) {
+                mask |= 1 << i;
+            }
+        }
+        return mask;
+    }
+
+    /**
+     * Sets the state of the specified calendar fields to
+     * <em>computed</em>. This state means that the specified calendar fields
+     * have valid values that have been set by internal time calculation
+     * rather than by calling one of the setter methods.
+     *
+     * @param fieldMask the field to be marked as computed.
+     * @exception IndexOutOfBoundsException if the specified
+     *                <code>field</code> is out of range
+     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #isExternallySet(int)
+     * @see #selectFields()
+     */
+    final void setFieldsComputed(int fieldMask) {
+        if (fieldMask == ALL_FIELDS) {
+            for (int i = 0; i < fields.length; i++) {
+                stamp[i] = COMPUTED;
+                isSet[i] = true;
+            }
+            areFieldsSet = areAllFieldsSet = true;
+        } else {
+            for (int i = 0; i < fields.length; i++) {
+                if ((fieldMask & 1) == 1) {
+                    stamp[i] = COMPUTED;
+                    isSet[i] = true;
+                } else {
+                    if (areAllFieldsSet && !isSet[i]) {
+                        areAllFieldsSet = false;
+                    }
+                }
+                fieldMask >>>= 1;
+            }
+        }
+    }
+
+    /**
+     * Sets the state of the calendar fields that are <em>not</em> specified
+     * by <code>fieldMask</code> to <em>unset</em>. If <code>fieldMask</code>
+     * specifies all the calendar fields, then the state of this
+     * <code>Calendar</code> becomes that all the calendar fields are in sync
+     * with the time value (millisecond offset from the Epoch).
+     *
+     * @param fieldMask the field mask indicating which calendar fields are in
+     * sync with the time value.
+     * @exception IndexOutOfBoundsException if the specified
+     *                <code>field</code> is out of range
+     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #isExternallySet(int)
+     * @see #selectFields()
+     */
+    final void setFieldsNormalized(int fieldMask) {
+        if (fieldMask != ALL_FIELDS) {
+            for (int i = 0; i < fields.length; i++) {
+                if ((fieldMask & 1) == 0) {
+                    stamp[i] = fields[i] = 0; // UNSET == 0
+                    isSet[i] = false;
+                }
+                fieldMask >>= 1;
+            }
+        }
+
+        // Some or all of the fields are in sync with the
+        // milliseconds, but the stamp values are not normalized yet.
+        areFieldsSet = true;
+        areAllFieldsSet = false;
+    }
+
+    /**
+     * Returns whether the calendar fields are partially in sync with the time
+     * value or fully in sync but not stamp values are not normalized yet.
+     */
+    final boolean isPartiallyNormalized() {
+        return areFieldsSet && !areAllFieldsSet;
+    }
+
+    /**
+     * Returns whether the calendar fields are fully in sync with the time
+     * value.
+     */
+    final boolean isFullyNormalized() {
+        return areFieldsSet && areAllFieldsSet;
+    }
+
+    /**
+     * Marks this Calendar as not sync'd.
+     */
+    final void setUnnormalized() {
+        areFieldsSet = areAllFieldsSet = false;
+    }
+
+    /**
+     * Returns whether the specified <code>field</code> is on in the
+     * <code>fieldMask</code>.
+     */
+    static boolean isFieldSet(int fieldMask, int field) {
+        return (fieldMask & (1 << field)) != 0;
+    }
+
+    /**
+     * Returns a field mask indicating which calendar field values
+     * to be used to calculate the time value. The calendar fields are
+     * returned as a bit mask, each bit of which corresponds to a field, i.e.,
+     * the mask value of <code>field</code> is <code>(1 &lt;&lt;
+     * field)</code>. For example, 0x26 represents the <code>YEAR</code>,
+     * <code>MONTH</code>, and <code>DAY_OF_MONTH</code> fields (i.e., 0x26 is
+     * equal to
+     * <code>(1&lt;&lt;YEAR)|(1&lt;&lt;MONTH)|(1&lt;&lt;DAY_OF_MONTH))</code>.
+     *
+     * <p>This method supports the calendar fields resolution as described in
+     * the class description. If the bit mask for a given field is on and its
+     * field has not been set (i.e., <code>isSet(field)</code> is
+     * <code>false</code>), then the default value of the field has to be
+     * used, which case means that the field has been selected because the
+     * selected combination involves the field.
+     *
+     * @return a bit mask of selected fields
+     * @see #isExternallySet(int)
+     */
+    final int selectFields() {
+        // This implementation has been taken from the GregorianCalendar class.
+
+        // The YEAR field must always be used regardless of its SET
+        // state because YEAR is a mandatory field to determine the date
+        // and the default value (EPOCH_YEAR) may change through the
+        // normalization process.
+        int fieldMask = YEAR_MASK;
+
+        if (stamp[ERA] != UNSET) {
+            fieldMask |= ERA_MASK;
+        }
+        // Find the most recent group of fields specifying the day within
+        // the year.  These may be any of the following combinations:
+        //   MONTH + DAY_OF_MONTH
+        //   MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
+        //   MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
+        //   DAY_OF_YEAR
+        //   WEEK_OF_YEAR + DAY_OF_WEEK
+        // We look for the most recent of the fields in each group to determine
+        // the age of the group.  For groups involving a week-related field such
+        // as WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR, both the
+        // week-related field and the DAY_OF_WEEK must be set for the group as a
+        // whole to be considered.  (See bug 4153860 - liu 7/24/98.)
+        int dowStamp = stamp[DAY_OF_WEEK];
+        int monthStamp = stamp[MONTH];
+        int domStamp = stamp[DAY_OF_MONTH];
+        int womStamp = aggregateStamp(stamp[WEEK_OF_MONTH], dowStamp);
+        int dowimStamp = aggregateStamp(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
+        int doyStamp = stamp[DAY_OF_YEAR];
+        int woyStamp = aggregateStamp(stamp[WEEK_OF_YEAR], dowStamp);
+
+        int bestStamp = domStamp;
+        if (womStamp > bestStamp) {
+            bestStamp = womStamp;
+        }
+        if (dowimStamp > bestStamp) {
+            bestStamp = dowimStamp;
+        }
+        if (doyStamp > bestStamp) {
+            bestStamp = doyStamp;
+        }
+        if (woyStamp > bestStamp) {
+            bestStamp = woyStamp;
+        }
+
+        /* No complete combination exists.  Look for WEEK_OF_MONTH,
+         * DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR alone.  Treat DAY_OF_WEEK alone
+         * as DAY_OF_WEEK_IN_MONTH.
+         */
+        if (bestStamp == UNSET) {
+            womStamp = stamp[WEEK_OF_MONTH];
+            dowimStamp = Math.max(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
+            woyStamp = stamp[WEEK_OF_YEAR];
+            bestStamp = Math.max(Math.max(womStamp, dowimStamp), woyStamp);
+
+            /* Treat MONTH alone or no fields at all as DAY_OF_MONTH.  This may
+             * result in bestStamp = domStamp = UNSET if no fields are set,
+             * which indicates DAY_OF_MONTH.
+             */
+            if (bestStamp == UNSET) {
+                bestStamp = domStamp = monthStamp;
+            }
+        }
+
+        if (bestStamp == domStamp ||
+           (bestStamp == womStamp && stamp[WEEK_OF_MONTH] >= stamp[WEEK_OF_YEAR]) ||
+           (bestStamp == dowimStamp && stamp[DAY_OF_WEEK_IN_MONTH] >= stamp[WEEK_OF_YEAR])) {
+            fieldMask |= MONTH_MASK;
+            if (bestStamp == domStamp) {
+                fieldMask |= DAY_OF_MONTH_MASK;
+            } else {
+                assert (bestStamp == womStamp || bestStamp == dowimStamp);
+                if (dowStamp != UNSET) {
+                    fieldMask |= DAY_OF_WEEK_MASK;
+                }
+                if (womStamp == dowimStamp) {
+                    // When they are equal, give the priority to
+                    // WEEK_OF_MONTH for compatibility.
+                    if (stamp[WEEK_OF_MONTH] >= stamp[DAY_OF_WEEK_IN_MONTH]) {
+                        fieldMask |= WEEK_OF_MONTH_MASK;
+                    } else {
+                        fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
+                    }
+                } else {
+                    if (bestStamp == womStamp) {
+                        fieldMask |= WEEK_OF_MONTH_MASK;
+                    } else {
+                        assert (bestStamp == dowimStamp);
+                        if (stamp[DAY_OF_WEEK_IN_MONTH] != UNSET) {
+                            fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
+                        }
+                    }
+                }
+            }
+        } else {
+            assert (bestStamp == doyStamp || bestStamp == woyStamp ||
+                    bestStamp == UNSET);
+            if (bestStamp == doyStamp) {
+                fieldMask |= DAY_OF_YEAR_MASK;
+            } else {
+                assert (bestStamp == woyStamp);
+                if (dowStamp != UNSET) {
+                    fieldMask |= DAY_OF_WEEK_MASK;
+                }
+                fieldMask |= WEEK_OF_YEAR_MASK;
+            }
+        }
+
+        // Find the best set of fields specifying the time of day.  There
+        // are only two possibilities here; the HOUR_OF_DAY or the
+        // AM_PM and the HOUR.
+        int hourOfDayStamp = stamp[HOUR_OF_DAY];
+        int hourStamp = aggregateStamp(stamp[HOUR], stamp[AM_PM]);
+        bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
+
+        // if bestStamp is still UNSET, then take HOUR or AM_PM. (See 4846659)
+        if (bestStamp == UNSET) {
+            bestStamp = Math.max(stamp[HOUR], stamp[AM_PM]);
+        }
+
+        // Hours
+        if (bestStamp != UNSET) {
+            if (bestStamp == hourOfDayStamp) {
+                fieldMask |= HOUR_OF_DAY_MASK;
+            } else {
+                fieldMask |= HOUR_MASK;
+                if (stamp[AM_PM] != UNSET) {
+                    fieldMask |= AM_PM_MASK;
+                }
+            }
+        }
+        if (stamp[MINUTE] != UNSET) {
+            fieldMask |= MINUTE_MASK;
+        }
+        if (stamp[SECOND] != UNSET) {
+            fieldMask |= SECOND_MASK;
+        }
+        if (stamp[MILLISECOND] != UNSET) {
+            fieldMask |= MILLISECOND_MASK;
+        }
+        if (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP) {
+                fieldMask |= ZONE_OFFSET_MASK;
+        }
+        if (stamp[DST_OFFSET] >= MINIMUM_USER_STAMP) {
+            fieldMask |= DST_OFFSET_MASK;
+        }
+
+        return fieldMask;
+    }
+
+    int getBaseStyle(int style) {
+        return style & ~STANDALONE_MASK;
+    }
+
+    // BEGIN Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat
+    /**
+     * @hide
+     */
+    public static int toStandaloneStyle(int style) {
+    // END Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat
+        return style | STANDALONE_MASK;
+    }
+
+    private boolean isStandaloneStyle(int style) {
+        return (style & STANDALONE_MASK) != 0;
+    }
+
+    private boolean isNarrowStyle(int style) {
+        return style == NARROW_FORMAT || style == NARROW_STANDALONE;
+    }
+
+    private boolean isNarrowFormatStyle(int style) {
+        return style == NARROW_FORMAT;
+    }
+
+    /**
+     * Returns the pseudo-time-stamp for two fields, given their
+     * individual pseudo-time-stamps.  If either of the fields
+     * is unset, then the aggregate is unset.  Otherwise, the
+     * aggregate is the later of the two stamps.
+     */
+    private static int aggregateStamp(int stamp_a, int stamp_b) {
+        if (stamp_a == UNSET || stamp_b == UNSET) {
+            return UNSET;
+        }
+        return (stamp_a > stamp_b) ? stamp_a : stamp_b;
+    }
+
+    /**
+     * Returns an unmodifiable {@code Set} containing all calendar types
+     * supported by {@code Calendar} in the runtime environment. The available
+     * calendar types can be used for the <a
+     * href="Locale.html#def_locale_extension">Unicode locale extensions</a>.
+     * The {@code Set} returned contains at least {@code "gregory"}. The
+     * calendar types don't include aliases, such as {@code "gregorian"} for
+     * {@code "gregory"}.
+     *
+     * @return an unmodifiable {@code Set} containing all available calendar types
+     * @since 1.8
+     * @see #getCalendarType()
+     * @see Calendar.Builder#setCalendarType(String)
+     * @see Locale#getUnicodeLocaleType(String)
+     */
+    public static Set<String> getAvailableCalendarTypes() {
+        return AvailableCalendarTypes.SET;
+    }
+
+    private static class AvailableCalendarTypes {
+        private static final Set<String> SET;
+        static {
+            Set<String> set = new HashSet<>(3);
+            set.add("gregory");
+            // Android-changed: removed "buddhist" and "japanese".
+            // set.add("buddhist");
+            // set.add("japanese");
+            SET = Collections.unmodifiableSet(set);
+        }
+        private AvailableCalendarTypes() {
+        }
+    }
+
+    /**
+     * Returns the calendar type of this {@code Calendar}. Calendar types are
+     * defined by the <em>Unicode Locale Data Markup Language (LDML)</em>
+     * specification.
+     *
+     * <p>The default implementation of this method returns the class name of
+     * this {@code Calendar} instance. Any subclasses that implement
+     * LDML-defined calendar systems should override this method to return
+     * appropriate calendar types.
+     *
+     * @return the LDML-defined calendar type or the class name of this
+     *         {@code Calendar} instance
+     * @since 1.8
+     * @see <a href="Locale.html#def_extensions">Locale extensions</a>
+     * @see Locale.Builder#setLocale(Locale)
+     * @see Locale.Builder#setUnicodeLocaleKeyword(String, String)
+     */
+    public String getCalendarType() {
+        return this.getClass().getName();
+    }
+
+    /**
+     * Compares this <code>Calendar</code> to the specified
+     * <code>Object</code>.  The result is <code>true</code> if and only if
+     * the argument is a <code>Calendar</code> object of the same calendar
+     * system that represents the same time value (millisecond offset from the
+     * <a href="#Epoch">Epoch</a>) under the same
+     * <code>Calendar</code> parameters as this object.
+     *
+     * <p>The <code>Calendar</code> parameters are the values represented
+     * by the <code>isLenient</code>, <code>getFirstDayOfWeek</code>,
+     * <code>getMinimalDaysInFirstWeek</code> and <code>getTimeZone</code>
+     * methods. If there is any difference in those parameters
+     * between the two <code>Calendar</code>s, this method returns
+     * <code>false</code>.
+     *
+     * <p>Use the {@link #compareTo(Calendar) compareTo} method to
+     * compare only the time values.
+     *
+     * @param obj the object to compare with.
+     * @return <code>true</code> if this object is equal to <code>obj</code>;
+     * <code>false</code> otherwise.
+     */
+    @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        try {
+            Calendar that = (Calendar)obj;
+            return compareTo(getMillisOf(that)) == 0 &&
+                lenient == that.lenient &&
+                firstDayOfWeek == that.firstDayOfWeek &&
+                minimalDaysInFirstWeek == that.minimalDaysInFirstWeek &&
+                zone.equals(that.zone);
+        } catch (Exception e) {
+            // Note: GregorianCalendar.computeTime throws
+            // IllegalArgumentException if the ERA value is invalid
+            // even it's in lenient mode.
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code for this calendar.
+     *
+     * @return a hash code value for this object.
+     * @since 1.2
+     */
+    @Override
+    public int hashCode() {
+        // 'otheritems' represents the hash code for the previous versions.
+        int otheritems = (lenient ? 1 : 0)
+            | (firstDayOfWeek << 1)
+            | (minimalDaysInFirstWeek << 4)
+            | (zone.hashCode() << 7);
+        long t = getMillisOf(this);
+        return (int) t ^ (int)(t >> 32) ^ otheritems;
+    }
+
+    /**
+     * Returns whether this <code>Calendar</code> represents a time
+     * before the time represented by the specified
+     * <code>Object</code>. This method is equivalent to:
+     * <pre>{@code
+     *         compareTo(when) < 0
+     * }</pre>
+     * if and only if <code>when</code> is a <code>Calendar</code>
+     * instance. Otherwise, the method returns <code>false</code>.
+     *
+     * @param when the <code>Object</code> to be compared
+     * @return <code>true</code> if the time of this
+     * <code>Calendar</code> is before the time represented by
+     * <code>when</code>; <code>false</code> otherwise.
+     * @see     #compareTo(Calendar)
+     */
+    public boolean before(Object when) {
+        return when instanceof Calendar
+            && compareTo((Calendar)when) < 0;
+    }
+
+    /**
+     * Returns whether this <code>Calendar</code> represents a time
+     * after the time represented by the specified
+     * <code>Object</code>. This method is equivalent to:
+     * <pre>{@code
+     *         compareTo(when) > 0
+     * }</pre>
+     * if and only if <code>when</code> is a <code>Calendar</code>
+     * instance. Otherwise, the method returns <code>false</code>.
+     *
+     * @param when the <code>Object</code> to be compared
+     * @return <code>true</code> if the time of this <code>Calendar</code> is
+     * after the time represented by <code>when</code>; <code>false</code>
+     * otherwise.
+     * @see     #compareTo(Calendar)
+     */
+    public boolean after(Object when) {
+        return when instanceof Calendar
+            && compareTo((Calendar)when) > 0;
+    }
+
+    /**
+     * Compares the time values (millisecond offsets from the <a
+     * href="#Epoch">Epoch</a>) represented by two
+     * <code>Calendar</code> objects.
+     *
+     * @param anotherCalendar the <code>Calendar</code> to be compared.
+     * @return the value <code>0</code> if the time represented by the argument
+     * is equal to the time represented by this <code>Calendar</code>; a value
+     * less than <code>0</code> if the time of this <code>Calendar</code> is
+     * before the time represented by the argument; and a value greater than
+     * <code>0</code> if the time of this <code>Calendar</code> is after the
+     * time represented by the argument.
+     * @exception NullPointerException if the specified <code>Calendar</code> is
+     *            <code>null</code>.
+     * @exception IllegalArgumentException if the time value of the
+     * specified <code>Calendar</code> object can't be obtained due to
+     * any invalid calendar values.
+     * @since   1.5
+     */
+    @Override
+    public int compareTo(Calendar anotherCalendar) {
+        return compareTo(getMillisOf(anotherCalendar));
+    }
+
+    /**
+     * Adds or subtracts the specified amount of time to the given calendar field,
+     * based on the calendar's rules. For example, to subtract 5 days from
+     * the current time of the calendar, you can achieve it by calling:
+     * <p><code>add(Calendar.DAY_OF_MONTH, -5)</code>.
+     *
+     * @param field the calendar field.
+     * @param amount the amount of date or time to be added to the field.
+     * @see #roll(int,int)
+     * @see #set(int,int)
+     */
+    abstract public void add(int field, int amount);
+
+    /**
+     * Adds or subtracts (up/down) a single unit of time on the given time
+     * field without changing larger fields. For example, to roll the current
+     * date up by one day, you can achieve it by calling:
+     * <p>roll(Calendar.DATE, true).
+     * When rolling on the year or Calendar.YEAR field, it will roll the year
+     * value in the range between 1 and the value returned by calling
+     * <code>getMaximum(Calendar.YEAR)</code>.
+     * When rolling on the month or Calendar.MONTH field, other fields like
+     * date might conflict and, need to be changed. For instance,
+     * rolling the month on the date 01/31/96 will result in 02/29/96.
+     * When rolling on the hour-in-day or Calendar.HOUR_OF_DAY field, it will
+     * roll the hour value in the range between 0 and 23, which is zero-based.
+     *
+     * @param field the time field.
+     * @param up indicates if the value of the specified time field is to be
+     * rolled up or rolled down. Use true if rolling up, false otherwise.
+     * @see Calendar#add(int,int)
+     * @see Calendar#set(int,int)
+     */
+    abstract public void roll(int field, boolean up);
+
+    /**
+     * Adds the specified (signed) amount to the specified calendar field
+     * without changing larger fields.  A negative amount means to roll
+     * down.
+     *
+     * <p>NOTE:  This default implementation on <code>Calendar</code> just repeatedly calls the
+     * version of {@link #roll(int,boolean) roll()} that rolls by one unit.  This may not
+     * always do the right thing.  For example, if the <code>DAY_OF_MONTH</code> field is 31,
+     * rolling through February will leave it set to 28.  The <code>GregorianCalendar</code>
+     * version of this function takes care of this problem.  Other subclasses
+     * should also provide overrides of this function that do the right thing.
+     *
+     * @param field the calendar field.
+     * @param amount the signed amount to add to the calendar <code>field</code>.
+     * @since 1.2
+     * @see #roll(int,boolean)
+     * @see #add(int,int)
+     * @see #set(int,int)
+     */
+    public void roll(int field, int amount)
+    {
+        while (amount > 0) {
+            roll(field, true);
+            amount--;
+        }
+        while (amount < 0) {
+            roll(field, false);
+            amount++;
+        }
+    }
+
+    /**
+     * Sets the time zone with the given time zone value.
+     *
+     * @param value the given time zone.
+     */
+    public void setTimeZone(TimeZone value)
+    {
+        zone = value;
+        sharedZone = false;
+        /* Recompute the fields from the time using the new zone.  This also
+         * works if isTimeSet is false (after a call to set()).  In that case
+         * the time will be computed from the fields using the new zone, then
+         * the fields will get recomputed from that.  Consider the sequence of
+         * calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST).
+         * Is cal set to 1 o'clock EST or 1 o'clock PST?  Answer: PST.  More
+         * generally, a call to setTimeZone() affects calls to set() BEFORE AND
+         * AFTER it up to the next call to complete().
+         */
+        areAllFieldsSet = areFieldsSet = false;
+    }
+
+    /**
+     * Gets the time zone.
+     *
+     * @return the time zone object associated with this calendar.
+     */
+    public TimeZone getTimeZone()
+    {
+        // If the TimeZone object is shared by other Calendar instances, then
+        // create a clone.
+        if (sharedZone) {
+            zone = (TimeZone) zone.clone();
+            sharedZone = false;
+        }
+        return zone;
+    }
+
+    /**
+     * Returns the time zone (without cloning).
+     */
+    TimeZone getZone() {
+        return zone;
+    }
+
+    /**
+     * Sets the sharedZone flag to <code>shared</code>.
+     */
+    void setZoneShared(boolean shared) {
+        sharedZone = shared;
+    }
+
+    /**
+     * Specifies whether or not date/time interpretation is to be lenient.  With
+     * lenient interpretation, a date such as "February 942, 1996" will be
+     * treated as being equivalent to the 941st day after February 1, 1996.
+     * With strict (non-lenient) interpretation, such dates will cause an exception to be
+     * thrown. The default is lenient.
+     *
+     * @param lenient <code>true</code> if the lenient mode is to be turned
+     * on; <code>false</code> if it is to be turned off.
+     * @see #isLenient()
+     * @see java.text.DateFormat#setLenient
+     */
+    public void setLenient(boolean lenient)
+    {
+        this.lenient = lenient;
+    }
+
+    /**
+     * Tells whether date/time interpretation is to be lenient.
+     *
+     * @return <code>true</code> if the interpretation mode of this calendar is lenient;
+     * <code>false</code> otherwise.
+     * @see #setLenient(boolean)
+     */
+    public boolean isLenient()
+    {
+        return lenient;
+    }
+
+    /**
+     * Sets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
+     * <code>MONDAY</code> in France.
+     *
+     * @param value the given first day of the week.
+     * @see #getFirstDayOfWeek()
+     * @see #getMinimalDaysInFirstWeek()
+     */
+    public void setFirstDayOfWeek(int value)
+    {
+        if (firstDayOfWeek == value) {
+            return;
+        }
+        firstDayOfWeek = value;
+        invalidateWeekFields();
+    }
+
+    /**
+     * Gets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
+     * <code>MONDAY</code> in France.
+     *
+     * @return the first day of the week.
+     * @see #setFirstDayOfWeek(int)
+     * @see #getMinimalDaysInFirstWeek()
+     */
+    public int getFirstDayOfWeek()
+    {
+        return firstDayOfWeek;
+    }
+
+    /**
+     * Sets what the minimal days required in the first week of the year are;
+     * For example, if the first week is defined as one that contains the first
+     * day of the first month of a year, call this method with value 1. If it
+     * must be a full week, use value 7.
+     *
+     * @param value the given minimal days required in the first week
+     * of the year.
+     * @see #getMinimalDaysInFirstWeek()
+     */
+    public void setMinimalDaysInFirstWeek(int value)
+    {
+        if (minimalDaysInFirstWeek == value) {
+            return;
+        }
+        minimalDaysInFirstWeek = value;
+        invalidateWeekFields();
+    }
+
+    /**
+     * Gets what the minimal days required in the first week of the year are;
+     * e.g., if the first week is defined as one that contains the first day
+     * of the first month of a year, this method returns 1. If
+     * the minimal days required must be a full week, this method
+     * returns 7.
+     *
+     * @return the minimal days required in the first week of the year.
+     * @see #setMinimalDaysInFirstWeek(int)
+     */
+    public int getMinimalDaysInFirstWeek()
+    {
+        return minimalDaysInFirstWeek;
+    }
+
+    /**
+     * Returns whether this {@code Calendar} supports week dates.
+     *
+     * <p>The default implementation of this method returns {@code false}.
+     *
+     * @return {@code true} if this {@code Calendar} supports week dates;
+     *         {@code false} otherwise.
+     * @see #getWeekYear()
+     * @see #setWeekDate(int,int,int)
+     * @see #getWeeksInWeekYear()
+     * @since 1.7
+     */
+    public boolean isWeekDateSupported() {
+        return false;
+    }
+
+    /**
+     * Returns the week year represented by this {@code Calendar}. The
+     * week year is in sync with the week cycle. The {@linkplain
+     * #getFirstDayOfWeek() first day of the first week} is the first
+     * day of the week year.
+     *
+     * <p>The default implementation of this method throws an
+     * {@link UnsupportedOperationException}.
+     *
+     * @return the week year of this {@code Calendar}
+     * @exception UnsupportedOperationException
+     *            if any week year numbering isn't supported
+     *            in this {@code Calendar}.
+     * @see #isWeekDateSupported()
+     * @see #getFirstDayOfWeek()
+     * @see #getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    public int getWeekYear() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Sets the date of this {@code Calendar} with the the given date
+     * specifiers - week year, week of year, and day of week.
+     *
+     * <p>Unlike the {@code set} method, all of the calendar fields
+     * and {@code time} values are calculated upon return.
+     *
+     * <p>If {@code weekOfYear} is out of the valid week-of-year range
+     * in {@code weekYear}, the {@code weekYear} and {@code
+     * weekOfYear} values are adjusted in lenient mode, or an {@code
+     * IllegalArgumentException} is thrown in non-lenient mode.
+     *
+     * <p>The default implementation of this method throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @param weekYear   the week year
+     * @param weekOfYear the week number based on {@code weekYear}
+     * @param dayOfWeek  the day of week value: one of the constants
+     *                   for the {@link #DAY_OF_WEEK} field: {@link
+     *                   #SUNDAY}, ..., {@link #SATURDAY}.
+     * @exception IllegalArgumentException
+     *            if any of the given date specifiers is invalid
+     *            or any of the calendar fields are inconsistent
+     *            with the given date specifiers in non-lenient mode
+     * @exception UnsupportedOperationException
+     *            if any week year numbering isn't supported in this
+     *            {@code Calendar}.
+     * @see #isWeekDateSupported()
+     * @see #getFirstDayOfWeek()
+     * @see #getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the number of weeks in the week year represented by this
+     * {@code Calendar}.
+     *
+     * <p>The default implementation of this method throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @return the number of weeks in the week year.
+     * @exception UnsupportedOperationException
+     *            if any week year numbering isn't supported in this
+     *            {@code Calendar}.
+     * @see #WEEK_OF_YEAR
+     * @see #isWeekDateSupported()
+     * @see #getWeekYear()
+     * @see #getActualMaximum(int)
+     * @since 1.7
+     */
+    public int getWeeksInWeekYear() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the minimum value for the given calendar field of this
+     * <code>Calendar</code> instance. The minimum value is defined as
+     * the smallest value returned by the {@link #get(int) get} method
+     * for any possible time value.  The minimum value depends on
+     * calendar system specific parameters of the instance.
+     *
+     * @param field the calendar field.
+     * @return the minimum value for the given calendar field.
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    abstract public int getMinimum(int field);
+
+    /**
+     * Returns the maximum value for the given calendar field of this
+     * <code>Calendar</code> instance. The maximum value is defined as
+     * the largest value returned by the {@link #get(int) get} method
+     * for any possible time value. The maximum value depends on
+     * calendar system specific parameters of the instance.
+     *
+     * @param field the calendar field.
+     * @return the maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    abstract public int getMaximum(int field);
+
+    /**
+     * Returns the highest minimum value for the given calendar field
+     * of this <code>Calendar</code> instance. The highest minimum
+     * value is defined as the largest value returned by {@link
+     * #getActualMinimum(int)} for any possible time value. The
+     * greatest minimum value depends on calendar system specific
+     * parameters of the instance.
+     *
+     * @param field the calendar field.
+     * @return the highest minimum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    abstract public int getGreatestMinimum(int field);
+
+    /**
+     * Returns the lowest maximum value for the given calendar field
+     * of this <code>Calendar</code> instance. The lowest maximum
+     * value is defined as the smallest value returned by {@link
+     * #getActualMaximum(int)} for any possible time value. The least
+     * maximum value depends on calendar system specific parameters of
+     * the instance. For example, a <code>Calendar</code> for the
+     * Gregorian calendar system returns 28 for the
+     * <code>DAY_OF_MONTH</code> field, because the 28th is the last
+     * day of the shortest month of this calendar, February in a
+     * common year.
+     *
+     * @param field the calendar field.
+     * @return the lowest maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    abstract public int getLeastMaximum(int field);
+
+    /**
+     * Returns the minimum value that the specified calendar field
+     * could have, given the time value of this <code>Calendar</code>.
+     *
+     * <p>The default implementation of this method uses an iterative
+     * algorithm to determine the actual minimum value for the
+     * calendar field. Subclasses should, if possible, override this
+     * with a more efficient implementation - in many cases, they can
+     * simply return <code>getMinimum()</code>.
+     *
+     * @param field the calendar field
+     * @return the minimum of the given calendar field for the time
+     * value of this <code>Calendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMaximum(int)
+     * @since 1.2
+     */
+    public int getActualMinimum(int field) {
+        int fieldValue = getGreatestMinimum(field);
+        int endValue = getMinimum(field);
+
+        // if we know that the minimum value is always the same, just return it
+        if (fieldValue == endValue) {
+            return fieldValue;
+        }
+
+        // clone the calendar so we don't mess with the real one, and set it to
+        // accept anything for the field values
+        Calendar work = (Calendar)this.clone();
+        work.setLenient(true);
+
+        // now try each value from getLeastMaximum() to getMaximum() one by one until
+        // we get a value that normalizes to another value.  The last value that
+        // normalizes to itself is the actual minimum for the current date
+        int result = fieldValue;
+
+        do {
+            work.set(field, fieldValue);
+            if (work.get(field) != fieldValue) {
+                break;
+            } else {
+                result = fieldValue;
+                fieldValue--;
+            }
+        } while (fieldValue >= endValue);
+
+        return result;
+    }
+
+    /**
+     * Returns the maximum value that the specified calendar field
+     * could have, given the time value of this
+     * <code>Calendar</code>. For example, the actual maximum value of
+     * the <code>MONTH</code> field is 12 in some years, and 13 in
+     * other years in the Hebrew calendar system.
+     *
+     * <p>The default implementation of this method uses an iterative
+     * algorithm to determine the actual maximum value for the
+     * calendar field. Subclasses should, if possible, override this
+     * with a more efficient implementation.
+     *
+     * @param field the calendar field
+     * @return the maximum of the given calendar field for the time
+     * value of this <code>Calendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @since 1.2
+     */
+    public int getActualMaximum(int field) {
+        int fieldValue = getLeastMaximum(field);
+        int endValue = getMaximum(field);
+
+        // if we know that the maximum value is always the same, just return it.
+        if (fieldValue == endValue) {
+            return fieldValue;
+        }
+
+        // clone the calendar so we don't mess with the real one, and set it to
+        // accept anything for the field values.
+        Calendar work = (Calendar)this.clone();
+        work.setLenient(true);
+
+        // if we're counting weeks, set the day of the week to Sunday.  We know the
+        // last week of a month or year will contain the first day of the week.
+        if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH) {
+            work.set(DAY_OF_WEEK, firstDayOfWeek);
+        }
+
+        // now try each value from getLeastMaximum() to getMaximum() one by one until
+        // we get a value that normalizes to another value.  The last value that
+        // normalizes to itself is the actual maximum for the current date
+        int result = fieldValue;
+
+        do {
+            work.set(field, fieldValue);
+            if (work.get(field) != fieldValue) {
+                break;
+            } else {
+                result = fieldValue;
+                fieldValue++;
+            }
+        } while (fieldValue <= endValue);
+
+        return result;
+    }
+
+    /**
+     * Creates and returns a copy of this object.
+     *
+     * @return a copy of this object.
+     */
+    @Override
+    public Object clone()
+    {
+        try {
+            Calendar other = (Calendar) super.clone();
+
+            other.fields = new int[FIELD_COUNT];
+            other.isSet = new boolean[FIELD_COUNT];
+            other.stamp = new int[FIELD_COUNT];
+            for (int i = 0; i < FIELD_COUNT; i++) {
+                other.fields[i] = fields[i];
+                other.stamp[i] = stamp[i];
+                other.isSet[i] = isSet[i];
+            }
+            other.zone = (TimeZone) zone.clone();
+            return other;
+        }
+        catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    private static final String[] FIELD_NAME = {
+        "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
+        "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR",
+        "HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
+        "DST_OFFSET"
+    };
+
+    /**
+     * Returns the name of the specified calendar field.
+     *
+     * @param field the calendar field
+     * @return the calendar field name
+     * @exception IndexOutOfBoundsException if <code>field</code> is negative,
+     * equal to or greater then <code>FIELD_COUNT</code>.
+     */
+    static String getFieldName(int field) {
+        return FIELD_NAME[field];
+    }
+
+    /**
+     * Return a string representation of this calendar. This method
+     * is intended to be used only for debugging purposes, and the
+     * format of the returned string may vary between implementations.
+     * The returned string may be empty but may not be <code>null</code>.
+     *
+     * @return  a string representation of this calendar.
+     */
+    @Override
+    public String toString() {
+        // NOTE: BuddhistCalendar.toString() interprets the string
+        // produced by this method so that the Gregorian year number
+        // is substituted by its B.E. year value. It relies on
+        // "...,YEAR=<year>,..." or "...,YEAR=?,...".
+        StringBuilder buffer = new StringBuilder(800);
+        buffer.append(getClass().getName()).append('[');
+        appendValue(buffer, "time", isTimeSet, time);
+        buffer.append(",areFieldsSet=").append(areFieldsSet);
+        buffer.append(",areAllFieldsSet=").append(areAllFieldsSet);
+        buffer.append(",lenient=").append(lenient);
+        buffer.append(",zone=").append(zone);
+        appendValue(buffer, ",firstDayOfWeek", true, (long) firstDayOfWeek);
+        appendValue(buffer, ",minimalDaysInFirstWeek", true, (long) minimalDaysInFirstWeek);
+        for (int i = 0; i < FIELD_COUNT; ++i) {
+            buffer.append(',');
+            appendValue(buffer, FIELD_NAME[i], isSet(i), (long) fields[i]);
+        }
+        buffer.append(']');
+        return buffer.toString();
+    }
+
+    // =======================privates===============================
+
+    private static void appendValue(StringBuilder sb, String item, boolean valid, long value) {
+        sb.append(item).append('=');
+        if (valid) {
+            sb.append(value);
+        } else {
+            sb.append('?');
+        }
+    }
+
+    /**
+     * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent.
+     * They are used to figure out the week count for a specific date for
+     * a given locale. These must be set when a Calendar is constructed.
+     * @param desiredLocale the given locale.
+     */
+    private void setWeekCountData(Locale desiredLocale)
+    {
+        /* try to get the Locale data from the cache */
+        int[] data = cachedLocaleData.get(desiredLocale);
+        if (data == null) {  /* cache miss */
+            data = new int[2];
+            // BEGIN Android-changed: Use ICU4C to get week data.
+            // data[0] = CalendarDataUtility.retrieveFirstDayOfWeek(desiredLocale);
+            // data[1] = CalendarDataUtility.retrieveMinimalDaysInFirstWeek(desiredLocale);
+            LocaleData localeData = LocaleData.get(desiredLocale);
+            data[0] = localeData.firstDayOfWeek.intValue();
+            data[1] = localeData.minimalDaysInFirstWeek.intValue();
+            // END Android-changed: Use ICU4C to get week data.
+            cachedLocaleData.putIfAbsent(desiredLocale, data);
+        }
+        firstDayOfWeek = data[0];
+        minimalDaysInFirstWeek = data[1];
+    }
+
+    /**
+     * Recomputes the time and updates the status fields isTimeSet
+     * and areFieldsSet.  Callers should check isTimeSet and only
+     * call this method if isTimeSet is false.
+     */
+    private void updateTime() {
+        computeTime();
+        // The areFieldsSet and areAllFieldsSet values are no longer
+        // controlled here (as of 1.5).
+        isTimeSet = true;
+    }
+
+    private int compareTo(long t) {
+        long thisTime = getMillisOf(this);
+        return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1;
+    }
+
+    private static long getMillisOf(Calendar calendar) {
+        if (calendar.isTimeSet) {
+            return calendar.time;
+        }
+        Calendar cal = (Calendar) calendar.clone();
+        cal.setLenient(true);
+        return cal.getTimeInMillis();
+    }
+
+    /**
+     * Adjusts the stamp[] values before nextStamp overflow. nextStamp
+     * is set to the next stamp value upon the return.
+     */
+    private void adjustStamp() {
+        int max = MINIMUM_USER_STAMP;
+        int newStamp = MINIMUM_USER_STAMP;
+
+        for (;;) {
+            int min = Integer.MAX_VALUE;
+            for (int i = 0; i < stamp.length; i++) {
+                int v = stamp[i];
+                if (v >= newStamp && min > v) {
+                    min = v;
+                }
+                if (max < v) {
+                    max = v;
+                }
+            }
+            if (max != min && min == Integer.MAX_VALUE) {
+                break;
+            }
+            for (int i = 0; i < stamp.length; i++) {
+                if (stamp[i] == min) {
+                    stamp[i] = newStamp;
+                }
+            }
+            newStamp++;
+            if (min == max) {
+                break;
+            }
+        }
+        nextStamp = newStamp;
+    }
+
+    /**
+     * Sets the WEEK_OF_MONTH and WEEK_OF_YEAR fields to new values with the
+     * new parameter value if they have been calculated internally.
+     */
+    private void invalidateWeekFields()
+    {
+        if (stamp[WEEK_OF_MONTH] != COMPUTED &&
+            stamp[WEEK_OF_YEAR] != COMPUTED) {
+            return;
+        }
+
+        // We have to check the new values of these fields after changing
+        // firstDayOfWeek and/or minimalDaysInFirstWeek. If the field values
+        // have been changed, then set the new values. (4822110)
+        Calendar cal = (Calendar) clone();
+        cal.setLenient(true);
+        cal.clear(WEEK_OF_MONTH);
+        cal.clear(WEEK_OF_YEAR);
+
+        if (stamp[WEEK_OF_MONTH] == COMPUTED) {
+            int weekOfMonth = cal.get(WEEK_OF_MONTH);
+            if (fields[WEEK_OF_MONTH] != weekOfMonth) {
+                fields[WEEK_OF_MONTH] = weekOfMonth;
+            }
+        }
+
+        if (stamp[WEEK_OF_YEAR] == COMPUTED) {
+            int weekOfYear = cal.get(WEEK_OF_YEAR);
+            if (fields[WEEK_OF_YEAR] != weekOfYear) {
+                fields[WEEK_OF_YEAR] = weekOfYear;
+            }
+        }
+    }
+
+    /**
+     * Save the state of this object to a stream (i.e., serialize it).
+     *
+     * Ideally, <code>Calendar</code> would only write out its state data and
+     * the current time, and not write any field data out, such as
+     * <code>fields[]</code>, <code>isTimeSet</code>, <code>areFieldsSet</code>,
+     * and <code>isSet[]</code>.  <code>nextStamp</code> also should not be part
+     * of the persistent state. Unfortunately, this didn't happen before JDK 1.1
+     * shipped. To be compatible with JDK 1.1, we will always have to write out
+     * the field values and state flags.  However, <code>nextStamp</code> can be
+     * removed from the serialization stream; this will probably happen in the
+     * near future.
+     */
+    private synchronized void writeObject(ObjectOutputStream stream)
+         throws IOException
+    {
+        // Try to compute the time correctly, for the future (stream
+        // version 2) in which we don't write out fields[] or isSet[].
+        if (!isTimeSet) {
+            try {
+                updateTime();
+            }
+            catch (IllegalArgumentException e) {}
+        }
+
+        // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+        // Write out the 1.1 FCS object.
+        stream.defaultWriteObject();
+    }
+
+    private static class CalendarAccessControlContext {
+        private static final AccessControlContext INSTANCE;
+        static {
+            RuntimePermission perm = new RuntimePermission("accessClassInPackage.sun.util.calendar");
+            PermissionCollection perms = perm.newPermissionCollection();
+            perms.add(perm);
+            INSTANCE = new AccessControlContext(new ProtectionDomain[] {
+                                                    new ProtectionDomain(null, perms)
+                                                });
+        }
+        private CalendarAccessControlContext() {
+        }
+    }
+
+    /**
+     * Reconstitutes this object from a stream (i.e., deserialize it).
+     */
+    private void readObject(ObjectInputStream stream)
+         throws IOException, ClassNotFoundException
+    {
+        final ObjectInputStream input = stream;
+        input.defaultReadObject();
+
+        stamp = new int[FIELD_COUNT];
+
+        // Starting with version 2 (not implemented yet), we expect that
+        // fields[], isSet[], isTimeSet, and areFieldsSet may not be
+        // streamed out anymore.  We expect 'time' to be correct.
+        if (serialVersionOnStream >= 2)
+        {
+            isTimeSet = true;
+            if (fields == null) {
+                fields = new int[FIELD_COUNT];
+            }
+            if (isSet == null) {
+                isSet = new boolean[FIELD_COUNT];
+            }
+        }
+        else if (serialVersionOnStream >= 0)
+        {
+            for (int i=0; i<FIELD_COUNT; ++i) {
+                stamp[i] = isSet[i] ? COMPUTED : UNSET;
+            }
+        }
+
+        serialVersionOnStream = currentSerialVersion;
+
+        // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+
+        // If the deserialized object has a SimpleTimeZone, try to
+        // replace it with a ZoneInfo equivalent (as of 1.4) in order
+        // to be compatible with the SimpleTimeZone-based
+        // implementation as much as possible.
+        if (zone instanceof SimpleTimeZone) {
+            String id = zone.getID();
+            TimeZone tz = TimeZone.getTimeZone(id);
+            if (tz != null && tz.hasSameRules(zone) && tz.getID().equals(id)) {
+                zone = tz;
+            }
+        }
+    }
+
+    /**
+     * Converts this object to an {@link Instant}.
+     * <p>
+     * The conversion creates an {@code Instant} that represents the
+     * same point on the time-line as this {@code Calendar}.
+     *
+     * @return the instant representing the same point on the time-line
+     * @since 1.8
+     */
+    public final Instant toInstant() {
+        return Instant.ofEpochMilli(getTimeInMillis());
+    }
+}
diff --git a/java/util/Collection.annotated.java b/java/util/Collection.annotated.java
new file mode 100644
index 0000000..d2f425f
--- /dev/null
+++ b/java/util/Collection.annotated.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Collection<E> extends java.lang.Iterable<E> {
+
+public int size();
+
+public boolean isEmpty();
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o);
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator();
+
+public [email protected] Object @libcore.util.NonNull [] toArray();
+
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a);
+
+public boolean add(@libcore.util.NullFromTypeParam E e);
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o);
+
+public boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c);
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public default boolean removeIf(@libcore.util.NonNull java.util.function.Predicate<? super @libcore.util.NullFromTypeParam E> filter) { throw new RuntimeException("Stub!"); }
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public void clear();
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o);
+
+public int hashCode();
+
[email protected] public default java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public default java.util.stream.Stream<@libcore.util.NullFromTypeParam E> stream() { throw new RuntimeException("Stub!"); }
+
[email protected] public default java.util.stream.Stream<@libcore.util.NullFromTypeParam E> parallelStream() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/Collection.java b/java/util/Collection.java
new file mode 100644
index 0000000..2ae8872
--- /dev/null
+++ b/java/util/Collection.java
@@ -0,0 +1,604 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * The root interface in the <i>collection hierarchy</i>.  A collection
+ * represents a group of objects, known as its <i>elements</i>.  Some
+ * collections allow duplicate elements and others do not.  Some are ordered
+ * and others unordered.  The JDK does not provide any <i>direct</i>
+ * implementations of this interface: it provides implementations of more
+ * specific subinterfaces like <tt>Set</tt> and <tt>List</tt>.  This interface
+ * is typically used to pass collections around and manipulate them where
+ * maximum generality is desired.
+ *
+ * <p><i>Bags</i> or <i>multisets</i> (unordered collections that may contain
+ * duplicate elements) should implement this interface directly.
+ *
+ * <p>All general-purpose <tt>Collection</tt> implementation classes (which
+ * typically implement <tt>Collection</tt> indirectly through one of its
+ * subinterfaces) should provide two "standard" constructors: a void (no
+ * arguments) constructor, which creates an empty collection, and a
+ * constructor with a single argument of type <tt>Collection</tt>, which
+ * creates a new collection with the same elements as its argument.  In
+ * effect, the latter constructor allows the user to copy any collection,
+ * producing an equivalent collection of the desired implementation type.
+ * There is no way to enforce this convention (as interfaces cannot contain
+ * constructors) but all of the general-purpose <tt>Collection</tt>
+ * implementations in the Java platform libraries comply.
+ *
+ * <p>The "destructive" methods contained in this interface, that is, the
+ * methods that modify the collection on which they operate, are specified to
+ * throw <tt>UnsupportedOperationException</tt> if this collection does not
+ * support the operation.  If this is the case, these methods may, but are not
+ * required to, throw an <tt>UnsupportedOperationException</tt> if the
+ * invocation would have no effect on the collection.  For example, invoking
+ * the {@link #addAll(Collection)} method on an unmodifiable collection may,
+ * but is not required to, throw the exception if the collection to be added
+ * is empty.
+ *
+ * <p><a name="optional-restrictions">
+ * Some collection implementations have restrictions on the elements that
+ * they may contain.</a>  For example, some implementations prohibit null elements,
+ * and some have restrictions on the types of their elements.  Attempting to
+ * add an ineligible element throws an unchecked exception, typically
+ * <tt>NullPointerException</tt> or <tt>ClassCastException</tt>.  Attempting
+ * to query the presence of an ineligible element may throw an exception,
+ * or it may simply return false; some implementations will exhibit the former
+ * behavior and some will exhibit the latter.  More generally, attempting an
+ * operation on an ineligible element whose completion would not result in
+ * the insertion of an ineligible element into the collection may throw an
+ * exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <p>It is up to each collection to determine its own synchronization
+ * policy.  In the absence of a stronger guarantee by the
+ * implementation, undefined behavior may result from the invocation
+ * of any method on a collection that is being mutated by another
+ * thread; this includes direct invocations, passing the collection to
+ * a method that might perform invocations, and using an existing
+ * iterator to examine the collection.
+ *
+ * <p>Many methods in Collections Framework interfaces are defined in
+ * terms of the {@link Object#equals(Object) equals} method.  For example,
+ * the specification for the {@link #contains(Object) contains(Object o)}
+ * method says: "returns <tt>true</tt> if and only if this collection
+ * contains at least one element <tt>e</tt> such that
+ * <tt>(o==null ? e==null : o.equals(e))</tt>."  This specification should
+ * <i>not</i> be construed to imply that invoking <tt>Collection.contains</tt>
+ * with a non-null argument <tt>o</tt> will cause <tt>o.equals(e)</tt> to be
+ * invoked for any element <tt>e</tt>.  Implementations are free to implement
+ * optimizations whereby the <tt>equals</tt> invocation is avoided, for
+ * example, by first comparing the hash codes of the two elements.  (The
+ * {@link Object#hashCode()} specification guarantees that two objects with
+ * unequal hash codes cannot be equal.)  More generally, implementations of
+ * the various Collections Framework interfaces are free to take advantage of
+ * the specified behavior of underlying {@link Object} methods wherever the
+ * implementor deems it appropriate.
+ *
+ * <p>Some collection operations which perform recursive traversal of the
+ * collection may fail with an exception for self-referential instances where
+ * the collection directly or indirectly contains itself. This includes the
+ * {@code clone()}, {@code equals()}, {@code hashCode()} and {@code toString()}
+ * methods. Implementations may optionally handle the self-referential scenario,
+ * however most current implementations do not do so.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @implSpec
+ * The default method implementations (inherited or otherwise) do not apply any
+ * synchronization protocol.  If a {@code Collection} implementation has a
+ * specific synchronization protocol, then it must override default
+ * implementations to apply that protocol.
+ *
+ * @param <E> the type of elements in this collection
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Set
+ * @see     List
+ * @see     Map
+ * @see     SortedSet
+ * @see     SortedMap
+ * @see     HashSet
+ * @see     TreeSet
+ * @see     ArrayList
+ * @see     LinkedList
+ * @see     Vector
+ * @see     Collections
+ * @see     Arrays
+ * @see     AbstractCollection
+ * @since 1.2
+ */
+
+public interface Collection<E> extends Iterable<E> {
+    // Query Operations
+
+    /**
+     * Returns the number of elements in this collection.  If this collection
+     * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
+     * <tt>Integer.MAX_VALUE</tt>.
+     *
+     * @return the number of elements in this collection
+     */
+    int size();
+
+    /**
+     * Returns <tt>true</tt> if this collection contains no elements.
+     *
+     * @return <tt>true</tt> if this collection contains no elements
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns <tt>true</tt> if this collection contains the specified element.
+     * More formally, returns <tt>true</tt> if and only if this collection
+     * contains at least one element <tt>e</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     *
+     * @param o element whose presence in this collection is to be tested
+     * @return <tt>true</tt> if this collection contains the specified
+     *         element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         collection does not permit null elements
+     *         (<a href="#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns an iterator over the elements in this collection.  There are no
+     * guarantees concerning the order in which the elements are returned
+     * (unless this collection is an instance of some class that provides a
+     * guarantee).
+     *
+     * @return an <tt>Iterator</tt> over the elements in this collection
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an array containing all of the elements in this collection.
+     * If this collection makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements in
+     * the same order.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this collection.  (In other words, this method must
+     * allocate a new array even if this collection is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this collection
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing all of the elements in this collection;
+     * the runtime type of the returned array is that of the specified array.
+     * If the collection fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this collection.
+     *
+     * <p>If this collection fits in the specified array with room to spare
+     * (i.e., the array has more elements than this collection), the element
+     * in the array immediately following the end of the collection is set to
+     * <tt>null</tt>.  (This is useful in determining the length of this
+     * collection <i>only</i> if the caller knows that this collection does
+     * not contain any <tt>null</tt> elements.)
+     *
+     * <p>If this collection makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements in
+     * the same order.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * 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 collection known to contain only strings.
+     * The following code can be used to dump the collection into a newly
+     * allocated array of <tt>String</tt>:
+     *
+     * <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>.
+     *
+     * @param <T> the runtime type of the array to contain the collection
+     * @param a the array into which the elements of this collection are to be
+     *        stored, if it is big enough; otherwise, a new array of the same
+     *        runtime type is allocated for this purpose.
+     * @return an array containing all of the elements in this collection
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this collection
+     * @throws NullPointerException if the specified array is null
+     */
+    <T> T[] toArray(T[] a);
+
+    // Modification Operations
+
+    /**
+     * Ensures that this collection contains the specified element (optional
+     * operation).  Returns <tt>true</tt> if this collection changed as a
+     * result of the call.  (Returns <tt>false</tt> if this collection does
+     * not permit duplicates and already contains the specified element.)<p>
+     *
+     * Collections that support this operation may place limitations on what
+     * elements may be added to this collection.  In particular, some
+     * collections will refuse to add <tt>null</tt> elements, and others will
+     * impose restrictions on the type of elements that may be added.
+     * Collection classes should clearly specify in their documentation any
+     * restrictions on what elements may be added.<p>
+     *
+     * If a collection refuses to add a particular element for any reason
+     * other than that it already contains the element, it <i>must</i> throw
+     * an exception (rather than returning <tt>false</tt>).  This preserves
+     * the invariant that a collection always contains the specified element
+     * after this call returns.
+     *
+     * @param e element whose presence in this collection is to be ensured
+     * @return <tt>true</tt> if this collection changed as a result of the
+     *         call
+     * @throws UnsupportedOperationException if the <tt>add</tt> operation
+     *         is not supported by this collection
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this collection
+     * @throws NullPointerException if the specified element is null and this
+     *         collection does not permit null elements
+     * @throws IllegalArgumentException if some property of the element
+     *         prevents it from being added to this collection
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to insertion restrictions
+     */
+    boolean add(E e);
+
+    /**
+     * Removes a single instance of the specified element from this
+     * collection, if it is present (optional operation).  More formally,
+     * removes an element <tt>e</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>, if
+     * this collection contains one or more such elements.  Returns
+     * <tt>true</tt> if this collection contained the specified element (or
+     * equivalently, if this collection changed as a result of the call).
+     *
+     * @param o element to be removed from this collection, if present
+     * @return <tt>true</tt> if an element was removed as a result of this call
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         collection does not permit null elements
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
+     *         is not supported by this collection
+     */
+    boolean remove(Object o);
+
+
+    // Bulk Operations
+
+    /**
+     * Returns <tt>true</tt> if this collection contains all of the elements
+     * in the specified collection.
+     *
+     * @param  c collection to be checked for containment in this collection
+     * @return <tt>true</tt> if this collection contains all of the elements
+     *         in the specified collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in the specified collection are incompatible with this
+     *         collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this collection does not permit null
+     *         elements
+     *         (<a href="#optional-restrictions">optional</a>),
+     *         or if the specified collection is null.
+     * @see    #contains(Object)
+     */
+    boolean containsAll(Collection<?> c);
+
+    /**
+     * Adds all of the elements in the specified collection to this collection
+     * (optional operation).  The behavior of this operation is undefined if
+     * the specified collection is modified while the operation is in progress.
+     * (This implies that the behavior of this call is undefined if the
+     * specified collection is this collection, and this collection is
+     * nonempty.)
+     *
+     * @param c collection containing elements to be added to this collection
+     * @return <tt>true</tt> if this collection changed as a result of the call
+     * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+     *         is not supported by this collection
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this collection
+     * @throws NullPointerException if the specified collection contains a
+     *         null element and this collection does not permit null elements,
+     *         or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this
+     *         collection
+     * @throws IllegalStateException if not all the elements can be added at
+     *         this time due to insertion restrictions
+     * @see #add(Object)
+     */
+    boolean addAll(Collection<? extends E> c);
+
+    /**
+     * Removes all of this collection's elements that are also contained in the
+     * specified collection (optional operation).  After this call returns,
+     * this collection will contain no elements in common with the specified
+     * collection.
+     *
+     * @param c collection containing elements to be removed from this collection
+     * @return <tt>true</tt> if this collection changed as a result of the
+     *         call
+     * @throws UnsupportedOperationException if the <tt>removeAll</tt> method
+     *         is not supported by this collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in this collection are incompatible with the specified
+     *         collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this collection contains one or more
+     *         null elements and the specified collection does not support
+     *         null elements
+     *         (<a href="#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean removeAll(Collection<?> c);
+
+    /**
+     * Removes all of the elements of this collection that satisfy the given
+     * predicate.  Errors or runtime exceptions thrown during iteration or by
+     * the predicate are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation traverses all elements of the collection using
+     * its {@link #iterator}.  Each matching element is removed using
+     * {@link Iterator#remove()}.  If the collection's iterator does not
+     * support removal then an {@code UnsupportedOperationException} will be
+     * thrown on the first matching element.
+     *
+     * @param filter a predicate which returns {@code true} for elements to be
+     *        removed
+     * @return {@code true} if any elements were removed
+     * @throws NullPointerException if the specified filter is null
+     * @throws UnsupportedOperationException if elements cannot be removed
+     *         from this collection.  Implementations may throw this exception if a
+     *         matching element cannot be removed or if, in general, removal is not
+     *         supported.
+     * @since 1.8
+     */
+    default boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        boolean removed = false;
+        final Iterator<E> each = iterator();
+        while (each.hasNext()) {
+            if (filter.test(each.next())) {
+                each.remove();
+                removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Retains only the elements in this collection that are contained in the
+     * specified collection (optional operation).  In other words, removes from
+     * this collection all of its elements that are not contained in the
+     * specified collection.
+     *
+     * @param c collection containing elements to be retained in this collection
+     * @return <tt>true</tt> if this collection changed as a result of the call
+     * @throws UnsupportedOperationException if the <tt>retainAll</tt> operation
+     *         is not supported by this collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in this collection are incompatible with the specified
+     *         collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this collection contains one or more
+     *         null elements and the specified collection does not permit null
+     *         elements
+     *         (<a href="#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean retainAll(Collection<?> c);
+
+    /**
+     * Removes all of the elements from this collection (optional operation).
+     * The collection will be empty after this method returns.
+     *
+     * @throws UnsupportedOperationException if the <tt>clear</tt> operation
+     *         is not supported by this collection
+     */
+    void clear();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this collection for equality. <p>
+     *
+     * While the <tt>Collection</tt> interface adds no stipulations to the
+     * general contract for the <tt>Object.equals</tt>, programmers who
+     * implement the <tt>Collection</tt> interface "directly" (in other words,
+     * create a class that is a <tt>Collection</tt> but is not a <tt>Set</tt>
+     * or a <tt>List</tt>) must exercise care if they choose to override the
+     * <tt>Object.equals</tt>.  It is not necessary to do so, and the simplest
+     * course of action is to rely on <tt>Object</tt>'s implementation, but
+     * the implementor may wish to implement a "value comparison" in place of
+     * the default "reference comparison."  (The <tt>List</tt> and
+     * <tt>Set</tt> interfaces mandate such value comparisons.)<p>
+     *
+     * The general contract for the <tt>Object.equals</tt> method states that
+     * equals must be symmetric (in other words, <tt>a.equals(b)</tt> if and
+     * only if <tt>b.equals(a)</tt>).  The contracts for <tt>List.equals</tt>
+     * and <tt>Set.equals</tt> state that lists are only equal to other lists,
+     * and sets to other sets.  Thus, a custom <tt>equals</tt> method for a
+     * collection class that implements neither the <tt>List</tt> nor
+     * <tt>Set</tt> interface must return <tt>false</tt> when this collection
+     * is compared to any list or set.  (By the same logic, it is not possible
+     * to write a class that correctly implements both the <tt>Set</tt> and
+     * <tt>List</tt> interfaces.)
+     *
+     * @param o object to be compared for equality with this collection
+     * @return <tt>true</tt> if the specified object is equal to this
+     * collection
+     *
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     * @see List#equals(Object)
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this collection.  While the
+     * <tt>Collection</tt> interface adds no stipulations to the general
+     * contract for the <tt>Object.hashCode</tt> method, programmers should
+     * take note that any class that overrides the <tt>Object.equals</tt>
+     * method must also override the <tt>Object.hashCode</tt> method in order
+     * to satisfy the general contract for the <tt>Object.hashCode</tt> method.
+     * In particular, <tt>c1.equals(c2)</tt> implies that
+     * <tt>c1.hashCode()==c2.hashCode()</tt>.
+     *
+     * @return the hash code value for this collection
+     *
+     * @see Object#hashCode()
+     * @see Object#equals(Object)
+     */
+    int hashCode();
+
+    /**
+     * Creates a {@link Spliterator} over the elements in this collection.
+     *
+     * Implementations should document characteristic values reported by the
+     * spliterator.  Such characteristic values are not required to be reported
+     * if the spliterator reports {@link Spliterator#SIZED} and this collection
+     * contains no elements.
+     *
+     * <p>The default implementation should be overridden by subclasses that
+     * can return a more efficient spliterator.  In order to
+     * preserve expected laziness behavior for the {@link #stream()} and
+     * {@link #parallelStream()}} methods, spliterators should either have the
+     * characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>.
+     * If none of these is practical, the overriding class should describe the
+     * spliterator's documented policy of binding and structural interference,
+     * and should override the {@link #stream()} and {@link #parallelStream()}
+     * methods to create streams using a {@code Supplier} of the spliterator,
+     * as in:
+     * <pre>{@code
+     *     Stream<E> s = StreamSupport.stream(() -> spliterator(), spliteratorCharacteristics)
+     * }</pre>
+     * <p>These requirements ensure that streams produced by the
+     * {@link #stream()} and {@link #parallelStream()} methods will reflect the
+     * contents of the collection as of initiation of the terminal stream
+     * operation.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the collections's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the collection's iterator.
+     * <p>
+     * The created {@code Spliterator} reports {@link Spliterator#SIZED}.
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * <p>If a spliterator covers no elements then the reporting of additional
+     * characteristic values, beyond that of {@code SIZED} and {@code SUBSIZED},
+     * does not aid clients to control, specialize or simplify computation.
+     * However, this does enable shared use of an immutable and empty
+     * spliterator instance (see {@link Spliterators#emptySpliterator()}) for
+     * empty collections, and enables clients to determine if such a spliterator
+     * covers no elements.
+     *
+     * @return a {@code Spliterator} over the elements in this collection
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, 0);
+    }
+
+    /**
+     * Returns a sequential {@code Stream} with this collection as its source.
+     *
+     * <p>This method should be overridden when the {@link #spliterator()}
+     * method cannot return a spliterator that is {@code IMMUTABLE},
+     * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
+     * for details.)
+     *
+     * @implSpec
+     * The default implementation creates a sequential {@code Stream} from the
+     * collection's {@code Spliterator}.
+     *
+     * @return a sequential {@code Stream} over the elements in this collection
+     * @since 1.8
+     */
+    default Stream<E> stream() {
+        return StreamSupport.stream(spliterator(), false);
+    }
+
+    /**
+     * Returns a possibly parallel {@code Stream} with this collection as its
+     * source.  It is allowable for this method to return a sequential stream.
+     *
+     * <p>This method should be overridden when the {@link #spliterator()}
+     * method cannot return a spliterator that is {@code IMMUTABLE},
+     * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
+     * for details.)
+     *
+     * @implSpec
+     * The default implementation creates a parallel {@code Stream} from the
+     * collection's {@code Spliterator}.
+     *
+     * @return a possibly parallel {@code Stream} over the elements in this
+     * collection
+     * @since 1.8
+     */
+    default Stream<E> parallelStream() {
+        return StreamSupport.stream(spliterator(), true);
+    }
+}
diff --git a/java/util/Collections.annotated.java b/java/util/Collections.annotated.java
new file mode 100644
index 0000000..3e3e636
--- /dev/null
+++ b/java/util/Collections.annotated.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.lang.reflect.Array;
+import java.util.stream.Stream;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Collections {
+
+Collections() { throw new RuntimeException("Stub!"); }
+
+public static <T extends java.lang.Comparable<? super T>> void sort(@libcore.util.NonNull java.util.List<@libcore.util.NonNull T> list) { throw new RuntimeException("Stub!"); }
+
+public static <T> void sort(@libcore.util.NonNull java.util.List<@libcore.util.NullFromTypeParam T> list, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static <T> int binarySearch(@libcore.util.NonNull java.util.List<? extends @libcore.util.NonNull java.lang.Comparable<? super T>> list, @libcore.util.NonNull T key) { throw new RuntimeException("Stub!"); }
+
+public static <T> int binarySearch(@libcore.util.NonNull java.util.List<? extends @libcore.util.NullFromTypeParam T> list, @libcore.util.NullFromTypeParam T key, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static void reverse(@libcore.util.NonNull java.util.List<?> list) { throw new RuntimeException("Stub!"); }
+
+public static void shuffle(@libcore.util.NonNull java.util.List<?> list) { throw new RuntimeException("Stub!"); }
+
+public static void shuffle(@libcore.util.NonNull java.util.List<?> list, @libcore.util.NonNull java.util.Random rnd) { throw new RuntimeException("Stub!"); }
+
+public static void swap(@libcore.util.NonNull java.util.List<?> list, int i, int j) { throw new RuntimeException("Stub!"); }
+
+public static <T> void fill(@libcore.util.NonNull java.util.List<? super @libcore.util.NullFromTypeParam T> list, @libcore.util.NullFromTypeParam T obj) { throw new RuntimeException("Stub!"); }
+
+public static <T> void copy(@libcore.util.NonNull java.util.List<? super @libcore.util.NullFromTypeParam T> dest, @libcore.util.NonNull java.util.List<? extends @libcore.util.NullFromTypeParam T> src) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NonNull T> coll) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T min(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam T> coll, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> comp) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NonNull T> coll) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T max(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam T> coll, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> comp) { throw new RuntimeException("Stub!"); }
+
+public static void rotate(@libcore.util.NonNull java.util.List<?> list, int distance) { throw new RuntimeException("Stub!"); }
+
+public static <T> boolean replaceAll(@libcore.util.NonNull java.util.List<@libcore.util.NullFromTypeParam T> list, @libcore.util.NullFromTypeParam T oldVal, @libcore.util.NullFromTypeParam T newVal) { throw new RuntimeException("Stub!"); }
+
+public static int indexOfSubList(@libcore.util.NonNull java.util.List<?> source, @libcore.util.NonNull java.util.List<?> target) { throw new RuntimeException("Stub!"); }
+
+public static int lastIndexOfSubList(@libcore.util.NonNull java.util.List<?> source, @libcore.util.NonNull java.util.List<?> target) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Collection<@libcore.util.NullFromTypeParam T> unmodifiableCollection(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Set<@libcore.util.NullFromTypeParam T> unmodifiableSet(@libcore.util.NonNull java.util.Set<? extends @libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.SortedSet<@libcore.util.NullFromTypeParam T> unmodifiableSortedSet(@libcore.util.NonNull java.util.SortedSet<@libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.NavigableSet<@libcore.util.NullFromTypeParam T> unmodifiableNavigableSet(@libcore.util.NonNull java.util.NavigableSet<@libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.List<@libcore.util.NullFromTypeParam T> unmodifiableList(@libcore.util.NonNull java.util.List<? extends @libcore.util.NullFromTypeParam T> list) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> unmodifiableMap(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K, ? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> unmodifiableSortedMap(@libcore.util.NonNull java.util.SortedMap<@libcore.util.NullFromTypeParam K, ? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> unmodifiableNavigableMap(@libcore.util.NonNull java.util.NavigableMap<@libcore.util.NullFromTypeParam K, ? extends @libcore.util.NullFromTypeParam  V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Collection<@libcore.util.NullFromTypeParam T> synchronizedCollection(@libcore.util.NonNull java.util.Collection<@libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Set<@libcore.util.NullFromTypeParam T> synchronizedSet(@libcore.util.NonNull java.util.Set<@libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.SortedSet<@libcore.util.NullFromTypeParam T> synchronizedSortedSet(@libcore.util.NonNull java.util.SortedSet<@libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.NavigableSet<@libcore.util.NullFromTypeParam T> synchronizedNavigableSet(@libcore.util.NonNull java.util.NavigableSet<@libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.List<@libcore.util.NullFromTypeParam T> synchronizedList(@libcore.util.NonNull java.util.List<@libcore.util.NullFromTypeParam T> list) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> synchronizedMap(@libcore.util.NonNull java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> synchronizedSortedMap(@libcore.util.NonNull java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> synchronizedNavigableMap(@libcore.util.NonNull java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Collection<@libcore.util.NullFromTypeParam E> checkedCollection(@libcore.util.NonNull java.util.Collection<@libcore.util.NullFromTypeParam E> c, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Queue<@libcore.util.NullFromTypeParam E> checkedQueue(@libcore.util.NonNull java.util.Queue<@libcore.util.NullFromTypeParam E> queue, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NullFromTypeParam E> checkedSet(@libcore.util.NonNull java.util.Set<@libcore.util.NullFromTypeParam E> s, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.SortedSet<@libcore.util.NullFromTypeParam E> checkedSortedSet(@libcore.util.NonNull java.util.SortedSet<@libcore.util.NullFromTypeParam E> s, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.NavigableSet<@libcore.util.NullFromTypeParam E> checkedNavigableSet(@libcore.util.NonNull java.util.NavigableSet<@libcore.util.NullFromTypeParam E> s, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NullFromTypeParam E> checkedList(@libcore.util.NonNull java.util.List<@libcore.util.NullFromTypeParam E> list, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> checkedMap(@libcore.util.NonNull java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m, @libcore.util.NonNull java.lang.Class<K> keyType, @libcore.util.NonNull java.lang.Class<V> valueType) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> checkedSortedMap(@libcore.util.NonNull java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m, @libcore.util.NonNull java.lang.Class<K> keyType, @libcore.util.NonNull java.lang.Class<V> valueType) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> checkedNavigableMap(@libcore.util.NonNull java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m, @libcore.util.NonNull java.lang.Class<K> keyType, @libcore.util.NonNull java.lang.Class<V> valueType) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Iterator<@libcore.util.NullFromTypeParam T> emptyIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.ListIterator<@libcore.util.NullFromTypeParam T> emptyListIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Enumeration<@libcore.util.NullFromTypeParam T> emptyEnumeration() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final <T> java.util.Set<@libcore.util.NullFromTypeParam T> emptySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.SortedSet<@libcore.util.NullFromTypeParam E> emptySortedSet() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.NavigableSet<@libcore.util.NullFromTypeParam E> emptyNavigableSet() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final <T> java.util.List<@libcore.util.NullFromTypeParam T> emptyList() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final <K, V> java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> emptyMap() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final <K, V> java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> emptySortedMap() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final <K, V> java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> emptyNavigableMap() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Set<@libcore.util.NullFromTypeParam T> singleton(@libcore.util.NullFromTypeParam T o) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.List<@libcore.util.NullFromTypeParam T> singletonList(@libcore.util.NullFromTypeParam T o) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> singletonMap(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.List<@libcore.util.NullFromTypeParam T> nCopies(int n, @libcore.util.NullFromTypeParam T o) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Comparator<@libcore.util.NonNull T> reverseOrder() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Comparator<@libcore.util.NullFromTypeParam T> reverseOrder(@libcore.util.Nullable java.util.Comparator<@libcore.util.NullFromTypeParam T> cmp) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Enumeration<@libcore.util.NullFromTypeParam T> enumeration(@libcore.util.NonNull java.util.Collection<@libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.ArrayList<@libcore.util.NullFromTypeParam T> list(@libcore.util.NonNull java.util.Enumeration<@libcore.util.NullFromTypeParam T> e) { throw new RuntimeException("Stub!"); }
+
+public static int frequency(@libcore.util.NonNull java.util.Collection<?> c, @libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public static boolean disjoint(@libcore.util.NonNull java.util.Collection<?> c1, @libcore.util.NonNull java.util.Collection<?> c2) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static <T> boolean addAll(@libcore.util.NonNull java.util.Collection<? super @libcore.util.NullFromTypeParam T> c, T @libcore.util.NonNull ... elements) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NullFromTypeParam E> newSetFromMap(@libcore.util.NonNull java.util.Map<@libcore.util.NullFromTypeParam E, @libcore.util.NonNull java.lang.Boolean> map) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Queue<@libcore.util.NullFromTypeParam T> asLifoQueue(@libcore.util.NonNull java.util.Deque<@libcore.util.NullFromTypeParam T> deque) { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.util.List EMPTY_LIST;
+static { EMPTY_LIST = null; }
+
[email protected] public static final java.util.Map EMPTY_MAP;
+static { EMPTY_MAP = null; }
+
[email protected] public static final java.util.Set EMPTY_SET;
+static { EMPTY_SET = null; }
+}
diff --git a/java/util/Collections.java b/java/util/Collections.java
new file mode 100644
index 0000000..58ad86f
--- /dev/null
+++ b/java/util/Collections.java
@@ -0,0 +1,5621 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import dalvik.system.VMRuntime;
+
+/**
+ * This class consists exclusively of static methods that operate on or return
+ * collections.  It contains polymorphic algorithms that operate on
+ * collections, "wrappers", which return a new collection backed by a
+ * specified collection, and a few other odds and ends.
+ *
+ * <p>The methods of this class all throw a <tt>NullPointerException</tt>
+ * if the collections or class objects provided to them are null.
+ *
+ * <p>The documentation for the polymorphic algorithms contained in this class
+ * generally includes a brief description of the <i>implementation</i>.  Such
+ * descriptions should be regarded as <i>implementation notes</i>, rather than
+ * parts of the <i>specification</i>.  Implementors should feel free to
+ * substitute other algorithms, so long as the specification itself is adhered
+ * to.  (For example, the algorithm used by <tt>sort</tt> does not have to be
+ * a mergesort, but it does have to be <i>stable</i>.)
+ *
+ * <p>The "destructive" algorithms contained in this class, that is, the
+ * algorithms that modify the collection on which they operate, are specified
+ * to throw <tt>UnsupportedOperationException</tt> if the collection does not
+ * support the appropriate mutation primitive(s), such as the <tt>set</tt>
+ * method.  These algorithms may, but are not required to, throw this
+ * exception if an invocation would have no effect on the collection.  For
+ * example, invoking the <tt>sort</tt> method on an unmodifiable list that is
+ * already sorted may or may not throw <tt>UnsupportedOperationException</tt>.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Collection
+ * @see     Set
+ * @see     List
+ * @see     Map
+ * @since   1.2
+ */
+
+public class Collections {
+    // Suppresses default constructor, ensuring non-instantiability.
+    private Collections() {
+    }
+
+    // Algorithms
+
+    /*
+     * Tuning parameters for algorithms - Many of the List algorithms have
+     * two implementations, one of which is appropriate for RandomAccess
+     * lists, the other for "sequential."  Often, the random access variant
+     * yields better performance on small sequential access lists.  The
+     * tuning parameters below determine the cutoff point for what constitutes
+     * a "small" sequential access list for each algorithm.  The values below
+     * were empirically determined to work well for LinkedList. Hopefully
+     * they should be reasonable for other sequential access List
+     * implementations.  Those doing performance work on this code would
+     * do well to validate the values of these parameters from time to time.
+     * (The first word of each tuning parameter name is the algorithm to which
+     * it applies.)
+     */
+    private static final int BINARYSEARCH_THRESHOLD   = 5000;
+    private static final int REVERSE_THRESHOLD        =   18;
+    private static final int SHUFFLE_THRESHOLD        =    5;
+    private static final int FILL_THRESHOLD           =   25;
+    private static final int ROTATE_THRESHOLD         =  100;
+    private static final int COPY_THRESHOLD           =   10;
+    private static final int REPLACEALL_THRESHOLD     =   11;
+    private static final int INDEXOFSUBLIST_THRESHOLD =   35;
+
+    // Android-added: List.sort() vs. Collections.sort() app compat.
+    // Added a warning in the documentation.
+    // Collections.sort() calls List.sort() for apps targeting API version >= 26
+    // (Android Oreo) but the other way around for app targeting <= 25 (Nougat).
+    /**
+     * Sorts the specified list into ascending order, according to the
+     * {@linkplain Comparable natural ordering} of its elements.
+     * All elements in the list must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in the list must be
+     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)}
+     * must not throw a {@code ClassCastException} for any elements
+     * {@code e1} and {@code e2} in the list).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>The specified list must be modifiable, but need not be resizable.
+     *
+     * @implNote
+     * This implementation defers to the {@link List#sort(Comparator)}
+     * method using the specified list and a {@code null} comparator.
+     * Do not call this method from {@code List.sort()} since that can lead
+     * to infinite recursion. Apps targeting APIs {@code <= 25} observe
+     * backwards compatibility behavior where this method was implemented
+     * on top of {@link List#toArray()}, {@link ListIterator#next()} and
+     * {@link ListIterator#set(Object)}.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be sorted.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and integers).
+     * @throws UnsupportedOperationException if the specified list's
+     *         list-iterator does not support the {@code set} operation.
+     * @throws IllegalArgumentException (optional) if the implementation
+     *         detects that the natural ordering of the list elements is
+     *         found to violate the {@link Comparable} contract
+     * @see List#sort(Comparator)
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>> void sort(List<T> list) {
+        // Android-changed: List.sort() vs. Collections.sort() app compat.
+        // Call sort(list, null) here to be consistent with that method's
+        // (changed on Android) behavior.
+        // list.sort(null);
+        sort(list, null);
+    }
+
+    // Android-added: List.sort() vs. Collections.sort() app compat.
+    // Added a warning in the documentation.
+    // Collections.sort() calls List.sort() for apps targeting API version >= 26
+    // (Android Oreo) but the other way around for app targeting <= 25 (Nougat).
+    /**
+     * Sorts the specified list according to the order induced by the
+     * specified comparator.  All elements in the list must be <i>mutually
+     * comparable</i> using the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the list).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>The specified list must be modifiable, but need not be resizable.
+     *
+     * @implNote
+     * This implementation defers to the {@link List#sort(Comparator)}
+     * method using the specified list and comparator.
+     * Do not call this method from {@code List.sort()} since that can lead
+     * to infinite recursion. Apps targeting APIs {@code <= 25} observe
+     * backwards compatibility behavior where this method was implemented
+     * on top of {@link List#toArray()}, {@link ListIterator#next()} and
+     * {@link ListIterator#set(Object)}.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be sorted.
+     * @param  c the comparator to determine the order of the list.  A
+     *        {@code null} value indicates that the elements' <i>natural
+     *        ordering</i> should be used.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator.
+     * @throws UnsupportedOperationException if the specified list's
+     *         list-iterator does not support the {@code set} operation.
+     * @throws IllegalArgumentException (optional) if the comparator is
+     *         found to violate the {@link Comparator} contract
+     * @see List#sort(Comparator)
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public static <T> void sort(List<T> list, Comparator<? super T> c) {
+        // BEGIN Android-changed: List.sort() vs. Collections.sort() app compat.
+        // list.sort(c);
+        int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+        if (targetSdkVersion > 25) {
+            list.sort(c);
+        } else {
+            // Compatibility behavior for API <= 25. http://b/33482884
+            if (list.getClass() == ArrayList.class) {
+                Arrays.sort((T[]) ((ArrayList) list).elementData, 0, list.size(), c);
+                return;
+            }
+
+            Object[] a = list.toArray();
+            Arrays.sort(a, (Comparator) c);
+            ListIterator<T> i = list.listIterator();
+            for (int j = 0; j < a.length; j++) {
+                i.next();
+                i.set((T) a[j]);
+            }
+        }
+        // END Android-changed: List.sort() vs. Collections.sort() app compat.
+    }
+
+
+    /**
+     * Searches the specified list for the specified object using the binary
+     * search algorithm.  The list must be sorted into ascending order
+     * according to the {@linkplain Comparable natural ordering} of its
+     * elements (as by the {@link #sort(List)} method) prior to making this
+     * call.  If it is not sorted, the results are undefined.  If the list
+     * contains multiple elements equal to the specified object, there is no
+     * guarantee which one will be found.
+     *
+     * <p>This method runs in log(n) time for a "random access" list (which
+     * provides near-constant-time positional access).  If the specified list
+     * does not implement the {@link RandomAccess} interface and is large,
+     * this method will do an iterator-based binary search that performs
+     * O(n) link traversals and O(log n) element comparisons.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be searched.
+     * @param  key the key to be searched for.
+     * @return the index of the search key, if it is contained in the list;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the list: the index of the first
+     *         element greater than the key, or <tt>list.size()</tt> if all
+     *         elements in the list are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and
+     *         integers), or the search key is not mutually comparable
+     *         with the elements of the list.
+     */
+    public static <T>
+    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
+        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
+            return Collections.indexedBinarySearch(list, key);
+        else
+            return Collections.iteratorBinarySearch(list, key);
+    }
+
+    private static <T>
+    int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
+        int low = 0;
+        int high = list.size()-1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            Comparable<? super T> midVal = list.get(mid);
+            int cmp = midVal.compareTo(key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    private static <T>
+    int iteratorBinarySearch(List<? extends Comparable<? super T>> list, T key)
+    {
+        int low = 0;
+        int high = list.size()-1;
+        ListIterator<? extends Comparable<? super T>> i = list.listIterator();
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            Comparable<? super T> midVal = get(i, mid);
+            int cmp = midVal.compareTo(key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    /**
+     * Gets the ith element from the given list by repositioning the specified
+     * list listIterator.
+     */
+    private static <T> T get(ListIterator<? extends T> i, int index) {
+        T obj = null;
+        int pos = i.nextIndex();
+        if (pos <= index) {
+            do {
+                obj = i.next();
+            } while (pos++ < index);
+        } else {
+            do {
+                obj = i.previous();
+            } while (--pos > index);
+        }
+        return obj;
+    }
+
+    /**
+     * Searches the specified list for the specified object using the binary
+     * search algorithm.  The list must be sorted into ascending order
+     * according to the specified comparator (as by the
+     * {@link #sort(List, Comparator) sort(List, Comparator)}
+     * method), prior to making this call.  If it is
+     * not sorted, the results are undefined.  If the list contains multiple
+     * elements equal to the specified object, there is no guarantee which one
+     * will be found.
+     *
+     * <p>This method runs in log(n) time for a "random access" list (which
+     * provides near-constant-time positional access).  If the specified list
+     * does not implement the {@link RandomAccess} interface and is large,
+     * this method will do an iterator-based binary search that performs
+     * O(n) link traversals and O(log n) element comparisons.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be searched.
+     * @param  key the key to be searched for.
+     * @param  c the comparator by which the list is ordered.
+     *         A <tt>null</tt> value indicates that the elements'
+     *         {@linkplain Comparable natural ordering} should be used.
+     * @return the index of the search key, if it is contained in the list;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the list: the index of the first
+     *         element greater than the key, or <tt>list.size()</tt> if all
+     *         elements in the list are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator,
+     *         or the search key is not mutually comparable with the
+     *         elements of the list using this comparator.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c) {
+        if (c==null)
+            return binarySearch((List<? extends Comparable<? super T>>) list, key);
+
+        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
+            return Collections.indexedBinarySearch(list, key, c);
+        else
+            return Collections.iteratorBinarySearch(list, key, c);
+    }
+
+    private static <T> int indexedBinarySearch(List<? extends T> l, T key, Comparator<? super T> c) {
+        int low = 0;
+        int high = l.size()-1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            T midVal = l.get(mid);
+            int cmp = c.compare(midVal, key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    private static <T> int iteratorBinarySearch(List<? extends T> l, T key, Comparator<? super T> c) {
+        int low = 0;
+        int high = l.size()-1;
+        ListIterator<? extends T> i = l.listIterator();
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            T midVal = get(i, mid);
+            int cmp = c.compare(midVal, key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    /**
+     * Reverses the order of the elements in the specified list.<p>
+     *
+     * This method runs in linear time.
+     *
+     * @param  list the list whose elements are to be reversed.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the <tt>set</tt> operation.
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static void reverse(List<?> list) {
+        int size = list.size();
+        if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
+            for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
+                swap(list, i, j);
+        } else {
+            // instead of using a raw type here, it's possible to capture
+            // the wildcard but it will require a call to a supplementary
+            // private method
+            ListIterator fwd = list.listIterator();
+            ListIterator rev = list.listIterator(size);
+            for (int i=0, mid=list.size()>>1; i<mid; i++) {
+                Object tmp = fwd.next();
+                fwd.set(rev.previous());
+                rev.set(tmp);
+            }
+        }
+    }
+
+    /**
+     * Randomly permutes the specified list using a default source of
+     * randomness.  All permutations occur with approximately equal
+     * likelihood.
+     *
+     * <p>The hedge "approximately" is used in the foregoing description because
+     * default source of randomness is only approximately an unbiased source
+     * of independently chosen bits. If it were a perfect source of randomly
+     * chosen bits, then the algorithm would choose permutations with perfect
+     * uniformity.
+     *
+     * <p>This implementation traverses the list backwards, from the last
+     * element up to the second, repeatedly swapping a randomly selected element
+     * into the "current position".  Elements are randomly selected from the
+     * portion of the list that runs from the first element to the current
+     * position, inclusive.
+     *
+     * <p>This method runs in linear time.  If the specified list does not
+     * implement the {@link RandomAccess} interface and is large, this
+     * implementation dumps the specified list into an array before shuffling
+     * it, and dumps the shuffled array back into the list.  This avoids the
+     * quadratic behavior that would result from shuffling a "sequential
+     * access" list in place.
+     *
+     * @param  list the list to be shuffled.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the <tt>set</tt> operation.
+     */
+    public static void shuffle(List<?> list) {
+        Random rnd = r;
+        if (rnd == null)
+            r = rnd = new Random(); // harmless race.
+        shuffle(list, rnd);
+    }
+
+    private static Random r;
+
+    /**
+     * Randomly permute the specified list using the specified source of
+     * randomness.  All permutations occur with equal likelihood
+     * assuming that the source of randomness is fair.<p>
+     *
+     * This implementation traverses the list backwards, from the last element
+     * up to the second, repeatedly swapping a randomly selected element into
+     * the "current position".  Elements are randomly selected from the
+     * portion of the list that runs from the first element to the current
+     * position, inclusive.<p>
+     *
+     * This method runs in linear time.  If the specified list does not
+     * implement the {@link RandomAccess} interface and is large, this
+     * implementation dumps the specified list into an array before shuffling
+     * it, and dumps the shuffled array back into the list.  This avoids the
+     * quadratic behavior that would result from shuffling a "sequential
+     * access" list in place.
+     *
+     * @param  list the list to be shuffled.
+     * @param  rnd the source of randomness to use to shuffle the list.
+     * @throws UnsupportedOperationException if the specified list or its
+     *         list-iterator does not support the <tt>set</tt> operation.
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static void shuffle(List<?> list, Random rnd) {
+        int size = list.size();
+        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
+            for (int i=size; i>1; i--)
+                swap(list, i-1, rnd.nextInt(i));
+        } else {
+            Object arr[] = list.toArray();
+
+            // Shuffle array
+            for (int i=size; i>1; i--)
+                swap(arr, i-1, rnd.nextInt(i));
+
+            // Dump array back into list
+            // instead of using a raw type here, it's possible to capture
+            // the wildcard but it will require a call to a supplementary
+            // private method
+            ListIterator it = list.listIterator();
+            for (int i=0; i<arr.length; i++) {
+                it.next();
+                it.set(arr[i]);
+            }
+        }
+    }
+
+    /**
+     * Swaps the elements at the specified positions in the specified list.
+     * (If the specified positions are equal, invoking this method leaves
+     * the list unchanged.)
+     *
+     * @param list The list in which to swap elements.
+     * @param i the index of one element to be swapped.
+     * @param j the index of the other element to be swapped.
+     * @throws IndexOutOfBoundsException if either <tt>i</tt> or <tt>j</tt>
+     *         is out of range (i &lt; 0 || i &gt;= list.size()
+     *         || j &lt; 0 || j &gt;= list.size()).
+     * @since 1.4
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static void swap(List<?> list, int i, int j) {
+        // instead of using a raw type here, it's possible to capture
+        // the wildcard but it will require a call to a supplementary
+        // private method
+        final List l = list;
+        l.set(i, l.set(j, l.get(i)));
+    }
+
+    /**
+     * Swaps the two specified elements in the specified array.
+     */
+    private static void swap(Object[] arr, int i, int j) {
+        Object tmp = arr[i];
+        arr[i] = arr[j];
+        arr[j] = tmp;
+    }
+
+    /**
+     * Replaces all of the elements of the specified list with the specified
+     * element. <p>
+     *
+     * This method runs in linear time.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be filled with the specified element.
+     * @param  obj The element with which to fill the specified list.
+     * @throws UnsupportedOperationException if the specified list or its
+     *         list-iterator does not support the <tt>set</tt> operation.
+     */
+    public static <T> void fill(List<? super T> list, T obj) {
+        int size = list.size();
+
+        if (size < FILL_THRESHOLD || list instanceof RandomAccess) {
+            for (int i=0; i<size; i++)
+                list.set(i, obj);
+        } else {
+            ListIterator<? super T> itr = list.listIterator();
+            for (int i=0; i<size; i++) {
+                itr.next();
+                itr.set(obj);
+            }
+        }
+    }
+
+    /**
+     * Copies all of the elements from one list into another.  After the
+     * operation, the index of each copied element in the destination list
+     * will be identical to its index in the source list.  The destination
+     * list must be at least as long as the source list.  If it is longer, the
+     * remaining elements in the destination list are unaffected. <p>
+     *
+     * This method runs in linear time.
+     *
+     * @param  <T> the class of the objects in the lists
+     * @param  dest The destination list.
+     * @param  src The source list.
+     * @throws IndexOutOfBoundsException if the destination list is too small
+     *         to contain the entire source List.
+     * @throws UnsupportedOperationException if the destination list's
+     *         list-iterator does not support the <tt>set</tt> operation.
+     */
+    public static <T> void copy(List<? super T> dest, List<? extends T> src) {
+        int srcSize = src.size();
+        if (srcSize > dest.size())
+            throw new IndexOutOfBoundsException("Source does not fit in dest");
+
+        if (srcSize < COPY_THRESHOLD ||
+            (src instanceof RandomAccess && dest instanceof RandomAccess)) {
+            for (int i=0; i<srcSize; i++)
+                dest.set(i, src.get(i));
+        } else {
+            ListIterator<? super T> di=dest.listIterator();
+            ListIterator<? extends T> si=src.listIterator();
+            for (int i=0; i<srcSize; i++) {
+                di.next();
+                di.set(si.next());
+            }
+        }
+    }
+
+    /**
+     * Returns the minimum element of the given collection, according to the
+     * <i>natural ordering</i> of its elements.  All elements in the
+     * collection must implement the <tt>Comparable</tt> interface.
+     * Furthermore, all elements in the collection must be <i>mutually
+     * comparable</i> (that is, <tt>e1.compareTo(e2)</tt> must not throw a
+     * <tt>ClassCastException</tt> for any elements <tt>e1</tt> and
+     * <tt>e2</tt> in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose minimum element is to be determined.
+     * @return the minimum element of the given collection, according
+     *         to the <i>natural ordering</i> of its elements.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) {
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (next.compareTo(candidate) < 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Returns the minimum element of the given collection, according to the
+     * order induced by the specified comparator.  All elements in the
+     * collection must be <i>mutually comparable</i> by the specified
+     * comparator (that is, <tt>comp.compare(e1, e2)</tt> must not throw a
+     * <tt>ClassCastException</tt> for any elements <tt>e1</tt> and
+     * <tt>e2</tt> in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose minimum element is to be determined.
+     * @param  comp the comparator with which to determine the minimum element.
+     *         A <tt>null</tt> value indicates that the elements' <i>natural
+     *         ordering</i> should be used.
+     * @return the minimum element of the given collection, according
+     *         to the specified comparator.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator.
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) {
+        if (comp==null)
+            return (T)min((Collection) coll);
+
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (comp.compare(next, candidate) < 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Returns the maximum element of the given collection, according to the
+     * <i>natural ordering</i> of its elements.  All elements in the
+     * collection must implement the <tt>Comparable</tt> interface.
+     * Furthermore, all elements in the collection must be <i>mutually
+     * comparable</i> (that is, <tt>e1.compareTo(e2)</tt> must not throw a
+     * <tt>ClassCastException</tt> for any elements <tt>e1</tt> and
+     * <tt>e2</tt> in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose maximum element is to be determined.
+     * @return the maximum element of the given collection, according
+     *         to the <i>natural ordering</i> of its elements.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (next.compareTo(candidate) > 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Returns the maximum element of the given collection, according to the
+     * order induced by the specified comparator.  All elements in the
+     * collection must be <i>mutually comparable</i> by the specified
+     * comparator (that is, <tt>comp.compare(e1, e2)</tt> must not throw a
+     * <tt>ClassCastException</tt> for any elements <tt>e1</tt> and
+     * <tt>e2</tt> in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose maximum element is to be determined.
+     * @param  comp the comparator with which to determine the maximum element.
+     *         A <tt>null</tt> value indicates that the elements' <i>natural
+     *        ordering</i> should be used.
+     * @return the maximum element of the given collection, according
+     *         to the specified comparator.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator.
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) {
+        if (comp==null)
+            return (T)max((Collection) coll);
+
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (comp.compare(next, candidate) > 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Rotates the elements in the specified list by the specified distance.
+     * After calling this method, the element at index <tt>i</tt> will be
+     * the element previously at index <tt>(i - distance)</tt> mod
+     * <tt>list.size()</tt>, for all values of <tt>i</tt> between <tt>0</tt>
+     * and <tt>list.size()-1</tt>, inclusive.  (This method has no effect on
+     * the size of the list.)
+     *
+     * <p>For example, suppose <tt>list</tt> comprises<tt> [t, a, n, k, s]</tt>.
+     * After invoking <tt>Collections.rotate(list, 1)</tt> (or
+     * <tt>Collections.rotate(list, -4)</tt>), <tt>list</tt> will comprise
+     * <tt>[s, t, a, n, k]</tt>.
+     *
+     * <p>Note that this method can usefully be applied to sublists to
+     * move one or more elements within a list while preserving the
+     * order of the remaining elements.  For example, the following idiom
+     * moves the element at index <tt>j</tt> forward to position
+     * <tt>k</tt> (which must be greater than or equal to <tt>j</tt>):
+     * <pre>
+     *     Collections.rotate(list.subList(j, k+1), -1);
+     * </pre>
+     * To make this concrete, suppose <tt>list</tt> comprises
+     * <tt>[a, b, c, d, e]</tt>.  To move the element at index <tt>1</tt>
+     * (<tt>b</tt>) forward two positions, perform the following invocation:
+     * <pre>
+     *     Collections.rotate(l.subList(1, 4), -1);
+     * </pre>
+     * The resulting list is <tt>[a, c, d, b, e]</tt>.
+     *
+     * <p>To move more than one element forward, increase the absolute value
+     * of the rotation distance.  To move elements backward, use a positive
+     * shift distance.
+     *
+     * <p>If the specified list is small or implements the {@link
+     * RandomAccess} interface, this implementation exchanges the first
+     * element into the location it should go, and then repeatedly exchanges
+     * the displaced element into the location it should go until a displaced
+     * element is swapped into the first element.  If necessary, the process
+     * is repeated on the second and successive elements, until the rotation
+     * is complete.  If the specified list is large and doesn't implement the
+     * <tt>RandomAccess</tt> interface, this implementation breaks the
+     * list into two sublist views around index <tt>-distance mod size</tt>.
+     * Then the {@link #reverse(List)} method is invoked on each sublist view,
+     * and finally it is invoked on the entire list.  For a more complete
+     * description of both algorithms, see Section 2.3 of Jon Bentley's
+     * <i>Programming Pearls</i> (Addison-Wesley, 1986).
+     *
+     * @param list the list to be rotated.
+     * @param distance the distance to rotate the list.  There are no
+     *        constraints on this value; it may be zero, negative, or
+     *        greater than <tt>list.size()</tt>.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the <tt>set</tt> operation.
+     * @since 1.4
+     */
+    public static void rotate(List<?> list, int distance) {
+        if (list instanceof RandomAccess || list.size() < ROTATE_THRESHOLD)
+            rotate1(list, distance);
+        else
+            rotate2(list, distance);
+    }
+
+    private static <T> void rotate1(List<T> list, int distance) {
+        int size = list.size();
+        if (size == 0)
+            return;
+        distance = distance % size;
+        if (distance < 0)
+            distance += size;
+        if (distance == 0)
+            return;
+
+        for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) {
+            T displaced = list.get(cycleStart);
+            int i = cycleStart;
+            do {
+                i += distance;
+                if (i >= size)
+                    i -= size;
+                displaced = list.set(i, displaced);
+                nMoved ++;
+            } while (i != cycleStart);
+        }
+    }
+
+    private static void rotate2(List<?> list, int distance) {
+        int size = list.size();
+        if (size == 0)
+            return;
+        int mid =  -distance % size;
+        if (mid < 0)
+            mid += size;
+        if (mid == 0)
+            return;
+
+        reverse(list.subList(0, mid));
+        reverse(list.subList(mid, size));
+        reverse(list);
+    }
+
+    /**
+     * Replaces all occurrences of one specified value in a list with another.
+     * More formally, replaces with <tt>newVal</tt> each element <tt>e</tt>
+     * in <tt>list</tt> such that
+     * <tt>(oldVal==null ? e==null : oldVal.equals(e))</tt>.
+     * (This method has no effect on the size of the list.)
+     *
+     * @param  <T> the class of the objects in the list
+     * @param list the list in which replacement is to occur.
+     * @param oldVal the old value to be replaced.
+     * @param newVal the new value with which <tt>oldVal</tt> is to be
+     *        replaced.
+     * @return <tt>true</tt> if <tt>list</tt> contained one or more elements
+     *         <tt>e</tt> such that
+     *         <tt>(oldVal==null ?  e==null : oldVal.equals(e))</tt>.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the <tt>set</tt> operation.
+     * @since  1.4
+     */
+    public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) {
+        boolean result = false;
+        int size = list.size();
+        if (size < REPLACEALL_THRESHOLD || list instanceof RandomAccess) {
+            if (oldVal==null) {
+                for (int i=0; i<size; i++) {
+                    if (list.get(i)==null) {
+                        list.set(i, newVal);
+                        result = true;
+                    }
+                }
+            } else {
+                for (int i=0; i<size; i++) {
+                    if (oldVal.equals(list.get(i))) {
+                        list.set(i, newVal);
+                        result = true;
+                    }
+                }
+            }
+        } else {
+            ListIterator<T> itr=list.listIterator();
+            if (oldVal==null) {
+                for (int i=0; i<size; i++) {
+                    if (itr.next()==null) {
+                        itr.set(newVal);
+                        result = true;
+                    }
+                }
+            } else {
+                for (int i=0; i<size; i++) {
+                    if (oldVal.equals(itr.next())) {
+                        itr.set(newVal);
+                        result = true;
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the starting position of the first occurrence of the specified
+     * target list within the specified source list, or -1 if there is no
+     * such occurrence.  More formally, returns the lowest index <tt>i</tt>
+     * such that {@code source.subList(i, i+target.size()).equals(target)},
+     * or -1 if there is no such index.  (Returns -1 if
+     * {@code target.size() > source.size()})
+     *
+     * <p>This implementation uses the "brute force" technique of scanning
+     * over the source list, looking for a match with the target at each
+     * location in turn.
+     *
+     * @param source the list in which to search for the first occurrence
+     *        of <tt>target</tt>.
+     * @param target the list to search for as a subList of <tt>source</tt>.
+     * @return the starting position of the first occurrence of the specified
+     *         target list within the specified source list, or -1 if there
+     *         is no such occurrence.
+     * @since  1.4
+     */
+    public static int indexOfSubList(List<?> source, List<?> target) {
+        int sourceSize = source.size();
+        int targetSize = target.size();
+        int maxCandidate = sourceSize - targetSize;
+
+        if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
+            (source instanceof RandomAccess&&target instanceof RandomAccess)) {
+        nextCand:
+            for (int candidate = 0; candidate <= maxCandidate; candidate++) {
+                for (int i=0, j=candidate; i<targetSize; i++, j++)
+                    if (!eq(target.get(i), source.get(j)))
+                        continue nextCand;  // Element mismatch, try next cand
+                return candidate;  // All elements of candidate matched target
+            }
+        } else {  // Iterator version of above algorithm
+            ListIterator<?> si = source.listIterator();
+        nextCand:
+            for (int candidate = 0; candidate <= maxCandidate; candidate++) {
+                ListIterator<?> ti = target.listIterator();
+                for (int i=0; i<targetSize; i++) {
+                    if (!eq(ti.next(), si.next())) {
+                        // Back up source iterator to next candidate
+                        for (int j=0; j<i; j++)
+                            si.previous();
+                        continue nextCand;
+                    }
+                }
+                return candidate;
+            }
+        }
+        return -1;  // No candidate matched the target
+    }
+
+    /**
+     * Returns the starting position of the last occurrence of the specified
+     * target list within the specified source list, or -1 if there is no such
+     * occurrence.  More formally, returns the highest index <tt>i</tt>
+     * such that {@code source.subList(i, i+target.size()).equals(target)},
+     * or -1 if there is no such index.  (Returns -1 if
+     * {@code target.size() > source.size()})
+     *
+     * <p>This implementation uses the "brute force" technique of iterating
+     * over the source list, looking for a match with the target at each
+     * location in turn.
+     *
+     * @param source the list in which to search for the last occurrence
+     *        of <tt>target</tt>.
+     * @param target the list to search for as a subList of <tt>source</tt>.
+     * @return the starting position of the last occurrence of the specified
+     *         target list within the specified source list, or -1 if there
+     *         is no such occurrence.
+     * @since  1.4
+     */
+    public static int lastIndexOfSubList(List<?> source, List<?> target) {
+        int sourceSize = source.size();
+        int targetSize = target.size();
+        int maxCandidate = sourceSize - targetSize;
+
+        if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
+            source instanceof RandomAccess) {   // Index access version
+        nextCand:
+            for (int candidate = maxCandidate; candidate >= 0; candidate--) {
+                for (int i=0, j=candidate; i<targetSize; i++, j++)
+                    if (!eq(target.get(i), source.get(j)))
+                        continue nextCand;  // Element mismatch, try next cand
+                return candidate;  // All elements of candidate matched target
+            }
+        } else {  // Iterator version of above algorithm
+            if (maxCandidate < 0)
+                return -1;
+            ListIterator<?> si = source.listIterator(maxCandidate);
+        nextCand:
+            for (int candidate = maxCandidate; candidate >= 0; candidate--) {
+                ListIterator<?> ti = target.listIterator();
+                for (int i=0; i<targetSize; i++) {
+                    if (!eq(ti.next(), si.next())) {
+                        if (candidate != 0) {
+                            // Back up source iterator to next candidate
+                            for (int j=0; j<=i+1; j++)
+                                si.previous();
+                        }
+                        continue nextCand;
+                    }
+                }
+                return candidate;
+            }
+        }
+        return -1;  // No candidate matched the target
+    }
+
+
+    // Unmodifiable Wrappers
+
+    /**
+     * Returns an unmodifiable view of the specified collection.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * collections.  Query operations on the returned collection "read through"
+     * to the specified collection, and attempts to modify the returned
+     * collection, whether direct or via its iterator, result in an
+     * <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned collection does <i>not</i> pass the hashCode and equals
+     * operations through to the backing collection, but relies on
+     * <tt>Object</tt>'s <tt>equals</tt> and <tt>hashCode</tt> methods.  This
+     * is necessary to preserve the contracts of these operations in the case
+     * that the backing collection is a set or a list.<p>
+     *
+     * The returned collection will be serializable if the specified collection
+     * is serializable.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  c the collection for which an unmodifiable view is to be
+     *         returned.
+     * @return an unmodifiable view of the specified collection.
+     */
+    public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) {
+        return new UnmodifiableCollection<>(c);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableCollection<E> implements Collection<E>, Serializable {
+        private static final long serialVersionUID = 1820017752578914078L;
+
+        final Collection<? extends E> c;
+
+        UnmodifiableCollection(Collection<? extends E> c) {
+            if (c==null)
+                throw new NullPointerException();
+            this.c = c;
+        }
+
+        public int size()                   {return c.size();}
+        public boolean isEmpty()            {return c.isEmpty();}
+        public boolean contains(Object o)   {return c.contains(o);}
+        public Object[] toArray()           {return c.toArray();}
+        public <T> T[] toArray(T[] a)       {return c.toArray(a);}
+        public String toString()            {return c.toString();}
+
+        public Iterator<E> iterator() {
+            return new Iterator<E>() {
+                private final Iterator<? extends E> i = c.iterator();
+
+                public boolean hasNext() {return i.hasNext();}
+                public E next()          {return i.next();}
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+                @Override
+                public void forEachRemaining(Consumer<? super E> action) {
+                    // Use backing collection version
+                    i.forEachRemaining(action);
+                }
+            };
+        }
+
+        public boolean add(E e) {
+            throw new UnsupportedOperationException();
+        }
+        public boolean remove(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean containsAll(Collection<?> coll) {
+            return c.containsAll(coll);
+        }
+        public boolean addAll(Collection<? extends E> coll) {
+            throw new UnsupportedOperationException();
+        }
+        public boolean removeAll(Collection<?> coll) {
+            throw new UnsupportedOperationException();
+        }
+        public boolean retainAll(Collection<?> coll) {
+            throw new UnsupportedOperationException();
+        }
+        public void clear() {
+            throw new UnsupportedOperationException();
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            c.forEach(action);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            throw new UnsupportedOperationException();
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public Spliterator<E> spliterator() {
+            return (Spliterator<E>)c.spliterator();
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public Stream<E> stream() {
+            return (Stream<E>)c.stream();
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public Stream<E> parallelStream() {
+            return (Stream<E>)c.parallelStream();
+        }
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified set.  This method allows
+     * modules to provide users with "read-only" access to internal sets.
+     * Query operations on the returned set "read through" to the specified
+     * set, and attempts to modify the returned set, whether direct or via its
+     * iterator, result in an <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned set will be serializable if the specified set
+     * is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param  s the set for which an unmodifiable view is to be returned.
+     * @return an unmodifiable view of the specified set.
+     */
+    public static <T> Set<T> unmodifiableSet(Set<? extends T> s) {
+        return new UnmodifiableSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableSet<E> extends UnmodifiableCollection<E>
+                                 implements Set<E>, Serializable {
+        private static final long serialVersionUID = -9215047833775013803L;
+
+        UnmodifiableSet(Set<? extends E> s)     {super(s);}
+        public boolean equals(Object o) {return o == this || c.equals(o);}
+        public int hashCode()           {return c.hashCode();}
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified sorted set.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * sorted sets.  Query operations on the returned sorted set "read
+     * through" to the specified sorted set.  Attempts to modify the returned
+     * sorted set, whether direct, via its iterator, or via its
+     * <tt>subSet</tt>, <tt>headSet</tt>, or <tt>tailSet</tt> views, result in
+     * an <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned sorted set will be serializable if the specified sorted set
+     * is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param s the sorted set for which an unmodifiable view is to be
+     *        returned.
+     * @return an unmodifiable view of the specified sorted set.
+     */
+    public static <T> SortedSet<T> unmodifiableSortedSet(SortedSet<T> s) {
+        return new UnmodifiableSortedSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableSortedSet<E>
+                             extends UnmodifiableSet<E>
+                             implements SortedSet<E>, Serializable {
+        private static final long serialVersionUID = -4929149591599911165L;
+        private final SortedSet<E> ss;
+
+        UnmodifiableSortedSet(SortedSet<E> s) {super(s); ss = s;}
+
+        public Comparator<? super E> comparator() {return ss.comparator();}
+
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            return new UnmodifiableSortedSet<>(ss.subSet(fromElement,toElement));
+        }
+        public SortedSet<E> headSet(E toElement) {
+            return new UnmodifiableSortedSet<>(ss.headSet(toElement));
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            return new UnmodifiableSortedSet<>(ss.tailSet(fromElement));
+        }
+
+        public E first()                   {return ss.first();}
+        public E last()                    {return ss.last();}
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified navigable set.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * navigable sets.  Query operations on the returned navigable set "read
+     * through" to the specified navigable set.  Attempts to modify the returned
+     * navigable set, whether direct, via its iterator, or via its
+     * {@code subSet}, {@code headSet}, or {@code tailSet} views, result in
+     * an {@code UnsupportedOperationException}.<p>
+     *
+     * The returned navigable set will be serializable if the specified
+     * navigable set is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param s the navigable set for which an unmodifiable view is to be
+     *        returned
+     * @return an unmodifiable view of the specified navigable set
+     * @since 1.8
+     */
+    public static <T> NavigableSet<T> unmodifiableNavigableSet(NavigableSet<T> s) {
+        return new UnmodifiableNavigableSet<>(s);
+    }
+
+    /**
+     * Wraps a navigable set and disables all of the mutative operations.
+     *
+     * @param <E> type of elements
+     * @serial include
+     */
+    static class UnmodifiableNavigableSet<E>
+                             extends UnmodifiableSortedSet<E>
+                             implements NavigableSet<E>, Serializable {
+
+        private static final long serialVersionUID = -6027448201786391929L;
+
+        /**
+         * A singleton empty unmodifiable navigable set used for
+         * {@link #emptyNavigableSet()}.
+         *
+         * @param <E> type of elements, if there were any, and bounds
+         */
+        private static class EmptyNavigableSet<E> extends UnmodifiableNavigableSet<E>
+            implements Serializable {
+            private static final long serialVersionUID = -6291252904449939134L;
+
+            public EmptyNavigableSet() {
+                super(new TreeSet<E>());
+            }
+
+            private Object readResolve()        { return EMPTY_NAVIGABLE_SET; }
+        }
+
+        @SuppressWarnings("rawtypes")
+        private static final NavigableSet<?> EMPTY_NAVIGABLE_SET =
+                new EmptyNavigableSet<>();
+
+        /**
+         * The instance we are protecting.
+         */
+        private final NavigableSet<E> ns;
+
+        UnmodifiableNavigableSet(NavigableSet<E> s)         {super(s); ns = s;}
+
+        public E lower(E e)                             { return ns.lower(e); }
+        public E floor(E e)                             { return ns.floor(e); }
+        public E ceiling(E e)                         { return ns.ceiling(e); }
+        public E higher(E e)                           { return ns.higher(e); }
+        public E pollFirst()     { throw new UnsupportedOperationException(); }
+        public E pollLast()      { throw new UnsupportedOperationException(); }
+        public NavigableSet<E> descendingSet()
+                 { return new UnmodifiableNavigableSet<>(ns.descendingSet()); }
+        public Iterator<E> descendingIterator()
+                                         { return descendingSet().iterator(); }
+
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+            return new UnmodifiableNavigableSet<>(
+                ns.subSet(fromElement, fromInclusive, toElement, toInclusive));
+        }
+
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            return new UnmodifiableNavigableSet<>(
+                ns.headSet(toElement, inclusive));
+        }
+
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            return new UnmodifiableNavigableSet<>(
+                ns.tailSet(fromElement, inclusive));
+        }
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified list.  This method allows
+     * modules to provide users with "read-only" access to internal
+     * lists.  Query operations on the returned list "read through" to the
+     * specified list, and attempts to modify the returned list, whether
+     * direct or via its iterator, result in an
+     * <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned list will be serializable if the specified list
+     * is serializable. Similarly, the returned list will implement
+     * {@link RandomAccess} if the specified list does.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list for which an unmodifiable view is to be returned.
+     * @return an unmodifiable view of the specified list.
+     */
+    public static <T> List<T> unmodifiableList(List<? extends T> list) {
+        return (list instanceof RandomAccess ?
+                new UnmodifiableRandomAccessList<>(list) :
+                new UnmodifiableList<>(list));
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableList<E> extends UnmodifiableCollection<E>
+                                  implements List<E> {
+        private static final long serialVersionUID = -283967356065247728L;
+
+        final List<? extends E> list;
+
+        UnmodifiableList(List<? extends E> list) {
+            super(list);
+            this.list = list;
+        }
+
+        public boolean equals(Object o) {return o == this || list.equals(o);}
+        public int hashCode()           {return list.hashCode();}
+
+        public E get(int index) {return list.get(index);}
+        public E set(int index, E element) {
+            throw new UnsupportedOperationException();
+        }
+        public void add(int index, E element) {
+            throw new UnsupportedOperationException();
+        }
+        public E remove(int index) {
+            throw new UnsupportedOperationException();
+        }
+        public int indexOf(Object o)            {return list.indexOf(o);}
+        public int lastIndexOf(Object o)        {return list.lastIndexOf(o);}
+        public boolean addAll(int index, Collection<? extends E> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public ListIterator<E> listIterator()   {return listIterator(0);}
+
+        public ListIterator<E> listIterator(final int index) {
+            return new ListIterator<E>() {
+                private final ListIterator<? extends E> i
+                    = list.listIterator(index);
+
+                public boolean hasNext()     {return i.hasNext();}
+                public E next()              {return i.next();}
+                public boolean hasPrevious() {return i.hasPrevious();}
+                public E previous()          {return i.previous();}
+                public int nextIndex()       {return i.nextIndex();}
+                public int previousIndex()   {return i.previousIndex();}
+
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+                public void set(E e) {
+                    throw new UnsupportedOperationException();
+                }
+                public void add(E e) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public void forEachRemaining(Consumer<? super E> action) {
+                    i.forEachRemaining(action);
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new UnmodifiableList<>(list.subList(fromIndex, toIndex));
+        }
+
+        /**
+         * UnmodifiableRandomAccessList instances are serialized as
+         * UnmodifiableList instances to allow them to be deserialized
+         * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList).
+         * This method inverts the transformation.  As a beneficial
+         * side-effect, it also grafts the RandomAccess marker onto
+         * UnmodifiableList instances that were serialized in pre-1.4 JREs.
+         *
+         * Note: Unfortunately, UnmodifiableRandomAccessList instances
+         * serialized in 1.4.1 and deserialized in 1.4 will become
+         * UnmodifiableList instances, as this method was missing in 1.4.
+         */
+        private Object readResolve() {
+            return (list instanceof RandomAccess
+                    ? new UnmodifiableRandomAccessList<>(list)
+                    : this);
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableRandomAccessList<E> extends UnmodifiableList<E>
+                                              implements RandomAccess
+    {
+        UnmodifiableRandomAccessList(List<? extends E> list) {
+            super(list);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new UnmodifiableRandomAccessList<>(
+                list.subList(fromIndex, toIndex));
+        }
+
+        private static final long serialVersionUID = -2542308836966382001L;
+
+        /**
+         * Allows instances to be deserialized in pre-1.4 JREs (which do
+         * not have UnmodifiableRandomAccessList).  UnmodifiableList has
+         * a readResolve method that inverts this transformation upon
+         * deserialization.
+         */
+        private Object writeReplace() {
+            return new UnmodifiableList<>(list);
+        }
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified map.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * maps.  Query operations on the returned map "read through"
+     * to the specified map, and attempts to modify the returned
+     * map, whether direct or via its collection views, result in an
+     * <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned map will be serializable if the specified map
+     * is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the map for which an unmodifiable view is to be returned.
+     * @return an unmodifiable view of the specified map.
+     */
+    public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
+        return new UnmodifiableMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class UnmodifiableMap<K,V> implements Map<K,V>, Serializable {
+        private static final long serialVersionUID = -1034234728574286014L;
+
+        private final Map<? extends K, ? extends V> m;
+
+        UnmodifiableMap(Map<? extends K, ? extends V> m) {
+            if (m==null)
+                throw new NullPointerException();
+            this.m = m;
+        }
+
+        public int size()                        {return m.size();}
+        public boolean isEmpty()                 {return m.isEmpty();}
+        public boolean containsKey(Object key)   {return m.containsKey(key);}
+        public boolean containsValue(Object val) {return m.containsValue(val);}
+        public V get(Object key)                 {return m.get(key);}
+
+        public V put(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+        public V remove(Object key) {
+            throw new UnsupportedOperationException();
+        }
+        public void putAll(Map<? extends K, ? extends V> m) {
+            throw new UnsupportedOperationException();
+        }
+        public void clear() {
+            throw new UnsupportedOperationException();
+        }
+
+        private transient Set<K> keySet;
+        private transient Set<Map.Entry<K,V>> entrySet;
+        private transient Collection<V> values;
+
+        public Set<K> keySet() {
+            if (keySet==null)
+                keySet = unmodifiableSet(m.keySet());
+            return keySet;
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            if (entrySet==null)
+                entrySet = new UnmodifiableEntrySet<>(m.entrySet());
+            return entrySet;
+        }
+
+        public Collection<V> values() {
+            if (values==null)
+                values = unmodifiableCollection(m.values());
+            return values;
+        }
+
+        public boolean equals(Object o) {return o == this || m.equals(o);}
+        public int hashCode()           {return m.hashCode();}
+        public String toString()        {return m.toString();}
+
+        // Override default methods in Map
+        @Override
+        @SuppressWarnings("unchecked")
+        public V getOrDefault(Object k, V defaultValue) {
+            // Safe cast as we don't change the value
+            return ((Map<K, V>)m).getOrDefault(k, defaultValue);
+        }
+
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            m.forEach(action);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * We need this class in addition to UnmodifiableSet as
+         * Map.Entries themselves permit modification of the backing Map
+         * via their setValue operation.  This class is subtle: there are
+         * many possible attacks that must be thwarted.
+         *
+         * @serial include
+         */
+        static class UnmodifiableEntrySet<K,V>
+            extends UnmodifiableSet<Map.Entry<K,V>> {
+            private static final long serialVersionUID = 7854390611657943733L;
+
+            @SuppressWarnings({"unchecked", "rawtypes"})
+            UnmodifiableEntrySet(Set<? extends Map.Entry<? extends K, ? extends V>> s) {
+                // Need to cast to raw in order to work around a limitation in the type system
+                super((Set)s);
+            }
+
+            static <K, V> Consumer<Map.Entry<K, V>> entryConsumer(Consumer<? super Entry<K, V>> action) {
+                return e -> action.accept(new UnmodifiableEntry<>(e));
+            }
+
+            public void forEach(Consumer<? super Entry<K, V>> action) {
+                Objects.requireNonNull(action);
+                c.forEach(entryConsumer(action));
+            }
+
+            static final class UnmodifiableEntrySetSpliterator<K, V>
+                    implements Spliterator<Entry<K,V>> {
+                final Spliterator<Map.Entry<K, V>> s;
+
+                UnmodifiableEntrySetSpliterator(Spliterator<Entry<K, V>> s) {
+                    this.s = s;
+                }
+
+                @Override
+                public boolean tryAdvance(Consumer<? super Entry<K, V>> action) {
+                    Objects.requireNonNull(action);
+                    return s.tryAdvance(entryConsumer(action));
+                }
+
+                @Override
+                public void forEachRemaining(Consumer<? super Entry<K, V>> action) {
+                    Objects.requireNonNull(action);
+                    s.forEachRemaining(entryConsumer(action));
+                }
+
+                @Override
+                public Spliterator<Entry<K, V>> trySplit() {
+                    Spliterator<Entry<K, V>> split = s.trySplit();
+                    return split == null
+                           ? null
+                           : new UnmodifiableEntrySetSpliterator<>(split);
+                }
+
+                @Override
+                public long estimateSize() {
+                    return s.estimateSize();
+                }
+
+                @Override
+                public long getExactSizeIfKnown() {
+                    return s.getExactSizeIfKnown();
+                }
+
+                @Override
+                public int characteristics() {
+                    return s.characteristics();
+                }
+
+                @Override
+                public boolean hasCharacteristics(int characteristics) {
+                    return s.hasCharacteristics(characteristics);
+                }
+
+                @Override
+                public Comparator<? super Entry<K, V>> getComparator() {
+                    return s.getComparator();
+                }
+            }
+
+            @SuppressWarnings("unchecked")
+            public Spliterator<Entry<K,V>> spliterator() {
+                return new UnmodifiableEntrySetSpliterator<>(
+                        (Spliterator<Map.Entry<K, V>>) c.spliterator());
+            }
+
+            @Override
+            public Stream<Entry<K,V>> stream() {
+                return StreamSupport.stream(spliterator(), false);
+            }
+
+            @Override
+            public Stream<Entry<K,V>> parallelStream() {
+                return StreamSupport.stream(spliterator(), true);
+            }
+
+            public Iterator<Map.Entry<K,V>> iterator() {
+                return new Iterator<Map.Entry<K,V>>() {
+                    private final Iterator<? extends Map.Entry<? extends K, ? extends V>> i = c.iterator();
+
+                    public boolean hasNext() {
+                        return i.hasNext();
+                    }
+                    public Map.Entry<K,V> next() {
+                        return new UnmodifiableEntry<>(i.next());
+                    }
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                    // Android-note: Oversight of Iterator.forEachRemaining().
+                    // This seems pretty inconsistent. Unlike other subclasses,
+                    // we aren't delegating to the subclass iterator here.
+                    // Seems like an oversight. http://b/110351017
+                };
+            }
+
+            @SuppressWarnings("unchecked")
+            public Object[] toArray() {
+                Object[] a = c.toArray();
+                for (int i=0; i<a.length; i++)
+                    a[i] = new UnmodifiableEntry<>((Map.Entry<? extends K, ? extends V>)a[i]);
+                return a;
+            }
+
+            @SuppressWarnings("unchecked")
+            public <T> T[] toArray(T[] a) {
+                // We don't pass a to c.toArray, to avoid window of
+                // vulnerability wherein an unscrupulous multithreaded client
+                // could get his hands on raw (unwrapped) Entries from c.
+                Object[] arr = c.toArray(a.length==0 ? a : Arrays.copyOf(a, 0));
+
+                for (int i=0; i<arr.length; i++)
+                    arr[i] = new UnmodifiableEntry<>((Map.Entry<? extends K, ? extends V>)arr[i]);
+
+                if (arr.length > a.length)
+                    return (T[])arr;
+
+                System.arraycopy(arr, 0, a, 0, arr.length);
+                if (a.length > arr.length)
+                    a[arr.length] = null;
+                return a;
+            }
+
+            /**
+             * This method is overridden to protect the backing set against
+             * an object with a nefarious equals function that senses
+             * that the equality-candidate is Map.Entry and calls its
+             * setValue method.
+             */
+            public boolean contains(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                return c.contains(
+                    new UnmodifiableEntry<>((Map.Entry<?,?>) o));
+            }
+
+            /**
+             * The next two methods are overridden to protect against
+             * an unscrupulous List whose contains(Object o) method senses
+             * when o is a Map.Entry, and calls o.setValue.
+             */
+            public boolean containsAll(Collection<?> coll) {
+                for (Object e : coll) {
+                    if (!contains(e)) // Invokes safe contains() above
+                        return false;
+                }
+                return true;
+            }
+            public boolean equals(Object o) {
+                if (o == this)
+                    return true;
+
+                if (!(o instanceof Set))
+                    return false;
+                Set<?> s = (Set<?>) o;
+                if (s.size() != c.size())
+                    return false;
+                return containsAll(s); // Invokes safe containsAll() above
+            }
+
+            /**
+             * This "wrapper class" serves two purposes: it prevents
+             * the client from modifying the backing Map, by short-circuiting
+             * the setValue method, and it protects the backing Map against
+             * an ill-behaved Map.Entry that attempts to modify another
+             * Map Entry when asked to perform an equality check.
+             */
+            private static class UnmodifiableEntry<K,V> implements Map.Entry<K,V> {
+                private Map.Entry<? extends K, ? extends V> e;
+
+                UnmodifiableEntry(Map.Entry<? extends K, ? extends V> e)
+                        {this.e = Objects.requireNonNull(e);}
+
+                public K getKey()        {return e.getKey();}
+                public V getValue()      {return e.getValue();}
+                public V setValue(V value) {
+                    throw new UnsupportedOperationException();
+                }
+                public int hashCode()    {return e.hashCode();}
+                public boolean equals(Object o) {
+                    if (this == o)
+                        return true;
+                    if (!(o instanceof Map.Entry))
+                        return false;
+                    Map.Entry<?,?> t = (Map.Entry<?,?>)o;
+                    return eq(e.getKey(),   t.getKey()) &&
+                           eq(e.getValue(), t.getValue());
+                }
+                public String toString() {return e.toString();}
+            }
+        }
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified sorted map.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * sorted maps.  Query operations on the returned sorted map "read through"
+     * to the specified sorted map.  Attempts to modify the returned
+     * sorted map, whether direct, via its collection views, or via its
+     * <tt>subMap</tt>, <tt>headMap</tt>, or <tt>tailMap</tt> views, result in
+     * an <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned sorted map will be serializable if the specified sorted map
+     * is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the sorted map for which an unmodifiable view is to be
+     *        returned.
+     * @return an unmodifiable view of the specified sorted map.
+     */
+    public static <K,V> SortedMap<K,V> unmodifiableSortedMap(SortedMap<K, ? extends V> m) {
+        return new UnmodifiableSortedMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableSortedMap<K,V>
+          extends UnmodifiableMap<K,V>
+          implements SortedMap<K,V>, Serializable {
+        private static final long serialVersionUID = -8806743815996713206L;
+
+        private final SortedMap<K, ? extends V> sm;
+
+        UnmodifiableSortedMap(SortedMap<K, ? extends V> m) {super(m); sm = m; }
+        public Comparator<? super K> comparator()   { return sm.comparator(); }
+        public SortedMap<K,V> subMap(K fromKey, K toKey)
+             { return new UnmodifiableSortedMap<>(sm.subMap(fromKey, toKey)); }
+        public SortedMap<K,V> headMap(K toKey)
+                     { return new UnmodifiableSortedMap<>(sm.headMap(toKey)); }
+        public SortedMap<K,V> tailMap(K fromKey)
+                   { return new UnmodifiableSortedMap<>(sm.tailMap(fromKey)); }
+        public K firstKey()                           { return sm.firstKey(); }
+        public K lastKey()                             { return sm.lastKey(); }
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified navigable map.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * navigable maps.  Query operations on the returned navigable map "read
+     * through" to the specified navigable map.  Attempts to modify the returned
+     * navigable map, whether direct, via its collection views, or via its
+     * {@code subMap}, {@code headMap}, or {@code tailMap} views, result in
+     * an {@code UnsupportedOperationException}.<p>
+     *
+     * The returned navigable map will be serializable if the specified
+     * navigable map is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the navigable map for which an unmodifiable view is to be
+     *        returned
+     * @return an unmodifiable view of the specified navigable map
+     * @since 1.8
+     */
+    public static <K,V> NavigableMap<K,V> unmodifiableNavigableMap(NavigableMap<K, ? extends V> m) {
+        return new UnmodifiableNavigableMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableNavigableMap<K,V>
+          extends UnmodifiableSortedMap<K,V>
+          implements NavigableMap<K,V>, Serializable {
+        private static final long serialVersionUID = -4858195264774772197L;
+
+        /**
+         * A class for the {@link EMPTY_NAVIGABLE_MAP} which needs readResolve
+         * to preserve singleton property.
+         *
+         * @param <K> type of keys, if there were any, and of bounds
+         * @param <V> type of values, if there were any
+         */
+        private static class EmptyNavigableMap<K,V> extends UnmodifiableNavigableMap<K,V>
+            implements Serializable {
+
+            private static final long serialVersionUID = -2239321462712562324L;
+
+            EmptyNavigableMap()                       { super(new TreeMap<K,V>()); }
+
+            @Override
+            public NavigableSet<K> navigableKeySet()
+                                                { return emptyNavigableSet(); }
+
+            private Object readResolve()        { return EMPTY_NAVIGABLE_MAP; }
+        }
+
+        /**
+         * Singleton for {@link emptyNavigableMap()} which is also immutable.
+         */
+        private static final EmptyNavigableMap<?,?> EMPTY_NAVIGABLE_MAP =
+            new EmptyNavigableMap<>();
+
+        /**
+         * The instance we wrap and protect.
+         */
+        private final NavigableMap<K, ? extends V> nm;
+
+        UnmodifiableNavigableMap(NavigableMap<K, ? extends V> m)
+                                                            {super(m); nm = m;}
+
+        public K lowerKey(K key)                   { return nm.lowerKey(key); }
+        public K floorKey(K key)                   { return nm.floorKey(key); }
+        public K ceilingKey(K key)               { return nm.ceilingKey(key); }
+        public K higherKey(K key)                 { return nm.higherKey(key); }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> lowerEntry(K key) {
+            Entry<K,V> lower = (Entry<K, V>) nm.lowerEntry(key);
+            return (null != lower)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(lower)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> floorEntry(K key) {
+            Entry<K,V> floor = (Entry<K, V>) nm.floorEntry(key);
+            return (null != floor)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(floor)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> ceilingEntry(K key) {
+            Entry<K,V> ceiling = (Entry<K, V>) nm.ceilingEntry(key);
+            return (null != ceiling)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(ceiling)
+                : null;
+        }
+
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> higherEntry(K key) {
+            Entry<K,V> higher = (Entry<K, V>) nm.higherEntry(key);
+            return (null != higher)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(higher)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> firstEntry() {
+            Entry<K,V> first = (Entry<K, V>) nm.firstEntry();
+            return (null != first)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(first)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> lastEntry() {
+            Entry<K,V> last = (Entry<K, V>) nm.lastEntry();
+            return (null != last)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(last)
+                : null;
+        }
+
+        public Entry<K, V> pollFirstEntry()
+                                 { throw new UnsupportedOperationException(); }
+        public Entry<K, V> pollLastEntry()
+                                 { throw new UnsupportedOperationException(); }
+        public NavigableMap<K, V> descendingMap()
+                       { return unmodifiableNavigableMap(nm.descendingMap()); }
+        public NavigableSet<K> navigableKeySet()
+                     { return unmodifiableNavigableSet(nm.navigableKeySet()); }
+        public NavigableSet<K> descendingKeySet()
+                    { return unmodifiableNavigableSet(nm.descendingKeySet()); }
+
+        public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+            return unmodifiableNavigableMap(
+                nm.subMap(fromKey, fromInclusive, toKey, toInclusive));
+        }
+
+        public NavigableMap<K, V> headMap(K toKey, boolean inclusive)
+             { return unmodifiableNavigableMap(nm.headMap(toKey, inclusive)); }
+        public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive)
+           { return unmodifiableNavigableMap(nm.tailMap(fromKey, inclusive)); }
+    }
+
+    // Synch Wrappers
+
+    /**
+     * Returns a synchronized (thread-safe) collection backed by the specified
+     * collection.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing collection is accomplished
+     * through the returned collection.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * collection when traversing it via {@link Iterator}, {@link Spliterator}
+     * or {@link Stream}:
+     * <pre>
+     *  Collection c = Collections.synchronizedCollection(myCollection);
+     *     ...
+     *  synchronized (c) {
+     *      Iterator i = c.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *         foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned collection does <i>not</i> pass the {@code hashCode}
+     * and {@code equals} operations through to the backing collection, but
+     * relies on {@code Object}'s equals and hashCode methods.  This is
+     * necessary to preserve the contracts of these operations in the case
+     * that the backing collection is a set or a list.<p>
+     *
+     * The returned collection will be serializable if the specified collection
+     * is serializable.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  c the collection to be "wrapped" in a synchronized collection.
+     * @return a synchronized view of the specified collection.
+     */
+    public static <T> Collection<T> synchronizedCollection(Collection<T> c) {
+        return new SynchronizedCollection<>(c);
+    }
+
+    static <T> Collection<T> synchronizedCollection(Collection<T> c, Object mutex) {
+        return new SynchronizedCollection<>(c, mutex);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedCollection<E> implements Collection<E>, Serializable {
+        private static final long serialVersionUID = 3053995032091335093L;
+
+        final Collection<E> c;  // Backing Collection
+        final Object mutex;     // Object on which to synchronize
+
+        SynchronizedCollection(Collection<E> c) {
+            this.c = Objects.requireNonNull(c);
+            mutex = this;
+        }
+
+        SynchronizedCollection(Collection<E> c, Object mutex) {
+            this.c = Objects.requireNonNull(c);
+            this.mutex = Objects.requireNonNull(mutex);
+        }
+
+        public int size() {
+            synchronized (mutex) {return c.size();}
+        }
+        public boolean isEmpty() {
+            synchronized (mutex) {return c.isEmpty();}
+        }
+        public boolean contains(Object o) {
+            synchronized (mutex) {return c.contains(o);}
+        }
+        public Object[] toArray() {
+            synchronized (mutex) {return c.toArray();}
+        }
+        public <T> T[] toArray(T[] a) {
+            synchronized (mutex) {return c.toArray(a);}
+        }
+
+        public Iterator<E> iterator() {
+            return c.iterator(); // Must be manually synched by user!
+        }
+
+        public boolean add(E e) {
+            synchronized (mutex) {return c.add(e);}
+        }
+        public boolean remove(Object o) {
+            synchronized (mutex) {return c.remove(o);}
+        }
+
+        public boolean containsAll(Collection<?> coll) {
+            synchronized (mutex) {return c.containsAll(coll);}
+        }
+        public boolean addAll(Collection<? extends E> coll) {
+            synchronized (mutex) {return c.addAll(coll);}
+        }
+        public boolean removeAll(Collection<?> coll) {
+            synchronized (mutex) {return c.removeAll(coll);}
+        }
+        public boolean retainAll(Collection<?> coll) {
+            synchronized (mutex) {return c.retainAll(coll);}
+        }
+        public void clear() {
+            synchronized (mutex) {c.clear();}
+        }
+        public String toString() {
+            synchronized (mutex) {return c.toString();}
+        }
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> consumer) {
+            synchronized (mutex) {c.forEach(consumer);}
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            synchronized (mutex) {return c.removeIf(filter);}
+        }
+        @Override
+        public Spliterator<E> spliterator() {
+            return c.spliterator(); // Must be manually synched by user!
+        }
+        @Override
+        public Stream<E> stream() {
+            return c.stream(); // Must be manually synched by user!
+        }
+        @Override
+        public Stream<E> parallelStream() {
+            return c.parallelStream(); // Must be manually synched by user!
+        }
+        private void writeObject(ObjectOutputStream s) throws IOException {
+            synchronized (mutex) {s.defaultWriteObject();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) set backed by the specified
+     * set.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing set is accomplished
+     * through the returned set.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * set when iterating over it:
+     * <pre>
+     *  Set s = Collections.synchronizedSet(new HashSet());
+     *      ...
+     *  synchronized (s) {
+     *      Iterator i = s.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned set will be serializable if the specified set is
+     * serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param  s the set to be "wrapped" in a synchronized set.
+     * @return a synchronized view of the specified set.
+     */
+    public static <T> Set<T> synchronizedSet(Set<T> s) {
+        return new SynchronizedSet<>(s);
+    }
+
+    static <T> Set<T> synchronizedSet(Set<T> s, Object mutex) {
+        return new SynchronizedSet<>(s, mutex);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedSet<E>
+          extends SynchronizedCollection<E>
+          implements Set<E> {
+        private static final long serialVersionUID = 487447009682186044L;
+
+        SynchronizedSet(Set<E> s) {
+            super(s);
+        }
+        SynchronizedSet(Set<E> s, Object mutex) {
+            super(s, mutex);
+        }
+
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            synchronized (mutex) {return c.equals(o);}
+        }
+        public int hashCode() {
+            synchronized (mutex) {return c.hashCode();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) sorted set backed by the specified
+     * sorted set.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing sorted set is accomplished
+     * through the returned sorted set (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * sorted set when iterating over it or any of its <tt>subSet</tt>,
+     * <tt>headSet</tt>, or <tt>tailSet</tt> views.
+     * <pre>
+     *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
+     *      ...
+     *  synchronized (s) {
+     *      Iterator i = s.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
+     *  SortedSet s2 = s.headSet(foo);
+     *      ...
+     *  synchronized (s) {  // Note: s, not s2!!!
+     *      Iterator i = s2.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned sorted set will be serializable if the specified
+     * sorted set is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param  s the sorted set to be "wrapped" in a synchronized sorted set.
+     * @return a synchronized view of the specified sorted set.
+     */
+    public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s) {
+        return new SynchronizedSortedSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedSortedSet<E>
+        extends SynchronizedSet<E>
+        implements SortedSet<E>
+    {
+        private static final long serialVersionUID = 8695801310862127406L;
+
+        private final SortedSet<E> ss;
+
+        SynchronizedSortedSet(SortedSet<E> s) {
+            super(s);
+            ss = s;
+        }
+        SynchronizedSortedSet(SortedSet<E> s, Object mutex) {
+            super(s, mutex);
+            ss = s;
+        }
+
+        public Comparator<? super E> comparator() {
+            synchronized (mutex) {return ss.comparator();}
+        }
+
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedSortedSet<>(
+                    ss.subSet(fromElement, toElement), mutex);
+            }
+        }
+        public SortedSet<E> headSet(E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedSortedSet<>(ss.headSet(toElement), mutex);
+            }
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            synchronized (mutex) {
+               return new SynchronizedSortedSet<>(ss.tailSet(fromElement),mutex);
+            }
+        }
+
+        public E first() {
+            synchronized (mutex) {return ss.first();}
+        }
+        public E last() {
+            synchronized (mutex) {return ss.last();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) navigable set backed by the
+     * specified navigable set.  In order to guarantee serial access, it is
+     * critical that <strong>all</strong> access to the backing navigable set is
+     * accomplished through the returned navigable set (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * navigable set when iterating over it or any of its {@code subSet},
+     * {@code headSet}, or {@code tailSet} views.
+     * <pre>
+     *  NavigableSet s = Collections.synchronizedNavigableSet(new TreeSet());
+     *      ...
+     *  synchronized (s) {
+     *      Iterator i = s.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  NavigableSet s = Collections.synchronizedNavigableSet(new TreeSet());
+     *  NavigableSet s2 = s.headSet(foo, true);
+     *      ...
+     *  synchronized (s) {  // Note: s, not s2!!!
+     *      Iterator i = s2.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned navigable set will be serializable if the specified
+     * navigable set is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param  s the navigable set to be "wrapped" in a synchronized navigable
+     * set
+     * @return a synchronized view of the specified navigable set
+     * @since 1.8
+     */
+    public static <T> NavigableSet<T> synchronizedNavigableSet(NavigableSet<T> s) {
+        return new SynchronizedNavigableSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedNavigableSet<E>
+        extends SynchronizedSortedSet<E>
+        implements NavigableSet<E>
+    {
+        private static final long serialVersionUID = -5505529816273629798L;
+
+        private final NavigableSet<E> ns;
+
+        SynchronizedNavigableSet(NavigableSet<E> s) {
+            super(s);
+            ns = s;
+        }
+
+        SynchronizedNavigableSet(NavigableSet<E> s, Object mutex) {
+            super(s, mutex);
+            ns = s;
+        }
+        public E lower(E e)      { synchronized (mutex) {return ns.lower(e);} }
+        public E floor(E e)      { synchronized (mutex) {return ns.floor(e);} }
+        public E ceiling(E e)  { synchronized (mutex) {return ns.ceiling(e);} }
+        public E higher(E e)    { synchronized (mutex) {return ns.higher(e);} }
+        public E pollFirst()  { synchronized (mutex) {return ns.pollFirst();} }
+        public E pollLast()    { synchronized (mutex) {return ns.pollLast();} }
+
+        public NavigableSet<E> descendingSet() {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.descendingSet(), mutex);
+            }
+        }
+
+        public Iterator<E> descendingIterator()
+                 { synchronized (mutex) { return descendingSet().iterator(); } }
+
+        public NavigableSet<E> subSet(E fromElement, E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.subSet(fromElement, true, toElement, false), mutex);
+            }
+        }
+        public NavigableSet<E> headSet(E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.headSet(toElement, false), mutex);
+            }
+        }
+        public NavigableSet<E> tailSet(E fromElement) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.tailSet(fromElement, true), mutex);
+            }
+        }
+
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), mutex);
+            }
+        }
+
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.headSet(toElement, inclusive), mutex);
+            }
+        }
+
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.tailSet(fromElement, inclusive), mutex);
+            }
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) list backed by the specified
+     * list.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing list is accomplished
+     * through the returned list.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * list when iterating over it:
+     * <pre>
+     *  List list = Collections.synchronizedList(new ArrayList());
+     *      ...
+     *  synchronized (list) {
+     *      Iterator i = list.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned list will be serializable if the specified list is
+     * serializable.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be "wrapped" in a synchronized list.
+     * @return a synchronized view of the specified list.
+     */
+    public static <T> List<T> synchronizedList(List<T> list) {
+        return (list instanceof RandomAccess ?
+                new SynchronizedRandomAccessList<>(list) :
+                new SynchronizedList<>(list));
+    }
+
+    static <T> List<T> synchronizedList(List<T> list, Object mutex) {
+        return (list instanceof RandomAccess ?
+                new SynchronizedRandomAccessList<>(list, mutex) :
+                new SynchronizedList<>(list, mutex));
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedList<E>
+        extends SynchronizedCollection<E>
+        implements List<E> {
+        private static final long serialVersionUID = -7754090372962971524L;
+
+        final List<E> list;
+
+        SynchronizedList(List<E> list) {
+            super(list);
+            this.list = list;
+        }
+        SynchronizedList(List<E> list, Object mutex) {
+            super(list, mutex);
+            this.list = list;
+        }
+
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            synchronized (mutex) {return list.equals(o);}
+        }
+        public int hashCode() {
+            synchronized (mutex) {return list.hashCode();}
+        }
+
+        public E get(int index) {
+            synchronized (mutex) {return list.get(index);}
+        }
+        public E set(int index, E element) {
+            synchronized (mutex) {return list.set(index, element);}
+        }
+        public void add(int index, E element) {
+            synchronized (mutex) {list.add(index, element);}
+        }
+        public E remove(int index) {
+            synchronized (mutex) {return list.remove(index);}
+        }
+
+        public int indexOf(Object o) {
+            synchronized (mutex) {return list.indexOf(o);}
+        }
+        public int lastIndexOf(Object o) {
+            synchronized (mutex) {return list.lastIndexOf(o);}
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            synchronized (mutex) {return list.addAll(index, c);}
+        }
+
+        public ListIterator<E> listIterator() {
+            return list.listIterator(); // Must be manually synched by user
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            return list.listIterator(index); // Must be manually synched by user
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            synchronized (mutex) {
+                return new SynchronizedList<>(list.subList(fromIndex, toIndex),
+                                            mutex);
+            }
+        }
+
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            synchronized (mutex) {list.replaceAll(operator);}
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+            synchronized (mutex) {list.sort(c);}
+        }
+
+        /**
+         * SynchronizedRandomAccessList instances are serialized as
+         * SynchronizedList instances to allow them to be deserialized
+         * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList).
+         * This method inverts the transformation.  As a beneficial
+         * side-effect, it also grafts the RandomAccess marker onto
+         * SynchronizedList instances that were serialized in pre-1.4 JREs.
+         *
+         * Note: Unfortunately, SynchronizedRandomAccessList instances
+         * serialized in 1.4.1 and deserialized in 1.4 will become
+         * SynchronizedList instances, as this method was missing in 1.4.
+         */
+        private Object readResolve() {
+            return (list instanceof RandomAccess
+                    ? new SynchronizedRandomAccessList<>(list)
+                    : this);
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedRandomAccessList<E>
+        extends SynchronizedList<E>
+        implements RandomAccess {
+
+        SynchronizedRandomAccessList(List<E> list) {
+            super(list);
+        }
+
+        SynchronizedRandomAccessList(List<E> list, Object mutex) {
+            super(list, mutex);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            synchronized (mutex) {
+                return new SynchronizedRandomAccessList<>(
+                    list.subList(fromIndex, toIndex), mutex);
+            }
+        }
+
+        private static final long serialVersionUID = 1530674583602358482L;
+
+        /**
+         * Allows instances to be deserialized in pre-1.4 JREs (which do
+         * not have SynchronizedRandomAccessList).  SynchronizedList has
+         * a readResolve method that inverts this transformation upon
+         * deserialization.
+         */
+        private Object writeReplace() {
+            return new SynchronizedList<>(list);
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) map backed by the specified
+     * map.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing map is accomplished
+     * through the returned map.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * map when iterating over any of its collection views:
+     * <pre>
+     *  Map m = Collections.synchronizedMap(new HashMap());
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the map to be "wrapped" in a synchronized map.
+     * @return a synchronized view of the specified map.
+     */
+    public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
+        return new SynchronizedMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SynchronizedMap<K,V>
+        implements Map<K,V>, Serializable {
+        private static final long serialVersionUID = 1978198479659022715L;
+
+        private final Map<K,V> m;     // Backing Map
+        final Object      mutex;        // Object on which to synchronize
+
+        SynchronizedMap(Map<K,V> m) {
+            this.m = Objects.requireNonNull(m);
+            mutex = this;
+        }
+
+        SynchronizedMap(Map<K,V> m, Object mutex) {
+            this.m = m;
+            this.mutex = mutex;
+        }
+
+        public int size() {
+            synchronized (mutex) {return m.size();}
+        }
+        public boolean isEmpty() {
+            synchronized (mutex) {return m.isEmpty();}
+        }
+        public boolean containsKey(Object key) {
+            synchronized (mutex) {return m.containsKey(key);}
+        }
+        public boolean containsValue(Object value) {
+            synchronized (mutex) {return m.containsValue(value);}
+        }
+        public V get(Object key) {
+            synchronized (mutex) {return m.get(key);}
+        }
+
+        public V put(K key, V value) {
+            synchronized (mutex) {return m.put(key, value);}
+        }
+        public V remove(Object key) {
+            synchronized (mutex) {return m.remove(key);}
+        }
+        public void putAll(Map<? extends K, ? extends V> map) {
+            synchronized (mutex) {m.putAll(map);}
+        }
+        public void clear() {
+            synchronized (mutex) {m.clear();}
+        }
+
+        private transient Set<K> keySet;
+        private transient Set<Map.Entry<K,V>> entrySet;
+        private transient Collection<V> values;
+
+        public Set<K> keySet() {
+            synchronized (mutex) {
+                if (keySet==null)
+                    keySet = new SynchronizedSet<>(m.keySet(), mutex);
+                return keySet;
+            }
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            synchronized (mutex) {
+                if (entrySet==null)
+                    entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
+                return entrySet;
+            }
+        }
+
+        public Collection<V> values() {
+            synchronized (mutex) {
+                if (values==null)
+                    values = new SynchronizedCollection<>(m.values(), mutex);
+                return values;
+            }
+        }
+
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            synchronized (mutex) {return m.equals(o);}
+        }
+        public int hashCode() {
+            synchronized (mutex) {return m.hashCode();}
+        }
+        public String toString() {
+            synchronized (mutex) {return m.toString();}
+        }
+
+        // Override default methods in Map
+        @Override
+        public V getOrDefault(Object k, V defaultValue) {
+            synchronized (mutex) {return m.getOrDefault(k, defaultValue);}
+        }
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            synchronized (mutex) {m.forEach(action);}
+        }
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            synchronized (mutex) {m.replaceAll(function);}
+        }
+        @Override
+        public V putIfAbsent(K key, V value) {
+            synchronized (mutex) {return m.putIfAbsent(key, value);}
+        }
+        @Override
+        public boolean remove(Object key, Object value) {
+            synchronized (mutex) {return m.remove(key, value);}
+        }
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            synchronized (mutex) {return m.replace(key, oldValue, newValue);}
+        }
+        @Override
+        public V replace(K key, V value) {
+            synchronized (mutex) {return m.replace(key, value);}
+        }
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}
+        }
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}
+        }
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            synchronized (mutex) {return m.compute(key, remappingFunction);}
+        }
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            synchronized (mutex) {return m.merge(key, value, remappingFunction);}
+        }
+
+        private void writeObject(ObjectOutputStream s) throws IOException {
+            synchronized (mutex) {s.defaultWriteObject();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) sorted map backed by the specified
+     * sorted map.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing sorted map is accomplished
+     * through the returned sorted map (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * sorted map when iterating over any of its collection views, or the
+     * collections views of any of its <tt>subMap</tt>, <tt>headMap</tt> or
+     * <tt>tailMap</tt> views.
+     * <pre>
+     *  SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
+     *  SortedMap m2 = m.subMap(foo, bar);
+     *      ...
+     *  Set s2 = m2.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not m2 or s2!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned sorted map will be serializable if the specified
+     * sorted map is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the sorted map to be "wrapped" in a synchronized sorted map.
+     * @return a synchronized view of the specified sorted map.
+     */
+    public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m) {
+        return new SynchronizedSortedMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedSortedMap<K,V>
+        extends SynchronizedMap<K,V>
+        implements SortedMap<K,V>
+    {
+        private static final long serialVersionUID = -8798146769416483793L;
+
+        private final SortedMap<K,V> sm;
+
+        SynchronizedSortedMap(SortedMap<K,V> m) {
+            super(m);
+            sm = m;
+        }
+        SynchronizedSortedMap(SortedMap<K,V> m, Object mutex) {
+            super(m, mutex);
+            sm = m;
+        }
+
+        public Comparator<? super K> comparator() {
+            synchronized (mutex) {return sm.comparator();}
+        }
+
+        public SortedMap<K,V> subMap(K fromKey, K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedSortedMap<>(
+                    sm.subMap(fromKey, toKey), mutex);
+            }
+        }
+        public SortedMap<K,V> headMap(K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedSortedMap<>(sm.headMap(toKey), mutex);
+            }
+        }
+        public SortedMap<K,V> tailMap(K fromKey) {
+            synchronized (mutex) {
+               return new SynchronizedSortedMap<>(sm.tailMap(fromKey),mutex);
+            }
+        }
+
+        public K firstKey() {
+            synchronized (mutex) {return sm.firstKey();}
+        }
+        public K lastKey() {
+            synchronized (mutex) {return sm.lastKey();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) navigable map backed by the
+     * specified navigable map.  In order to guarantee serial access, it is
+     * critical that <strong>all</strong> access to the backing navigable map is
+     * accomplished through the returned navigable map (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * navigable map when iterating over any of its collection views, or the
+     * collections views of any of its {@code subMap}, {@code headMap} or
+     * {@code tailMap} views.
+     * <pre>
+     *  NavigableMap m = Collections.synchronizedNavigableMap(new TreeMap());
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  NavigableMap m = Collections.synchronizedNavigableMap(new TreeMap());
+     *  NavigableMap m2 = m.subMap(foo, true, bar, false);
+     *      ...
+     *  Set s2 = m2.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not m2 or s2!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned navigable map will be serializable if the specified
+     * navigable map is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the navigable map to be "wrapped" in a synchronized navigable
+     *              map
+     * @return a synchronized view of the specified navigable map.
+     * @since 1.8
+     */
+    public static <K,V> NavigableMap<K,V> synchronizedNavigableMap(NavigableMap<K,V> m) {
+        return new SynchronizedNavigableMap<>(m);
+    }
+
+    /**
+     * A synchronized NavigableMap.
+     *
+     * @serial include
+     */
+    static class SynchronizedNavigableMap<K,V>
+        extends SynchronizedSortedMap<K,V>
+        implements NavigableMap<K,V>
+    {
+        private static final long serialVersionUID = 699392247599746807L;
+
+        private final NavigableMap<K,V> nm;
+
+        SynchronizedNavigableMap(NavigableMap<K,V> m) {
+            super(m);
+            nm = m;
+        }
+        SynchronizedNavigableMap(NavigableMap<K,V> m, Object mutex) {
+            super(m, mutex);
+            nm = m;
+        }
+
+        public Entry<K, V> lowerEntry(K key)
+                        { synchronized (mutex) { return nm.lowerEntry(key); } }
+        public K lowerKey(K key)
+                          { synchronized (mutex) { return nm.lowerKey(key); } }
+        public Entry<K, V> floorEntry(K key)
+                        { synchronized (mutex) { return nm.floorEntry(key); } }
+        public K floorKey(K key)
+                          { synchronized (mutex) { return nm.floorKey(key); } }
+        public Entry<K, V> ceilingEntry(K key)
+                      { synchronized (mutex) { return nm.ceilingEntry(key); } }
+        public K ceilingKey(K key)
+                        { synchronized (mutex) { return nm.ceilingKey(key); } }
+        public Entry<K, V> higherEntry(K key)
+                       { synchronized (mutex) { return nm.higherEntry(key); } }
+        public K higherKey(K key)
+                         { synchronized (mutex) { return nm.higherKey(key); } }
+        public Entry<K, V> firstEntry()
+                           { synchronized (mutex) { return nm.firstEntry(); } }
+        public Entry<K, V> lastEntry()
+                            { synchronized (mutex) { return nm.lastEntry(); } }
+        public Entry<K, V> pollFirstEntry()
+                       { synchronized (mutex) { return nm.pollFirstEntry(); } }
+        public Entry<K, V> pollLastEntry()
+                        { synchronized (mutex) { return nm.pollLastEntry(); } }
+
+        public NavigableMap<K, V> descendingMap() {
+            synchronized (mutex) {
+                return
+                    new SynchronizedNavigableMap<>(nm.descendingMap(), mutex);
+            }
+        }
+
+        public NavigableSet<K> keySet() {
+            return navigableKeySet();
+        }
+
+        public NavigableSet<K> navigableKeySet() {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(nm.navigableKeySet(), mutex);
+            }
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(nm.descendingKeySet(), mutex);
+            }
+        }
+
+
+        public SortedMap<K,V> subMap(K fromKey, K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                    nm.subMap(fromKey, true, toKey, false), mutex);
+            }
+        }
+        public SortedMap<K,V> headMap(K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(nm.headMap(toKey, false), mutex);
+            }
+        }
+        public SortedMap<K,V> tailMap(K fromKey) {
+            synchronized (mutex) {
+        return new SynchronizedNavigableMap<>(nm.tailMap(fromKey, true),mutex);
+            }
+        }
+
+        public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                    nm.subMap(fromKey, fromInclusive, toKey, toInclusive), mutex);
+            }
+        }
+
+        public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                        nm.headMap(toKey, inclusive), mutex);
+            }
+        }
+
+        public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                    nm.tailMap(fromKey, inclusive), mutex);
+            }
+        }
+    }
+
+    // Dynamically typesafe collection wrappers
+
+    /**
+     * Returns a dynamically typesafe view of the specified collection.
+     * Any attempt to insert an element of the wrong type will result in an
+     * immediate {@link ClassCastException}.  Assuming a collection
+     * contains no incorrectly typed elements prior to the time a
+     * dynamically typesafe view is generated, and that all subsequent
+     * access to the collection takes place through the view, it is
+     * <i>guaranteed</i> that the collection cannot contain an incorrectly
+     * typed element.
+     *
+     * <p>The generics mechanism in the language provides compile-time
+     * (static) type checking, but it is possible to defeat this mechanism
+     * with unchecked casts.  Usually this is not a problem, as the compiler
+     * issues warnings on all such unchecked operations.  There are, however,
+     * times when static type checking alone is not sufficient.  For example,
+     * suppose a collection is passed to a third-party library and it is
+     * imperative that the library code not corrupt the collection by
+     * inserting an element of the wrong type.
+     *
+     * <p>Another use of dynamically typesafe views is debugging.  Suppose a
+     * program fails with a {@code ClassCastException}, indicating that an
+     * incorrectly typed element was put into a parameterized collection.
+     * Unfortunately, the exception can occur at any time after the erroneous
+     * element is inserted, so it typically provides little or no information
+     * as to the real source of the problem.  If the problem is reproducible,
+     * one can quickly determine its source by temporarily modifying the
+     * program to wrap the collection with a dynamically typesafe view.
+     * For example, this declaration:
+     *  <pre> {@code
+     *     Collection<String> c = new HashSet<>();
+     * }</pre>
+     * may be replaced temporarily by this one:
+     *  <pre> {@code
+     *     Collection<String> c = Collections.checkedCollection(
+     *         new HashSet<>(), String.class);
+     * }</pre>
+     * Running the program again will cause it to fail at the point where
+     * an incorrectly typed element is inserted into the collection, clearly
+     * identifying the source of the problem.  Once the problem is fixed, the
+     * modified declaration may be reverted back to the original.
+     *
+     * <p>The returned collection does <i>not</i> pass the hashCode and equals
+     * operations through to the backing collection, but relies on
+     * {@code Object}'s {@code equals} and {@code hashCode} methods.  This
+     * is necessary to preserve the contracts of these operations in the case
+     * that the backing collection is a set or a list.
+     *
+     * <p>The returned collection will be serializable if the specified
+     * collection is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned collection permits insertion of null elements
+     * whenever the backing collection does.
+     *
+     * @param <E> the class of the objects in the collection
+     * @param c the collection for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code c} is permitted to hold
+     * @return a dynamically typesafe view of the specified collection
+     * @since 1.5
+     */
+    public static <E> Collection<E> checkedCollection(Collection<E> c,
+                                                      Class<E> type) {
+        return new CheckedCollection<>(c, type);
+    }
+
+    @SuppressWarnings("unchecked")
+    static <T> T[] zeroLengthArray(Class<T> type) {
+        return (T[]) Array.newInstance(type, 0);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedCollection<E> implements Collection<E>, Serializable {
+        private static final long serialVersionUID = 1578914078182001775L;
+
+        final Collection<E> c;
+        final Class<E> type;
+
+        @SuppressWarnings("unchecked")
+        E typeCheck(Object o) {
+            if (o != null && !type.isInstance(o))
+                throw new ClassCastException(badElementMsg(o));
+            return (E) o;
+        }
+
+        private String badElementMsg(Object o) {
+            return "Attempt to insert " + o.getClass() +
+                " element into collection with element type " + type;
+        }
+
+        CheckedCollection(Collection<E> c, Class<E> type) {
+            this.c = Objects.requireNonNull(c, "c");
+            this.type = Objects.requireNonNull(type, "type");
+        }
+
+        public int size()                 { return c.size(); }
+        public boolean isEmpty()          { return c.isEmpty(); }
+        public boolean contains(Object o) { return c.contains(o); }
+        public Object[] toArray()         { return c.toArray(); }
+        public <T> T[] toArray(T[] a)     { return c.toArray(a); }
+        public String toString()          { return c.toString(); }
+        public boolean remove(Object o)   { return c.remove(o); }
+        public void clear()               {        c.clear(); }
+
+        public boolean containsAll(Collection<?> coll) {
+            return c.containsAll(coll);
+        }
+        public boolean removeAll(Collection<?> coll) {
+            return c.removeAll(coll);
+        }
+        public boolean retainAll(Collection<?> coll) {
+            return c.retainAll(coll);
+        }
+
+        public Iterator<E> iterator() {
+            // JDK-6363904 - unwrapped iterator could be typecast to
+            // ListIterator with unsafe set()
+            final Iterator<E> it = c.iterator();
+            return new Iterator<E>() {
+                public boolean hasNext() { return it.hasNext(); }
+                public E next()          { return it.next(); }
+                public void remove()     {        it.remove(); }};
+            // Android-note: Oversight of Iterator.forEachRemaining().
+            // http://b/110351017
+        }
+
+        public boolean add(E e)          { return c.add(typeCheck(e)); }
+
+        private E[] zeroLengthElementArray; // Lazily initialized
+
+        private E[] zeroLengthElementArray() {
+            return zeroLengthElementArray != null ? zeroLengthElementArray :
+                (zeroLengthElementArray = zeroLengthArray(type));
+        }
+
+        @SuppressWarnings("unchecked")
+        Collection<E> checkedCopyOf(Collection<? extends E> coll) {
+            Object[] a;
+            try {
+                E[] z = zeroLengthElementArray();
+                a = coll.toArray(z);
+                // Defend against coll violating the toArray contract
+                if (a.getClass() != z.getClass())
+                    a = Arrays.copyOf(a, a.length, z.getClass());
+            } catch (ArrayStoreException ignore) {
+                // To get better and consistent diagnostics,
+                // we call typeCheck explicitly on each element.
+                // We call clone() to defend against coll retaining a
+                // reference to the returned array and storing a bad
+                // element into it after it has been type checked.
+                a = coll.toArray().clone();
+                for (Object o : a)
+                    typeCheck(o);
+            }
+            // A slight abuse of the type system, but safe here.
+            return (Collection<E>) Arrays.asList(a);
+        }
+
+        public boolean addAll(Collection<? extends E> coll) {
+            // Doing things this way insulates us from concurrent changes
+            // in the contents of coll and provides all-or-nothing
+            // semantics (which we wouldn't get if we type-checked each
+            // element as we added it)
+            return c.addAll(checkedCopyOf(coll));
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {c.forEach(action);}
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            return c.removeIf(filter);
+        }
+        @Override
+        public Spliterator<E> spliterator() {return c.spliterator();}
+        @Override
+        public Stream<E> stream()           {return c.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return c.parallelStream();}
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified queue.
+     * Any attempt to insert an element of the wrong type will result in
+     * an immediate {@link ClassCastException}.  Assuming a queue contains
+     * no incorrectly typed elements prior to the time a dynamically typesafe
+     * view is generated, and that all subsequent access to the queue
+     * takes place through the view, it is <i>guaranteed</i> that the
+     * queue cannot contain an incorrectly typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned queue will be serializable if the specified queue
+     * is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned queue permits insertion of {@code null} elements
+     * whenever the backing queue does.
+     *
+     * @param <E> the class of the objects in the queue
+     * @param queue the queue for which a dynamically typesafe view is to be
+     *             returned
+     * @param type the type of element that {@code queue} is permitted to hold
+     * @return a dynamically typesafe view of the specified queue
+     * @since 1.8
+     */
+    public static <E> Queue<E> checkedQueue(Queue<E> queue, Class<E> type) {
+        return new CheckedQueue<>(queue, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedQueue<E>
+        extends CheckedCollection<E>
+        implements Queue<E>, Serializable
+    {
+        private static final long serialVersionUID = 1433151992604707767L;
+        final Queue<E> queue;
+
+        CheckedQueue(Queue<E> queue, Class<E> elementType) {
+            super(queue, elementType);
+            this.queue = queue;
+        }
+
+        public E element()              {return queue.element();}
+        public boolean equals(Object o) {return o == this || c.equals(o);}
+        public int hashCode()           {return c.hashCode();}
+        public E peek()                 {return queue.peek();}
+        public E poll()                 {return queue.poll();}
+        public E remove()               {return queue.remove();}
+        public boolean offer(E e)       {return queue.offer(typeCheck(e));}
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified set.
+     * Any attempt to insert an element of the wrong type will result in
+     * an immediate {@link ClassCastException}.  Assuming a set contains
+     * no incorrectly typed elements prior to the time a dynamically typesafe
+     * view is generated, and that all subsequent access to the set
+     * takes place through the view, it is <i>guaranteed</i> that the
+     * set cannot contain an incorrectly typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned set will be serializable if the specified set is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned set permits insertion of null elements whenever
+     * the backing set does.
+     *
+     * @param <E> the class of the objects in the set
+     * @param s the set for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code s} is permitted to hold
+     * @return a dynamically typesafe view of the specified set
+     * @since 1.5
+     */
+    public static <E> Set<E> checkedSet(Set<E> s, Class<E> type) {
+        return new CheckedSet<>(s, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedSet<E> extends CheckedCollection<E>
+                                 implements Set<E>, Serializable
+    {
+        private static final long serialVersionUID = 4694047833775013803L;
+
+        CheckedSet(Set<E> s, Class<E> elementType) { super(s, elementType); }
+
+        public boolean equals(Object o) { return o == this || c.equals(o); }
+        public int hashCode()           { return c.hashCode(); }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified sorted set.
+     * Any attempt to insert an element of the wrong type will result in an
+     * immediate {@link ClassCastException}.  Assuming a sorted set
+     * contains no incorrectly typed elements prior to the time a
+     * dynamically typesafe view is generated, and that all subsequent
+     * access to the sorted set takes place through the view, it is
+     * <i>guaranteed</i> that the sorted set cannot contain an incorrectly
+     * typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned sorted set will be serializable if the specified sorted
+     * set is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned sorted set permits insertion of null elements
+     * whenever the backing sorted set does.
+     *
+     * @param <E> the class of the objects in the set
+     * @param s the sorted set for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code s} is permitted to hold
+     * @return a dynamically typesafe view of the specified sorted set
+     * @since 1.5
+     */
+    public static <E> SortedSet<E> checkedSortedSet(SortedSet<E> s,
+                                                    Class<E> type) {
+        return new CheckedSortedSet<>(s, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedSortedSet<E> extends CheckedSet<E>
+        implements SortedSet<E>, Serializable
+    {
+        private static final long serialVersionUID = 1599911165492914959L;
+
+        private final SortedSet<E> ss;
+
+        CheckedSortedSet(SortedSet<E> s, Class<E> type) {
+            super(s, type);
+            ss = s;
+        }
+
+        public Comparator<? super E> comparator() { return ss.comparator(); }
+        public E first()                   { return ss.first(); }
+        public E last()                    { return ss.last(); }
+
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            return checkedSortedSet(ss.subSet(fromElement,toElement), type);
+        }
+        public SortedSet<E> headSet(E toElement) {
+            return checkedSortedSet(ss.headSet(toElement), type);
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            return checkedSortedSet(ss.tailSet(fromElement), type);
+        }
+    }
+
+/**
+     * Returns a dynamically typesafe view of the specified navigable set.
+     * Any attempt to insert an element of the wrong type will result in an
+     * immediate {@link ClassCastException}.  Assuming a navigable set
+     * contains no incorrectly typed elements prior to the time a
+     * dynamically typesafe view is generated, and that all subsequent
+     * access to the navigable set takes place through the view, it is
+     * <em>guaranteed</em> that the navigable set cannot contain an incorrectly
+     * typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned navigable set will be serializable if the specified
+     * navigable set is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned navigable set permits insertion of null elements
+     * whenever the backing sorted set does.
+     *
+     * @param <E> the class of the objects in the set
+     * @param s the navigable set for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code s} is permitted to hold
+     * @return a dynamically typesafe view of the specified navigable set
+     * @since 1.8
+     */
+    public static <E> NavigableSet<E> checkedNavigableSet(NavigableSet<E> s,
+                                                    Class<E> type) {
+        return new CheckedNavigableSet<>(s, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedNavigableSet<E> extends CheckedSortedSet<E>
+        implements NavigableSet<E>, Serializable
+    {
+        private static final long serialVersionUID = -5429120189805438922L;
+
+        private final NavigableSet<E> ns;
+
+        CheckedNavigableSet(NavigableSet<E> s, Class<E> type) {
+            super(s, type);
+            ns = s;
+        }
+
+        public E lower(E e)                             { return ns.lower(e); }
+        public E floor(E e)                             { return ns.floor(e); }
+        public E ceiling(E e)                         { return ns.ceiling(e); }
+        public E higher(E e)                           { return ns.higher(e); }
+        public E pollFirst()                         { return ns.pollFirst(); }
+        public E pollLast()                            {return ns.pollLast(); }
+        public NavigableSet<E> descendingSet()
+                      { return checkedNavigableSet(ns.descendingSet(), type); }
+        public Iterator<E> descendingIterator()
+            {return checkedNavigableSet(ns.descendingSet(), type).iterator(); }
+
+        public NavigableSet<E> subSet(E fromElement, E toElement) {
+            return checkedNavigableSet(ns.subSet(fromElement, true, toElement, false), type);
+        }
+        public NavigableSet<E> headSet(E toElement) {
+            return checkedNavigableSet(ns.headSet(toElement, false), type);
+        }
+        public NavigableSet<E> tailSet(E fromElement) {
+            return checkedNavigableSet(ns.tailSet(fromElement, true), type);
+        }
+
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+            return checkedNavigableSet(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), type);
+        }
+
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            return checkedNavigableSet(ns.headSet(toElement, inclusive), type);
+        }
+
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            return checkedNavigableSet(ns.tailSet(fromElement, inclusive), type);
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified list.
+     * Any attempt to insert an element of the wrong type will result in
+     * an immediate {@link ClassCastException}.  Assuming a list contains
+     * no incorrectly typed elements prior to the time a dynamically typesafe
+     * view is generated, and that all subsequent access to the list
+     * takes place through the view, it is <i>guaranteed</i> that the
+     * list cannot contain an incorrectly typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned list will be serializable if the specified list
+     * is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned list permits insertion of null elements whenever
+     * the backing list does.
+     *
+     * @param <E> the class of the objects in the list
+     * @param list the list for which a dynamically typesafe view is to be
+     *             returned
+     * @param type the type of element that {@code list} is permitted to hold
+     * @return a dynamically typesafe view of the specified list
+     * @since 1.5
+     */
+    public static <E> List<E> checkedList(List<E> list, Class<E> type) {
+        return (list instanceof RandomAccess ?
+                new CheckedRandomAccessList<>(list, type) :
+                new CheckedList<>(list, type));
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedList<E>
+        extends CheckedCollection<E>
+        implements List<E>
+    {
+        private static final long serialVersionUID = 65247728283967356L;
+        final List<E> list;
+
+        CheckedList(List<E> list, Class<E> type) {
+            super(list, type);
+            this.list = list;
+        }
+
+        public boolean equals(Object o)  { return o == this || list.equals(o); }
+        public int hashCode()            { return list.hashCode(); }
+        public E get(int index)          { return list.get(index); }
+        public E remove(int index)       { return list.remove(index); }
+        public int indexOf(Object o)     { return list.indexOf(o); }
+        public int lastIndexOf(Object o) { return list.lastIndexOf(o); }
+
+        public E set(int index, E element) {
+            return list.set(index, typeCheck(element));
+        }
+
+        public void add(int index, E element) {
+            list.add(index, typeCheck(element));
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            return list.addAll(index, checkedCopyOf(c));
+        }
+        public ListIterator<E> listIterator()   { return listIterator(0); }
+
+        public ListIterator<E> listIterator(final int index) {
+            final ListIterator<E> i = list.listIterator(index);
+
+            return new ListIterator<E>() {
+                public boolean hasNext()     { return i.hasNext(); }
+                public E next()              { return i.next(); }
+                public boolean hasPrevious() { return i.hasPrevious(); }
+                public E previous()          { return i.previous(); }
+                public int nextIndex()       { return i.nextIndex(); }
+                public int previousIndex()   { return i.previousIndex(); }
+                public void remove()         {        i.remove(); }
+
+                public void set(E e) {
+                    i.set(typeCheck(e));
+                }
+
+                public void add(E e) {
+                    i.add(typeCheck(e));
+                }
+
+                @Override
+                public void forEachRemaining(Consumer<? super E> action) {
+                    i.forEachRemaining(action);
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new CheckedList<>(list.subList(fromIndex, toIndex), type);
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @throws ClassCastException if the class of an element returned by the
+         *         operator prevents it from being added to this collection. The
+         *         exception may be thrown after some elements of the list have
+         *         already been replaced.
+         */
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            Objects.requireNonNull(operator);
+            list.replaceAll(e -> typeCheck(operator.apply(e)));
+        }
+
+        @Override
+        public void sort(Comparator<? super E> c) {
+            list.sort(c);
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedRandomAccessList<E> extends CheckedList<E>
+                                            implements RandomAccess
+    {
+        private static final long serialVersionUID = 1638200125423088369L;
+
+        CheckedRandomAccessList(List<E> list, Class<E> type) {
+            super(list, type);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new CheckedRandomAccessList<>(
+                    list.subList(fromIndex, toIndex), type);
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified map.
+     * Any attempt to insert a mapping whose key or value have the wrong
+     * type will result in an immediate {@link ClassCastException}.
+     * Similarly, any attempt to modify the value currently associated with
+     * a key will result in an immediate {@link ClassCastException},
+     * whether the modification is attempted directly through the map
+     * itself, or through a {@link Map.Entry} instance obtained from the
+     * map's {@link Map#entrySet() entry set} view.
+     *
+     * <p>Assuming a map contains no incorrectly typed keys or values
+     * prior to the time a dynamically typesafe view is generated, and
+     * that all subsequent access to the map takes place through the view
+     * (or one of its collection views), it is <i>guaranteed</i> that the
+     * map cannot contain an incorrectly typed key or value.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned map permits insertion of null keys or values
+     * whenever the backing map does.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the map for which a dynamically typesafe view is to be
+     *          returned
+     * @param keyType the type of key that {@code m} is permitted to hold
+     * @param valueType the type of value that {@code m} is permitted to hold
+     * @return a dynamically typesafe view of the specified map
+     * @since 1.5
+     */
+    public static <K, V> Map<K, V> checkedMap(Map<K, V> m,
+                                              Class<K> keyType,
+                                              Class<V> valueType) {
+        return new CheckedMap<>(m, keyType, valueType);
+    }
+
+
+    /**
+     * @serial include
+     */
+    private static class CheckedMap<K,V>
+        implements Map<K,V>, Serializable
+    {
+        private static final long serialVersionUID = 5742860141034234728L;
+
+        private final Map<K, V> m;
+        final Class<K> keyType;
+        final Class<V> valueType;
+
+        private void typeCheck(Object key, Object value) {
+            if (key != null && !keyType.isInstance(key))
+                throw new ClassCastException(badKeyMsg(key));
+
+            if (value != null && !valueType.isInstance(value))
+                throw new ClassCastException(badValueMsg(value));
+        }
+
+        private BiFunction<? super K, ? super V, ? extends V> typeCheck(
+                BiFunction<? super K, ? super V, ? extends V> func) {
+            Objects.requireNonNull(func);
+            return (k, v) -> {
+                V newValue = func.apply(k, v);
+                typeCheck(k, newValue);
+                return newValue;
+            };
+        }
+
+        private String badKeyMsg(Object key) {
+            return "Attempt to insert " + key.getClass() +
+                    " key into map with key type " + keyType;
+        }
+
+        private String badValueMsg(Object value) {
+            return "Attempt to insert " + value.getClass() +
+                    " value into map with value type " + valueType;
+        }
+
+        CheckedMap(Map<K, V> m, Class<K> keyType, Class<V> valueType) {
+            this.m = Objects.requireNonNull(m);
+            this.keyType = Objects.requireNonNull(keyType);
+            this.valueType = Objects.requireNonNull(valueType);
+        }
+
+        public int size()                      { return m.size(); }
+        public boolean isEmpty()               { return m.isEmpty(); }
+        public boolean containsKey(Object key) { return m.containsKey(key); }
+        public boolean containsValue(Object v) { return m.containsValue(v); }
+        public V get(Object key)               { return m.get(key); }
+        public V remove(Object key)            { return m.remove(key); }
+        public void clear()                    { m.clear(); }
+        public Set<K> keySet()                 { return m.keySet(); }
+        public Collection<V> values()          { return m.values(); }
+        public boolean equals(Object o)        { return o == this || m.equals(o); }
+        public int hashCode()                  { return m.hashCode(); }
+        public String toString()               { return m.toString(); }
+
+        public V put(K key, V value) {
+            typeCheck(key, value);
+            return m.put(key, value);
+        }
+
+        @SuppressWarnings("unchecked")
+        public void putAll(Map<? extends K, ? extends V> t) {
+            // Satisfy the following goals:
+            // - good diagnostics in case of type mismatch
+            // - all-or-nothing semantics
+            // - protection from malicious t
+            // - correct behavior if t is a concurrent map
+            Object[] entries = t.entrySet().toArray();
+            List<Map.Entry<K,V>> checked = new ArrayList<>(entries.length);
+            for (Object o : entries) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                Object k = e.getKey();
+                Object v = e.getValue();
+                typeCheck(k, v);
+                checked.add(
+                        new AbstractMap.SimpleImmutableEntry<>((K)k, (V)v));
+            }
+            for (Map.Entry<K,V> e : checked)
+                m.put(e.getKey(), e.getValue());
+        }
+
+        private transient Set<Map.Entry<K,V>> entrySet;
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            if (entrySet==null)
+                entrySet = new CheckedEntrySet<>(m.entrySet(), valueType);
+            return entrySet;
+        }
+
+        // Override default methods in Map
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            m.forEach(action);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            m.replaceAll(typeCheck(function));
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            typeCheck(key, value);
+            return m.putIfAbsent(key, value);
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            return m.remove(key, value);
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            typeCheck(key, newValue);
+            return m.replace(key, oldValue, newValue);
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            typeCheck(key, value);
+            return m.replace(key, value);
+        }
+
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            Objects.requireNonNull(mappingFunction);
+            return m.computeIfAbsent(key, k -> {
+                V value = mappingFunction.apply(k);
+                typeCheck(k, value);
+                return value;
+            });
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            return m.computeIfPresent(key, typeCheck(remappingFunction));
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            return m.compute(key, typeCheck(remappingFunction));
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            Objects.requireNonNull(remappingFunction);
+            return m.merge(key, value, (v1, v2) -> {
+                V newValue = remappingFunction.apply(v1, v2);
+                typeCheck(null, newValue);
+                return newValue;
+            });
+        }
+
+        /**
+         * We need this class in addition to CheckedSet as Map.Entry permits
+         * modification of the backing Map via the setValue operation.  This
+         * class is subtle: there are many possible attacks that must be
+         * thwarted.
+         *
+         * @serial exclude
+         */
+        static class CheckedEntrySet<K,V> implements Set<Map.Entry<K,V>> {
+            private final Set<Map.Entry<K,V>> s;
+            private final Class<V> valueType;
+
+            CheckedEntrySet(Set<Map.Entry<K, V>> s, Class<V> valueType) {
+                this.s = s;
+                this.valueType = valueType;
+            }
+
+            public int size()        { return s.size(); }
+            public boolean isEmpty() { return s.isEmpty(); }
+            public String toString() { return s.toString(); }
+            public int hashCode()    { return s.hashCode(); }
+            public void clear()      {        s.clear(); }
+
+            public boolean add(Map.Entry<K, V> e) {
+                throw new UnsupportedOperationException();
+            }
+            public boolean addAll(Collection<? extends Map.Entry<K, V>> coll) {
+                throw new UnsupportedOperationException();
+            }
+
+            public Iterator<Map.Entry<K,V>> iterator() {
+                final Iterator<Map.Entry<K, V>> i = s.iterator();
+                final Class<V> valueType = this.valueType;
+
+                return new Iterator<Map.Entry<K,V>>() {
+                    public boolean hasNext() { return i.hasNext(); }
+                    public void remove()     { i.remove(); }
+
+                    public Map.Entry<K,V> next() {
+                        return checkedEntry(i.next(), valueType);
+                    }
+                    // Android-note: Oversight of Iterator.forEachRemaining().
+                    // http://b/110351017
+                };
+            }
+
+            // Android-changed: Ignore IsInstanceOfClass warning. b/73288967, b/73344263.
+            // @SuppressWarnings("unchecked")
+            @SuppressWarnings({ "unchecked", "IsInstanceOfClass" })
+            public Object[] toArray() {
+                Object[] source = s.toArray();
+
+                /*
+                 * Ensure that we don't get an ArrayStoreException even if
+                 * s.toArray returns an array of something other than Object
+                 */
+                Object[] dest = (CheckedEntry.class.isInstance(
+                    source.getClass().getComponentType()) ? source :
+                                 new Object[source.length]);
+
+                for (int i = 0; i < source.length; i++)
+                    dest[i] = checkedEntry((Map.Entry<K,V>)source[i],
+                                           valueType);
+                return dest;
+            }
+
+            @SuppressWarnings("unchecked")
+            public <T> T[] toArray(T[] a) {
+                // We don't pass a to s.toArray, to avoid window of
+                // vulnerability wherein an unscrupulous multithreaded client
+                // could get his hands on raw (unwrapped) Entries from s.
+                T[] arr = s.toArray(a.length==0 ? a : Arrays.copyOf(a, 0));
+
+                for (int i=0; i<arr.length; i++)
+                    arr[i] = (T) checkedEntry((Map.Entry<K,V>)arr[i],
+                                              valueType);
+                if (arr.length > a.length)
+                    return arr;
+
+                System.arraycopy(arr, 0, a, 0, arr.length);
+                if (a.length > arr.length)
+                    a[arr.length] = null;
+                return a;
+            }
+
+            /**
+             * This method is overridden to protect the backing set against
+             * an object with a nefarious equals function that senses
+             * that the equality-candidate is Map.Entry and calls its
+             * setValue method.
+             */
+            public boolean contains(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                return s.contains(
+                    (e instanceof CheckedEntry) ? e : checkedEntry(e, valueType));
+            }
+
+            /**
+             * The bulk collection methods are overridden to protect
+             * against an unscrupulous collection whose contains(Object o)
+             * method senses when o is a Map.Entry, and calls o.setValue.
+             */
+            public boolean containsAll(Collection<?> c) {
+                for (Object o : c)
+                    if (!contains(o)) // Invokes safe contains() above
+                        return false;
+                return true;
+            }
+
+            public boolean remove(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                return s.remove(new AbstractMap.SimpleImmutableEntry
+                                <>((Map.Entry<?,?>)o));
+            }
+
+            public boolean removeAll(Collection<?> c) {
+                return batchRemove(c, false);
+            }
+            public boolean retainAll(Collection<?> c) {
+                return batchRemove(c, true);
+            }
+            private boolean batchRemove(Collection<?> c, boolean complement) {
+                Objects.requireNonNull(c);
+                boolean modified = false;
+                Iterator<Map.Entry<K,V>> it = iterator();
+                while (it.hasNext()) {
+                    if (c.contains(it.next()) != complement) {
+                        it.remove();
+                        modified = true;
+                    }
+                }
+                return modified;
+            }
+
+            public boolean equals(Object o) {
+                if (o == this)
+                    return true;
+                if (!(o instanceof Set))
+                    return false;
+                Set<?> that = (Set<?>) o;
+                return that.size() == s.size()
+                    && containsAll(that); // Invokes safe containsAll() above
+            }
+
+            static <K,V,T> CheckedEntry<K,V,T> checkedEntry(Map.Entry<K,V> e,
+                                                            Class<T> valueType) {
+                return new CheckedEntry<>(e, valueType);
+            }
+
+            /**
+             * This "wrapper class" serves two purposes: it prevents
+             * the client from modifying the backing Map, by short-circuiting
+             * the setValue method, and it protects the backing Map against
+             * an ill-behaved Map.Entry that attempts to modify another
+             * Map.Entry when asked to perform an equality check.
+             */
+            private static class CheckedEntry<K,V,T> implements Map.Entry<K,V> {
+                private final Map.Entry<K, V> e;
+                private final Class<T> valueType;
+
+                CheckedEntry(Map.Entry<K, V> e, Class<T> valueType) {
+                    this.e = Objects.requireNonNull(e);
+                    this.valueType = Objects.requireNonNull(valueType);
+                }
+
+                public K getKey()        { return e.getKey(); }
+                public V getValue()      { return e.getValue(); }
+                public int hashCode()    { return e.hashCode(); }
+                public String toString() { return e.toString(); }
+
+                public V setValue(V value) {
+                    if (value != null && !valueType.isInstance(value))
+                        throw new ClassCastException(badValueMsg(value));
+                    return e.setValue(value);
+                }
+
+                private String badValueMsg(Object value) {
+                    return "Attempt to insert " + value.getClass() +
+                        " value into map with value type " + valueType;
+                }
+
+                public boolean equals(Object o) {
+                    if (o == this)
+                        return true;
+                    if (!(o instanceof Map.Entry))
+                        return false;
+                    return e.equals(new AbstractMap.SimpleImmutableEntry
+                                    <>((Map.Entry<?,?>)o));
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified sorted map.
+     * Any attempt to insert a mapping whose key or value have the wrong
+     * type will result in an immediate {@link ClassCastException}.
+     * Similarly, any attempt to modify the value currently associated with
+     * a key will result in an immediate {@link ClassCastException},
+     * whether the modification is attempted directly through the map
+     * itself, or through a {@link Map.Entry} instance obtained from the
+     * map's {@link Map#entrySet() entry set} view.
+     *
+     * <p>Assuming a map contains no incorrectly typed keys or values
+     * prior to the time a dynamically typesafe view is generated, and
+     * that all subsequent access to the map takes place through the view
+     * (or one of its collection views), it is <i>guaranteed</i> that the
+     * map cannot contain an incorrectly typed key or value.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned map permits insertion of null keys or values
+     * whenever the backing map does.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the map for which a dynamically typesafe view is to be
+     *          returned
+     * @param keyType the type of key that {@code m} is permitted to hold
+     * @param valueType the type of value that {@code m} is permitted to hold
+     * @return a dynamically typesafe view of the specified map
+     * @since 1.5
+     */
+    public static <K,V> SortedMap<K,V> checkedSortedMap(SortedMap<K, V> m,
+                                                        Class<K> keyType,
+                                                        Class<V> valueType) {
+        return new CheckedSortedMap<>(m, keyType, valueType);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedSortedMap<K,V> extends CheckedMap<K,V>
+        implements SortedMap<K,V>, Serializable
+    {
+        private static final long serialVersionUID = 1599671320688067438L;
+
+        private final SortedMap<K, V> sm;
+
+        CheckedSortedMap(SortedMap<K, V> m,
+                         Class<K> keyType, Class<V> valueType) {
+            super(m, keyType, valueType);
+            sm = m;
+        }
+
+        public Comparator<? super K> comparator() { return sm.comparator(); }
+        public K firstKey()                       { return sm.firstKey(); }
+        public K lastKey()                        { return sm.lastKey(); }
+
+        public SortedMap<K,V> subMap(K fromKey, K toKey) {
+            return checkedSortedMap(sm.subMap(fromKey, toKey),
+                                    keyType, valueType);
+        }
+        public SortedMap<K,V> headMap(K toKey) {
+            return checkedSortedMap(sm.headMap(toKey), keyType, valueType);
+        }
+        public SortedMap<K,V> tailMap(K fromKey) {
+            return checkedSortedMap(sm.tailMap(fromKey), keyType, valueType);
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified navigable map.
+     * Any attempt to insert a mapping whose key or value have the wrong
+     * type will result in an immediate {@link ClassCastException}.
+     * Similarly, any attempt to modify the value currently associated with
+     * a key will result in an immediate {@link ClassCastException},
+     * whether the modification is attempted directly through the map
+     * itself, or through a {@link Map.Entry} instance obtained from the
+     * map's {@link Map#entrySet() entry set} view.
+     *
+     * <p>Assuming a map contains no incorrectly typed keys or values
+     * prior to the time a dynamically typesafe view is generated, and
+     * that all subsequent access to the map takes place through the view
+     * (or one of its collection views), it is <em>guaranteed</em> that the
+     * map cannot contain an incorrectly typed key or value.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned map permits insertion of null keys or values
+     * whenever the backing map does.
+     *
+     * @param <K> type of map keys
+     * @param <V> type of map values
+     * @param m the map for which a dynamically typesafe view is to be
+     *          returned
+     * @param keyType the type of key that {@code m} is permitted to hold
+     * @param valueType the type of value that {@code m} is permitted to hold
+     * @return a dynamically typesafe view of the specified map
+     * @since 1.8
+     */
+    public static <K,V> NavigableMap<K,V> checkedNavigableMap(NavigableMap<K, V> m,
+                                                        Class<K> keyType,
+                                                        Class<V> valueType) {
+        return new CheckedNavigableMap<>(m, keyType, valueType);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedNavigableMap<K,V> extends CheckedSortedMap<K,V>
+        implements NavigableMap<K,V>, Serializable
+    {
+        private static final long serialVersionUID = -4852462692372534096L;
+
+        private final NavigableMap<K, V> nm;
+
+        CheckedNavigableMap(NavigableMap<K, V> m,
+                         Class<K> keyType, Class<V> valueType) {
+            super(m, keyType, valueType);
+            nm = m;
+        }
+
+        public Comparator<? super K> comparator()   { return nm.comparator(); }
+        public K firstKey()                           { return nm.firstKey(); }
+        public K lastKey()                             { return nm.lastKey(); }
+
+        public Entry<K, V> lowerEntry(K key) {
+            Entry<K,V> lower = nm.lowerEntry(key);
+            return (null != lower)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(lower, valueType)
+                : null;
+        }
+
+        public K lowerKey(K key)                   { return nm.lowerKey(key); }
+
+        public Entry<K, V> floorEntry(K key) {
+            Entry<K,V> floor = nm.floorEntry(key);
+            return (null != floor)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(floor, valueType)
+                : null;
+        }
+
+        public K floorKey(K key)                   { return nm.floorKey(key); }
+
+        public Entry<K, V> ceilingEntry(K key) {
+            Entry<K,V> ceiling = nm.ceilingEntry(key);
+            return (null != ceiling)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(ceiling, valueType)
+                : null;
+        }
+
+        public K ceilingKey(K key)               { return nm.ceilingKey(key); }
+
+        public Entry<K, V> higherEntry(K key) {
+            Entry<K,V> higher = nm.higherEntry(key);
+            return (null != higher)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(higher, valueType)
+                : null;
+        }
+
+        public K higherKey(K key)                 { return nm.higherKey(key); }
+
+        public Entry<K, V> firstEntry() {
+            Entry<K,V> first = nm.firstEntry();
+            return (null != first)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(first, valueType)
+                : null;
+        }
+
+        public Entry<K, V> lastEntry() {
+            Entry<K,V> last = nm.lastEntry();
+            return (null != last)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(last, valueType)
+                : null;
+        }
+
+        public Entry<K, V> pollFirstEntry() {
+            Entry<K,V> entry = nm.pollFirstEntry();
+            return (null == entry)
+                ? null
+                : new CheckedMap.CheckedEntrySet.CheckedEntry<>(entry, valueType);
+        }
+
+        public Entry<K, V> pollLastEntry() {
+            Entry<K,V> entry = nm.pollLastEntry();
+            return (null == entry)
+                ? null
+                : new CheckedMap.CheckedEntrySet.CheckedEntry<>(entry, valueType);
+        }
+
+        public NavigableMap<K, V> descendingMap() {
+            return checkedNavigableMap(nm.descendingMap(), keyType, valueType);
+        }
+
+        public NavigableSet<K> keySet() {
+            return navigableKeySet();
+        }
+
+        public NavigableSet<K> navigableKeySet() {
+            return checkedNavigableSet(nm.navigableKeySet(), keyType);
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            return checkedNavigableSet(nm.descendingKeySet(), keyType);
+        }
+
+        @Override
+        public NavigableMap<K,V> subMap(K fromKey, K toKey) {
+            return checkedNavigableMap(nm.subMap(fromKey, true, toKey, false),
+                                    keyType, valueType);
+        }
+
+        @Override
+        public NavigableMap<K,V> headMap(K toKey) {
+            return checkedNavigableMap(nm.headMap(toKey, false), keyType, valueType);
+        }
+
+        @Override
+        public NavigableMap<K,V> tailMap(K fromKey) {
+            return checkedNavigableMap(nm.tailMap(fromKey, true), keyType, valueType);
+        }
+
+        public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+            return checkedNavigableMap(nm.subMap(fromKey, fromInclusive, toKey, toInclusive), keyType, valueType);
+        }
+
+        public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+            return checkedNavigableMap(nm.headMap(toKey, inclusive), keyType, valueType);
+        }
+
+        public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+            return checkedNavigableMap(nm.tailMap(fromKey, inclusive), keyType, valueType);
+        }
+    }
+
+    // Empty collections
+
+    /**
+     * Returns an iterator that has no elements.  More precisely,
+     *
+     * <ul>
+     * <li>{@link Iterator#hasNext hasNext} always returns {@code
+     * false}.</li>
+     * <li>{@link Iterator#next next} always throws {@link
+     * NoSuchElementException}.</li>
+     * <li>{@link Iterator#remove remove} always throws {@link
+     * IllegalStateException}.</li>
+     * </ul>
+     *
+     * <p>Implementations of this method are permitted, but not
+     * required, to return the same object from multiple invocations.
+     *
+     * @param <T> type of elements, if there were any, in the iterator
+     * @return an empty iterator
+     * @since 1.7
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Iterator<T> emptyIterator() {
+        return (Iterator<T>) EmptyIterator.EMPTY_ITERATOR;
+    }
+
+    private static class EmptyIterator<E> implements Iterator<E> {
+        static final EmptyIterator<Object> EMPTY_ITERATOR
+            = new EmptyIterator<>();
+
+        public boolean hasNext() { return false; }
+        public E next() { throw new NoSuchElementException(); }
+        public void remove() { throw new IllegalStateException(); }
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+        }
+    }
+
+    /**
+     * Returns a list iterator that has no elements.  More precisely,
+     *
+     * <ul>
+     * <li>{@link Iterator#hasNext hasNext} and {@link
+     * ListIterator#hasPrevious hasPrevious} always return {@code
+     * false}.</li>
+     * <li>{@link Iterator#next next} and {@link ListIterator#previous
+     * previous} always throw {@link NoSuchElementException}.</li>
+     * <li>{@link Iterator#remove remove} and {@link ListIterator#set
+     * set} always throw {@link IllegalStateException}.</li>
+     * <li>{@link ListIterator#add add} always throws {@link
+     * UnsupportedOperationException}.</li>
+     * <li>{@link ListIterator#nextIndex nextIndex} always returns
+     * {@code 0}.</li>
+     * <li>{@link ListIterator#previousIndex previousIndex} always
+     * returns {@code -1}.</li>
+     * </ul>
+     *
+     * <p>Implementations of this method are permitted, but not
+     * required, to return the same object from multiple invocations.
+     *
+     * @param <T> type of elements, if there were any, in the iterator
+     * @return an empty list iterator
+     * @since 1.7
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> ListIterator<T> emptyListIterator() {
+        return (ListIterator<T>) EmptyListIterator.EMPTY_ITERATOR;
+    }
+
+    private static class EmptyListIterator<E>
+        extends EmptyIterator<E>
+        implements ListIterator<E>
+    {
+        static final EmptyListIterator<Object> EMPTY_ITERATOR
+            = new EmptyListIterator<>();
+
+        public boolean hasPrevious() { return false; }
+        public E previous() { throw new NoSuchElementException(); }
+        public int nextIndex()     { return 0; }
+        public int previousIndex() { return -1; }
+        public void set(E e) { throw new IllegalStateException(); }
+        public void add(E e) { throw new UnsupportedOperationException(); }
+    }
+
+    /**
+     * Returns an enumeration that has no elements.  More precisely,
+     *
+     * <ul>
+     * <li>{@link Enumeration#hasMoreElements hasMoreElements} always
+     * returns {@code false}.</li>
+     * <li> {@link Enumeration#nextElement nextElement} always throws
+     * {@link NoSuchElementException}.</li>
+     * </ul>
+     *
+     * <p>Implementations of this method are permitted, but not
+     * required, to return the same object from multiple invocations.
+     *
+     * @param  <T> the class of the objects in the enumeration
+     * @return an empty enumeration
+     * @since 1.7
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Enumeration<T> emptyEnumeration() {
+        return (Enumeration<T>) EmptyEnumeration.EMPTY_ENUMERATION;
+    }
+
+    private static class EmptyEnumeration<E> implements Enumeration<E> {
+        static final EmptyEnumeration<Object> EMPTY_ENUMERATION
+            = new EmptyEnumeration<>();
+
+        public boolean hasMoreElements() { return false; }
+        public E nextElement() { throw new NoSuchElementException(); }
+    }
+
+    /**
+     * The empty set (immutable).  This set is serializable.
+     *
+     * @see #emptySet()
+     */
+    @SuppressWarnings("rawtypes")
+    public static final Set EMPTY_SET = new EmptySet<>();
+
+    /**
+     * Returns an empty set (immutable).  This set is serializable.
+     * Unlike the like-named field, this method is parameterized.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty set:
+     * <pre>
+     *     Set&lt;String&gt; s = Collections.emptySet();
+     * </pre>
+     * @implNote Implementations of this method need not create a separate
+     * {@code Set} object for each call.  Using this method is likely to have
+     * comparable cost to using the like-named field.  (Unlike this method, the
+     * field does not provide type safety.)
+     *
+     * @param  <T> the class of the objects in the set
+     * @return the empty set
+     *
+     * @see #EMPTY_SET
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public static final <T> Set<T> emptySet() {
+        return (Set<T>) EMPTY_SET;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class EmptySet<E>
+        extends AbstractSet<E>
+        implements Serializable
+    {
+        private static final long serialVersionUID = 1582296315990362920L;
+
+        public Iterator<E> iterator() { return emptyIterator(); }
+
+        public int size() {return 0;}
+        public boolean isEmpty() {return true;}
+
+        public boolean contains(Object obj) {return false;}
+        public boolean containsAll(Collection<?> c) { return c.isEmpty(); }
+
+        public Object[] toArray() { return new Object[0]; }
+
+        public <T> T[] toArray(T[] a) {
+            if (a.length > 0)
+                a[0] = null;
+            return a;
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            Objects.requireNonNull(filter);
+            return false;
+        }
+        @Override
+        public Spliterator<E> spliterator() { return Spliterators.emptySpliterator(); }
+
+        // Preserves singleton property
+        private Object readResolve() {
+            return EMPTY_SET;
+        }
+    }
+
+    /**
+     * Returns an empty sorted set (immutable).  This set is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty
+     * sorted set:
+     * <pre> {@code
+     *     SortedSet<String> s = Collections.emptySortedSet();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not create a separate
+     * {@code SortedSet} object for each call.
+     *
+     * @param <E> type of elements, if there were any, in the set
+     * @return the empty sorted set
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> SortedSet<E> emptySortedSet() {
+        return (SortedSet<E>) UnmodifiableNavigableSet.EMPTY_NAVIGABLE_SET;
+    }
+
+    /**
+     * Returns an empty navigable set (immutable).  This set is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty
+     * navigable set:
+     * <pre> {@code
+     *     NavigableSet<String> s = Collections.emptyNavigableSet();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not
+     * create a separate {@code NavigableSet} object for each call.
+     *
+     * @param <E> type of elements, if there were any, in the set
+     * @return the empty navigable set
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> NavigableSet<E> emptyNavigableSet() {
+        return (NavigableSet<E>) UnmodifiableNavigableSet.EMPTY_NAVIGABLE_SET;
+    }
+
+    /**
+     * The empty list (immutable).  This list is serializable.
+     *
+     * @see #emptyList()
+     */
+    @SuppressWarnings("rawtypes")
+    public static final List EMPTY_LIST = new EmptyList<>();
+
+    /**
+     * Returns an empty list (immutable).  This list is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty list:
+     * <pre>
+     *     List&lt;String&gt; s = Collections.emptyList();
+     * </pre>
+     *
+     * @implNote
+     * Implementations of this method need not create a separate <tt>List</tt>
+     * object for each call.   Using this method is likely to have comparable
+     * cost to using the like-named field.  (Unlike this method, the field does
+     * not provide type safety.)
+     *
+     * @param <T> type of elements, if there were any, in the list
+     * @return an empty immutable list
+     *
+     * @see #EMPTY_LIST
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public static final <T> List<T> emptyList() {
+        return (List<T>) EMPTY_LIST;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class EmptyList<E>
+        extends AbstractList<E>
+        implements RandomAccess, Serializable {
+        private static final long serialVersionUID = 8842843931221139166L;
+
+        public Iterator<E> iterator() {
+            return emptyIterator();
+        }
+        public ListIterator<E> listIterator() {
+            return emptyListIterator();
+        }
+
+        public int size() {return 0;}
+        public boolean isEmpty() {return true;}
+
+        public boolean contains(Object obj) {return false;}
+        public boolean containsAll(Collection<?> c) { return c.isEmpty(); }
+
+        public Object[] toArray() { return new Object[0]; }
+
+        public <T> T[] toArray(T[] a) {
+            if (a.length > 0)
+                a[0] = null;
+            return a;
+        }
+
+        public E get(int index) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+
+        public boolean equals(Object o) {
+            return (o instanceof List) && ((List<?>)o).isEmpty();
+        }
+
+        public int hashCode() { return 1; }
+
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            Objects.requireNonNull(filter);
+            return false;
+        }
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            Objects.requireNonNull(operator);
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+        }
+
+        @Override
+        public Spliterator<E> spliterator() { return Spliterators.emptySpliterator(); }
+
+        // Preserves singleton property
+        private Object readResolve() {
+            return EMPTY_LIST;
+        }
+    }
+
+    /**
+     * The empty map (immutable).  This map is serializable.
+     *
+     * @see #emptyMap()
+     * @since 1.3
+     */
+    @SuppressWarnings("rawtypes")
+    public static final Map EMPTY_MAP = new EmptyMap<>();
+
+    /**
+     * Returns an empty map (immutable).  This map is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty map:
+     * <pre>
+     *     Map&lt;String, Date&gt; s = Collections.emptyMap();
+     * </pre>
+     * @implNote Implementations of this method need not create a separate
+     * {@code Map} object for each call.  Using this method is likely to have
+     * comparable cost to using the like-named field.  (Unlike this method, the
+     * field does not provide type safety.)
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @return an empty map
+     * @see #EMPTY_MAP
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public static final <K,V> Map<K,V> emptyMap() {
+        return (Map<K,V>) EMPTY_MAP;
+    }
+
+    /**
+     * Returns an empty sorted map (immutable).  This map is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty map:
+     * <pre> {@code
+     *     SortedMap<String, Date> s = Collections.emptySortedMap();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not create a separate
+     * {@code SortedMap} object for each call.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @return an empty sorted map
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static final <K,V> SortedMap<K,V> emptySortedMap() {
+        return (SortedMap<K,V>) UnmodifiableNavigableMap.EMPTY_NAVIGABLE_MAP;
+    }
+
+    /**
+     * Returns an empty navigable map (immutable).  This map is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty map:
+     * <pre> {@code
+     *     NavigableMap<String, Date> s = Collections.emptyNavigableMap();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not create a separate
+     * {@code NavigableMap} object for each call.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @return an empty navigable map
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static final <K,V> NavigableMap<K,V> emptyNavigableMap() {
+        return (NavigableMap<K,V>) UnmodifiableNavigableMap.EMPTY_NAVIGABLE_MAP;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class EmptyMap<K,V>
+        extends AbstractMap<K,V>
+        implements Serializable
+    {
+        private static final long serialVersionUID = 6428348081105594320L;
+
+        public int size()                          {return 0;}
+        public boolean isEmpty()                   {return true;}
+        public boolean containsKey(Object key)     {return false;}
+        public boolean containsValue(Object value) {return false;}
+        public V get(Object key)                   {return null;}
+        public Set<K> keySet()                     {return emptySet();}
+        public Collection<V> values()              {return emptySet();}
+        public Set<Map.Entry<K,V>> entrySet()      {return emptySet();}
+
+        public boolean equals(Object o) {
+            return (o instanceof Map) && ((Map<?,?>)o).isEmpty();
+        }
+
+        public int hashCode()                      {return 0;}
+
+        // Override default methods in Map
+        @Override
+        @SuppressWarnings("unchecked")
+        public V getOrDefault(Object k, V defaultValue) {
+            return defaultValue;
+        }
+
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            Objects.requireNonNull(action);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            Objects.requireNonNull(function);
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Preserves singleton property
+        private Object readResolve() {
+            return EMPTY_MAP;
+        }
+    }
+
+    // Singleton collections
+
+    /**
+     * Returns an immutable set containing only the specified object.
+     * The returned set is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param o the sole object to be stored in the returned set.
+     * @return an immutable set containing only the specified object.
+     */
+    public static <T> Set<T> singleton(T o) {
+        return new SingletonSet<>(o);
+    }
+
+    static <E> Iterator<E> singletonIterator(final E e) {
+        return new Iterator<E>() {
+            private boolean hasNext = true;
+            public boolean hasNext() {
+                return hasNext;
+            }
+            public E next() {
+                if (hasNext) {
+                    hasNext = false;
+                    return e;
+                }
+                throw new NoSuchElementException();
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public void forEachRemaining(Consumer<? super E> action) {
+                Objects.requireNonNull(action);
+                if (hasNext) {
+                    action.accept(e);
+                    hasNext = false;
+                }
+            }
+        };
+    }
+
+    /**
+     * Creates a {@code Spliterator} with only the specified element
+     *
+     * @param <T> Type of elements
+     * @return A singleton {@code Spliterator}
+     */
+    static <T> Spliterator<T> singletonSpliterator(final T element) {
+        return new Spliterator<T>() {
+            long est = 1;
+
+            @Override
+            public Spliterator<T> trySplit() {
+                return null;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> consumer) {
+                Objects.requireNonNull(consumer);
+                if (est > 0) {
+                    est--;
+                    consumer.accept(element);
+                    return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> consumer) {
+                tryAdvance(consumer);
+            }
+
+            @Override
+            public long estimateSize() {
+                return est;
+            }
+
+            @Override
+            public int characteristics() {
+                int value = (element != null) ? Spliterator.NONNULL : 0;
+
+                return value | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.IMMUTABLE |
+                       Spliterator.DISTINCT | Spliterator.ORDERED;
+            }
+        };
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SingletonSet<E>
+        extends AbstractSet<E>
+        implements Serializable
+    {
+        private static final long serialVersionUID = 3193687207550431679L;
+
+        private final E element;
+
+        SingletonSet(E e) {element = e;}
+
+        public Iterator<E> iterator() {
+            return singletonIterator(element);
+        }
+
+        public int size() {return 1;}
+
+        public boolean contains(Object o) {return eq(o, element);}
+
+        // Override default methods for Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            action.accept(element);
+        }
+        @Override
+        public Spliterator<E> spliterator() {
+            return singletonSpliterator(element);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Returns an immutable list containing only the specified object.
+     * The returned list is serializable.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param o the sole object to be stored in the returned list.
+     * @return an immutable list containing only the specified object.
+     * @since 1.3
+     */
+    public static <T> List<T> singletonList(T o) {
+        return new SingletonList<>(o);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SingletonList<E>
+        extends AbstractList<E>
+        implements RandomAccess, Serializable {
+
+        private static final long serialVersionUID = 3093736618740652951L;
+
+        private final E element;
+
+        SingletonList(E obj)                {element = obj;}
+
+        public Iterator<E> iterator() {
+            return singletonIterator(element);
+        }
+
+        public int size()                   {return 1;}
+
+        public boolean contains(Object obj) {return eq(obj, element);}
+
+        public E get(int index) {
+            if (index != 0)
+              throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
+            return element;
+        }
+
+        // Override default methods for Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            action.accept(element);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+        }
+        @Override
+        public Spliterator<E> spliterator() {
+            return singletonSpliterator(element);
+        }
+    }
+
+    /**
+     * Returns an immutable map, mapping only the specified key to the
+     * specified value.  The returned map is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param key the sole key to be stored in the returned map.
+     * @param value the value to which the returned map maps <tt>key</tt>.
+     * @return an immutable map containing only the specified key-value
+     *         mapping.
+     * @since 1.3
+     */
+    public static <K,V> Map<K,V> singletonMap(K key, V value) {
+        return new SingletonMap<>(key, value);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SingletonMap<K,V>
+          extends AbstractMap<K,V>
+          implements Serializable {
+        private static final long serialVersionUID = -6979724477215052911L;
+
+        private final K k;
+        private final V v;
+
+        SingletonMap(K key, V value) {
+            k = key;
+            v = value;
+        }
+
+        public int size()                                           {return 1;}
+        public boolean isEmpty()                                {return false;}
+        public boolean containsKey(Object key)             {return eq(key, k);}
+        public boolean containsValue(Object value)       {return eq(value, v);}
+        public V get(Object key)              {return (eq(key, k) ? v : null);}
+
+        private transient Set<K> keySet;
+        private transient Set<Map.Entry<K,V>> entrySet;
+        private transient Collection<V> values;
+
+        public Set<K> keySet() {
+            if (keySet==null)
+                keySet = singleton(k);
+            return keySet;
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            if (entrySet==null)
+                entrySet = Collections.<Map.Entry<K,V>>singleton(
+                    new SimpleImmutableEntry<>(k, v));
+            return entrySet;
+        }
+
+        public Collection<V> values() {
+            if (values==null)
+                values = singleton(v);
+            return values;
+        }
+
+        // Override default methods in Map
+        @Override
+        public V getOrDefault(Object key, V defaultValue) {
+            return eq(key, k) ? v : defaultValue;
+        }
+
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            action.accept(k, v);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    // Miscellaneous
+
+    /**
+     * Returns an immutable list consisting of <tt>n</tt> copies of the
+     * specified object.  The newly allocated data object is tiny (it contains
+     * a single reference to the data object).  This method is useful in
+     * combination with the <tt>List.addAll</tt> method to grow lists.
+     * The returned list is serializable.
+     *
+     * @param  <T> the class of the object to copy and of the objects
+     *         in the returned list.
+     * @param  n the number of elements in the returned list.
+     * @param  o the element to appear repeatedly in the returned list.
+     * @return an immutable list consisting of <tt>n</tt> copies of the
+     *         specified object.
+     * @throws IllegalArgumentException if {@code n < 0}
+     * @see    List#addAll(Collection)
+     * @see    List#addAll(int, Collection)
+     */
+    public static <T> List<T> nCopies(int n, T o) {
+        if (n < 0)
+            throw new IllegalArgumentException("List length = " + n);
+        return new CopiesList<>(n, o);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class CopiesList<E>
+        extends AbstractList<E>
+        implements RandomAccess, Serializable
+    {
+        private static final long serialVersionUID = 2739099268398711800L;
+
+        final int n;
+        final E element;
+
+        CopiesList(int n, E e) {
+            assert n >= 0;
+            this.n = n;
+            element = e;
+        }
+
+        public int size() {
+            return n;
+        }
+
+        public boolean contains(Object obj) {
+            return n != 0 && eq(obj, element);
+        }
+
+        public int indexOf(Object o) {
+            return contains(o) ? 0 : -1;
+        }
+
+        public int lastIndexOf(Object o) {
+            return contains(o) ? n - 1 : -1;
+        }
+
+        public E get(int index) {
+            if (index < 0 || index >= n)
+                throw new IndexOutOfBoundsException("Index: "+index+
+                                                    ", Size: "+n);
+            return element;
+        }
+
+        public Object[] toArray() {
+            final Object[] a = new Object[n];
+            if (element != null)
+                Arrays.fill(a, 0, n, element);
+            return a;
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            final int n = this.n;
+            if (a.length < n) {
+                a = (T[])java.lang.reflect.Array
+                    .newInstance(a.getClass().getComponentType(), n);
+                if (element != null)
+                    Arrays.fill(a, 0, n, element);
+            } else {
+                Arrays.fill(a, 0, n, element);
+                if (a.length > n)
+                    a[n] = null;
+            }
+            return a;
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            if (fromIndex < 0)
+                throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+            if (toIndex > n)
+                throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+            if (fromIndex > toIndex)
+                throw new IllegalArgumentException("fromIndex(" + fromIndex +
+                                                   ") > toIndex(" + toIndex + ")");
+            return new CopiesList<>(toIndex - fromIndex, element);
+        }
+
+        // Override default methods in Collection
+        @Override
+        public Stream<E> stream() {
+            return IntStream.range(0, n).mapToObj(i -> element);
+        }
+
+        @Override
+        public Stream<E> parallelStream() {
+            return IntStream.range(0, n).parallel().mapToObj(i -> element);
+        }
+
+        @Override
+        public Spliterator<E> spliterator() {
+            return stream().spliterator();
+        }
+    }
+
+    /**
+     * Returns a comparator that imposes the reverse of the <em>natural
+     * ordering</em> on a collection of objects that implement the
+     * {@code Comparable} interface.  (The natural ordering is the ordering
+     * imposed by the objects' own {@code compareTo} method.)  This enables a
+     * simple idiom for sorting (or maintaining) collections (or arrays) of
+     * objects that implement the {@code Comparable} interface in
+     * reverse-natural-order.  For example, suppose {@code a} is an array of
+     * strings. Then: <pre>
+     *          Arrays.sort(a, Collections.reverseOrder());
+     * </pre> sorts the array in reverse-lexicographic (alphabetical) order.<p>
+     *
+     * The returned comparator is serializable.
+     *
+     * @param  <T> the class of the objects compared by the comparator
+     * @return A comparator that imposes the reverse of the <i>natural
+     *         ordering</i> on a collection of objects that implement
+     *         the <tt>Comparable</tt> interface.
+     * @see Comparable
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Comparator<T> reverseOrder() {
+        return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class ReverseComparator
+        implements Comparator<Comparable<Object>>, Serializable {
+
+        private static final long serialVersionUID = 7207038068494060240L;
+
+        static final ReverseComparator REVERSE_ORDER
+            = new ReverseComparator();
+
+        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
+            return c2.compareTo(c1);
+        }
+
+        private Object readResolve() { return Collections.reverseOrder(); }
+
+        @Override
+        public Comparator<Comparable<Object>> reversed() {
+            return Comparator.naturalOrder();
+        }
+    }
+
+    /**
+     * Returns a comparator that imposes the reverse ordering of the specified
+     * comparator.  If the specified comparator is {@code null}, this method is
+     * equivalent to {@link #reverseOrder()} (in other words, it returns a
+     * comparator that imposes the reverse of the <em>natural ordering</em> on
+     * a collection of objects that implement the Comparable interface).
+     *
+     * <p>The returned comparator is serializable (assuming the specified
+     * comparator is also serializable or {@code null}).
+     *
+     * @param <T> the class of the objects compared by the comparator
+     * @param cmp a comparator who's ordering is to be reversed by the returned
+     * comparator or {@code null}
+     * @return A comparator that imposes the reverse ordering of the
+     *         specified comparator.
+     * @since 1.5
+     */
+    public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) {
+        if (cmp == null)
+            return reverseOrder();
+
+        if (cmp instanceof ReverseComparator2)
+            return ((ReverseComparator2<T>)cmp).cmp;
+
+        return new ReverseComparator2<>(cmp);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class ReverseComparator2<T> implements Comparator<T>,
+        Serializable
+    {
+        private static final long serialVersionUID = 4374092139857L;
+
+        /**
+         * The comparator specified in the static factory.  This will never
+         * be null, as the static factory returns a ReverseComparator
+         * instance if its argument is null.
+         *
+         * @serial
+         */
+        final Comparator<T> cmp;
+
+        ReverseComparator2(Comparator<T> cmp) {
+            assert cmp != null;
+            this.cmp = cmp;
+        }
+
+        public int compare(T t1, T t2) {
+            return cmp.compare(t2, t1);
+        }
+
+        public boolean equals(Object o) {
+            return (o == this) ||
+                (o instanceof ReverseComparator2 &&
+                 cmp.equals(((ReverseComparator2)o).cmp));
+        }
+
+        public int hashCode() {
+            return cmp.hashCode() ^ Integer.MIN_VALUE;
+        }
+
+        @Override
+        public Comparator<T> reversed() {
+            return cmp;
+        }
+    }
+
+    /**
+     * Returns an enumeration over the specified collection.  This provides
+     * interoperability with legacy APIs that require an enumeration
+     * as input.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param c the collection for which an enumeration is to be returned.
+     * @return an enumeration over the specified collection.
+     * @see Enumeration
+     */
+    public static <T> Enumeration<T> enumeration(final Collection<T> c) {
+        return new Enumeration<T>() {
+            private final Iterator<T> i = c.iterator();
+
+            public boolean hasMoreElements() {
+                return i.hasNext();
+            }
+
+            public T nextElement() {
+                return i.next();
+            }
+        };
+    }
+
+    /**
+     * Returns an array list containing the elements returned by the
+     * specified enumeration in the order they are returned by the
+     * enumeration.  This method provides interoperability between
+     * legacy APIs that return enumerations and new APIs that require
+     * collections.
+     *
+     * @param <T> the class of the objects returned by the enumeration
+     * @param e enumeration providing elements for the returned
+     *          array list
+     * @return an array list containing the elements returned
+     *         by the specified enumeration.
+     * @since 1.4
+     * @see Enumeration
+     * @see ArrayList
+     */
+    public static <T> ArrayList<T> list(Enumeration<T> e) {
+        ArrayList<T> l = new ArrayList<>();
+        while (e.hasMoreElements())
+            l.add(e.nextElement());
+        return l;
+    }
+
+    /**
+     * Returns true if the specified arguments are equal, or both null.
+     *
+     * NB: Do not replace with Object.equals until JDK-8015417 is resolved.
+     */
+    static boolean eq(Object o1, Object o2) {
+        return o1==null ? o2==null : o1.equals(o2);
+    }
+
+    /**
+     * Returns the number of elements in the specified collection equal to the
+     * specified object.  More formally, returns the number of elements
+     * <tt>e</tt> in the collection such that
+     * <tt>(o == null ? e == null : o.equals(e))</tt>.
+     *
+     * @param c the collection in which to determine the frequency
+     *     of <tt>o</tt>
+     * @param o the object whose frequency is to be determined
+     * @return the number of elements in {@code c} equal to {@code o}
+     * @throws NullPointerException if <tt>c</tt> is null
+     * @since 1.5
+     */
+    public static int frequency(Collection<?> c, Object o) {
+        int result = 0;
+        if (o == null) {
+            for (Object e : c)
+                if (e == null)
+                    result++;
+        } else {
+            for (Object e : c)
+                if (o.equals(e))
+                    result++;
+        }
+        return result;
+    }
+
+    /**
+     * Returns {@code true} if the two specified collections have no
+     * elements in common.
+     *
+     * <p>Care must be exercised if this method is used on collections that
+     * do not comply with the general contract for {@code Collection}.
+     * Implementations may elect to iterate over either collection and test
+     * for containment in the other collection (or to perform any equivalent
+     * computation).  If either collection uses a nonstandard equality test
+     * (as does a {@link SortedSet} whose ordering is not <em>compatible with
+     * equals</em>, or the key set of an {@link IdentityHashMap}), both
+     * collections must use the same nonstandard equality test, or the
+     * result of this method is undefined.
+     *
+     * <p>Care must also be exercised when using collections that have
+     * restrictions on the elements that they may contain. Collection
+     * implementations are allowed to throw exceptions for any operation
+     * involving elements they deem ineligible. For absolute safety the
+     * specified collections should contain only elements which are
+     * eligible elements for both collections.
+     *
+     * <p>Note that it is permissible to pass the same collection in both
+     * parameters, in which case the method will return {@code true} if and
+     * only if the collection is empty.
+     *
+     * @param c1 a collection
+     * @param c2 a collection
+     * @return {@code true} if the two specified collections have no
+     * elements in common.
+     * @throws NullPointerException if either collection is {@code null}.
+     * @throws NullPointerException if one collection contains a {@code null}
+     * element and {@code null} is not an eligible element for the other collection.
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if one collection contains an element that is
+     * of a type which is ineligible for the other collection.
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.5
+     */
+    public static boolean disjoint(Collection<?> c1, Collection<?> c2) {
+        // The collection to be used for contains(). Preference is given to
+        // the collection who's contains() has lower O() complexity.
+        Collection<?> contains = c2;
+        // The collection to be iterated. If the collections' contains() impl
+        // are of different O() complexity, the collection with slower
+        // contains() will be used for iteration. For collections who's
+        // contains() are of the same complexity then best performance is
+        // achieved by iterating the smaller collection.
+        Collection<?> iterate = c1;
+
+        // Performance optimization cases. The heuristics:
+        //   1. Generally iterate over c1.
+        //   2. If c1 is a Set then iterate over c2.
+        //   3. If either collection is empty then result is always true.
+        //   4. Iterate over the smaller Collection.
+        if (c1 instanceof Set) {
+            // Use c1 for contains as a Set's contains() is expected to perform
+            // better than O(N/2)
+            iterate = c2;
+            contains = c1;
+        } else if (!(c2 instanceof Set)) {
+            // Both are mere Collections. Iterate over smaller collection.
+            // Example: If c1 contains 3 elements and c2 contains 50 elements and
+            // assuming contains() requires ceiling(N/2) comparisons then
+            // checking for all c1 elements in c2 would require 75 comparisons
+            // (3 * ceiling(50/2)) vs. checking all c2 elements in c1 requiring
+            // 100 comparisons (50 * ceiling(3/2)).
+            int c1size = c1.size();
+            int c2size = c2.size();
+            if (c1size == 0 || c2size == 0) {
+                // At least one collection is empty. Nothing will match.
+                return true;
+            }
+
+            if (c1size > c2size) {
+                iterate = c2;
+                contains = c1;
+            }
+        }
+
+        for (Object e : iterate) {
+            if (contains.contains(e)) {
+               // Found a common element. Collections are not disjoint.
+                return false;
+            }
+        }
+
+        // No common elements were found.
+        return true;
+    }
+
+    /**
+     * Adds all of the specified elements to the specified collection.
+     * Elements to be added may be specified individually or as an array.
+     * The behavior of this convenience method is identical to that of
+     * <tt>c.addAll(Arrays.asList(elements))</tt>, but this method is likely
+     * to run significantly faster under most implementations.
+     *
+     * <p>When elements are specified individually, this method provides a
+     * convenient way to add a few elements to an existing collection:
+     * <pre>
+     *     Collections.addAll(flavors, "Peaches 'n Plutonium", "Rocky Racoon");
+     * </pre>
+     *
+     * @param  <T> the class of the elements to add and of the collection
+     * @param c the collection into which <tt>elements</tt> are to be inserted
+     * @param elements the elements to insert into <tt>c</tt>
+     * @return <tt>true</tt> if the collection changed as a result of the call
+     * @throws UnsupportedOperationException if <tt>c</tt> does not support
+     *         the <tt>add</tt> operation
+     * @throws NullPointerException if <tt>elements</tt> contains one or more
+     *         null values and <tt>c</tt> does not permit null elements, or
+     *         if <tt>c</tt> or <tt>elements</tt> are <tt>null</tt>
+     * @throws IllegalArgumentException if some property of a value in
+     *         <tt>elements</tt> prevents it from being added to <tt>c</tt>
+     * @see Collection#addAll(Collection)
+     * @since 1.5
+     */
+    @SafeVarargs
+    public static <T> boolean addAll(Collection<? super T> c, T... elements) {
+        boolean result = false;
+        for (T element : elements)
+            result |= c.add(element);
+        return result;
+    }
+
+    /**
+     * Returns a set backed by the specified map.  The resulting set displays
+     * the same ordering, concurrency, and performance characteristics as the
+     * backing map.  In essence, this factory method provides a {@link Set}
+     * implementation corresponding to any {@link Map} implementation.  There
+     * is no need to use this method on a {@link Map} implementation that
+     * already has a corresponding {@link Set} implementation (such as {@link
+     * HashMap} or {@link TreeMap}).
+     *
+     * <p>Each method invocation on the set returned by this method results in
+     * exactly one method invocation on the backing map or its <tt>keySet</tt>
+     * view, with one exception.  The <tt>addAll</tt> method is implemented
+     * as a sequence of <tt>put</tt> invocations on the backing map.
+     *
+     * <p>The specified map must be empty at the time this method is invoked,
+     * and should not be accessed directly after this method returns.  These
+     * conditions are ensured if the map is created empty, passed directly
+     * to this method, and no reference to the map is retained, as illustrated
+     * in the following code fragment:
+     * <pre>
+     *    Set&lt;Object&gt; weakHashSet = Collections.newSetFromMap(
+     *        new WeakHashMap&lt;Object, Boolean&gt;());
+     * </pre>
+     *
+     * @param <E> the class of the map keys and of the objects in the
+     *        returned set
+     * @param map the backing map
+     * @return the set backed by the map
+     * @throws IllegalArgumentException if <tt>map</tt> is not empty
+     * @since 1.6
+     */
+    public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
+        return new SetFromMap<>(map);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SetFromMap<E> extends AbstractSet<E>
+        implements Set<E>, Serializable
+    {
+        private final Map<E, Boolean> m;  // The backing map
+        private transient Set<E> s;       // Its keySet
+
+        SetFromMap(Map<E, Boolean> map) {
+            if (!map.isEmpty())
+                throw new IllegalArgumentException("Map is non-empty");
+            m = map;
+            s = map.keySet();
+        }
+
+        public void clear()               {        m.clear(); }
+        public int size()                 { return m.size(); }
+        public boolean isEmpty()          { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsKey(o); }
+        public boolean remove(Object o)   { return m.remove(o) != null; }
+        public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; }
+        public Iterator<E> iterator()     { return s.iterator(); }
+        public Object[] toArray()         { return s.toArray(); }
+        public <T> T[] toArray(T[] a)     { return s.toArray(a); }
+        public String toString()          { return s.toString(); }
+        public int hashCode()             { return s.hashCode(); }
+        public boolean equals(Object o)   { return o == this || s.equals(o); }
+        public boolean containsAll(Collection<?> c) {return s.containsAll(c);}
+        public boolean removeAll(Collection<?> c)   {return s.removeAll(c);}
+        public boolean retainAll(Collection<?> c)   {return s.retainAll(c);}
+        // addAll is the only inherited implementation
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            s.forEach(action);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            return s.removeIf(filter);
+        }
+
+        @Override
+        public Spliterator<E> spliterator() {return s.spliterator();}
+        @Override
+        public Stream<E> stream()           {return s.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return s.parallelStream();}
+
+        private static final long serialVersionUID = 2454657854757543876L;
+
+        private void readObject(java.io.ObjectInputStream stream)
+            throws IOException, ClassNotFoundException
+        {
+            stream.defaultReadObject();
+            s = m.keySet();
+        }
+    }
+
+    /**
+     * Returns a view of a {@link Deque} as a Last-in-first-out (Lifo)
+     * {@link Queue}. Method <tt>add</tt> is mapped to <tt>push</tt>,
+     * <tt>remove</tt> is mapped to <tt>pop</tt> and so on. This
+     * view can be useful when you would like to use a method
+     * requiring a <tt>Queue</tt> but you need Lifo ordering.
+     *
+     * <p>Each method invocation on the queue returned by this method
+     * results in exactly one method invocation on the backing deque, with
+     * one exception.  The {@link Queue#addAll addAll} method is
+     * implemented as a sequence of {@link Deque#addFirst addFirst}
+     * invocations on the backing deque.
+     *
+     * @param  <T> the class of the objects in the deque
+     * @param deque the deque
+     * @return the queue
+     * @since  1.6
+     */
+    public static <T> Queue<T> asLifoQueue(Deque<T> deque) {
+        return new AsLIFOQueue<>(deque);
+    }
+
+    /**
+     * @serial include
+     */
+    static class AsLIFOQueue<E> extends AbstractQueue<E>
+        implements Queue<E>, Serializable {
+        private static final long serialVersionUID = 1802017725587941708L;
+        private final Deque<E> q;
+        AsLIFOQueue(Deque<E> q)           { this.q = q; }
+        public boolean add(E e)           { q.addFirst(e); return true; }
+        public boolean offer(E e)         { return q.offerFirst(e); }
+        public E poll()                   { return q.pollFirst(); }
+        public E remove()                 { return q.removeFirst(); }
+        public E peek()                   { return q.peekFirst(); }
+        public E element()                { return q.getFirst(); }
+        public void clear()               {        q.clear(); }
+        public int size()                 { return q.size(); }
+        public boolean isEmpty()          { return q.isEmpty(); }
+        public boolean contains(Object o) { return q.contains(o); }
+        public boolean remove(Object o)   { return q.remove(o); }
+        public Iterator<E> iterator()     { return q.iterator(); }
+        public Object[] toArray()         { return q.toArray(); }
+        public <T> T[] toArray(T[] a)     { return q.toArray(a); }
+        public String toString()          { return q.toString(); }
+        public boolean containsAll(Collection<?> c) {return q.containsAll(c);}
+        public boolean removeAll(Collection<?> c)   {return q.removeAll(c);}
+        public boolean retainAll(Collection<?> c)   {return q.retainAll(c);}
+        // We use inherited addAll; forwarding addAll would be wrong
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {q.forEach(action);}
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            return q.removeIf(filter);
+        }
+        @Override
+        public Spliterator<E> spliterator() {return q.spliterator();}
+        @Override
+        public Stream<E> stream()           {return q.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return q.parallelStream();}
+    }
+}
diff --git a/java/util/ComparableTimSort.java b/java/util/ComparableTimSort.java
new file mode 100644
index 0000000..36c8d90
--- /dev/null
+++ b/java/util/ComparableTimSort.java
@@ -0,0 +1,908 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This is a near duplicate of {@link TimSort}, modified for use with
+ * arrays of objects that implement {@link Comparable}, instead of using
+ * explicit comparators.
+ *
+ * <p>If you are using an optimizing VM, you may find that ComparableTimSort
+ * offers no performance benefit over TimSort in conjunction with a
+ * comparator that simply returns {@code ((Comparable)first).compareTo(Second)}.
+ * If this is the case, you are better off deleting ComparableTimSort to
+ * eliminate the code duplication.  (See Arrays.java for details.)
+ *
+ * @author Josh Bloch
+ */
+class ComparableTimSort {
+    /**
+     * This is the minimum sized sequence that will be merged.  Shorter
+     * sequences will be lengthened by calling binarySort.  If the entire
+     * array is less than this length, no merges will be performed.
+     *
+     * This constant should be a power of two.  It was 64 in Tim Peter's C
+     * implementation, but 32 was empirically determined to work better in
+     * this implementation.  In the unlikely event that you set this constant
+     * to be a number that's not a power of two, you'll need to change the
+     * {@link #minRunLength} computation.
+     *
+     * If you decrease this constant, you must change the stackLen
+     * computation in the TimSort constructor, or you risk an
+     * ArrayOutOfBounds exception.  See listsort.txt for a discussion
+     * of the minimum stack length required as a function of the length
+     * of the array being sorted and the minimum merge sequence length.
+     */
+    private static final int MIN_MERGE = 32;
+
+    /**
+     * The array being sorted.
+     */
+    private final Object[] a;
+
+    /**
+     * When we get into galloping mode, we stay there until both runs win less
+     * often than MIN_GALLOP consecutive times.
+     */
+    private static final int  MIN_GALLOP = 7;
+
+    /**
+     * This controls when we get *into* galloping mode.  It is initialized
+     * to MIN_GALLOP.  The mergeLo and mergeHi methods nudge it higher for
+     * random data, and lower for highly structured data.
+     */
+    private int minGallop = MIN_GALLOP;
+
+    /**
+     * Maximum initial size of tmp array, which is used for merging.  The array
+     * can grow to accommodate demand.
+     *
+     * Unlike Tim's original C version, we do not allocate this much storage
+     * when sorting smaller arrays.  This change was required for performance.
+     */
+    private static final int INITIAL_TMP_STORAGE_LENGTH = 256;
+
+    /**
+     * Temp storage for merges. A workspace array may optionally be
+     * provided in constructor, and if so will be used as long as it
+     * is big enough.
+     */
+    private Object[] tmp;
+    private int tmpBase; // base of tmp array slice
+    private int tmpLen;  // length of tmp array slice
+
+    /**
+     * A stack of pending runs yet to be merged.  Run i starts at
+     * address base[i] and extends for len[i] elements.  It's always
+     * true (so long as the indices are in bounds) that:
+     *
+     *     runBase[i] + runLen[i] == runBase[i + 1]
+     *
+     * so we could cut the storage for this, but it's a minor amount,
+     * and keeping all the info explicit simplifies the code.
+     */
+    private int stackSize = 0;  // Number of pending runs on stack
+    private final int[] runBase;
+    private final int[] runLen;
+
+    /**
+     * Creates a TimSort instance to maintain the state of an ongoing sort.
+     *
+     * @param a the array to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private ComparableTimSort(Object[] a, Object[] work, int workBase, int workLen) {
+        this.a = a;
+
+        // Allocate temp storage (which may be increased later if necessary)
+        int len = a.length;
+        int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?
+            len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;
+        if (work == null || workLen < tlen || workBase + tlen > work.length) {
+            tmp = new Object[tlen];
+            tmpBase = 0;
+            tmpLen = tlen;
+        }
+        else {
+            tmp = work;
+            tmpBase = workBase;
+            tmpLen = workLen;
+        }
+
+        /*
+         * Allocate runs-to-be-merged stack (which cannot be expanded).  The
+         * stack length requirements are described in listsort.txt.  The C
+         * version always uses the same stack length (85), but this was
+         * measured to be too expensive when sorting "mid-sized" arrays (e.g.,
+         * 100 elements) in Java.  Therefore, we use smaller (but sufficiently
+         * large) stack lengths for smaller arrays.  The "magic numbers" in the
+         * computation below must be changed if MIN_MERGE is decreased.  See
+         * the MIN_MERGE declaration above for more information.
+         * The maximum value of 49 allows for an array up to length
+         * Integer.MAX_VALUE-4, if array is filled by the worst case stack size
+         * increasing scenario. More explanations are given in section 4 of:
+         * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf
+         */
+        int stackLen = (len <    120  ?  5 :
+                        len <   1542  ? 10 :
+                        len < 119151  ? 24 : 49);
+        runBase = new int[stackLen];
+        runLen = new int[stackLen];
+    }
+
+    /*
+     * The next method (package private and static) constitutes the
+     * entire API of this class.
+     */
+
+    /**
+     * Sorts the given range, using the given workspace array slice
+     * for temp storage when possible. This method is designed to be
+     * invoked from public methods (in class Arrays) after performing
+     * any necessary array bounds checks and expanding parameters into
+     * the required forms.
+     *
+     * @param a the array to be sorted
+     * @param lo the index of the first element, inclusive, to be sorted
+     * @param hi the index of the last element, exclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     * @since 1.8
+     */
+    static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
+        assert a != null && lo >= 0 && lo <= hi && hi <= a.length;
+
+        int nRemaining  = hi - lo;
+        if (nRemaining < 2)
+            return;  // Arrays of size 0 and 1 are always sorted
+
+        // If array is small, do a "mini-TimSort" with no merges
+        if (nRemaining < MIN_MERGE) {
+            int initRunLen = countRunAndMakeAscending(a, lo, hi);
+            binarySort(a, lo, hi, lo + initRunLen);
+            return;
+        }
+
+        /**
+         * March over the array once, left to right, finding natural runs,
+         * extending short natural runs to minRun elements, and merging runs
+         * to maintain stack invariant.
+         */
+        ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen);
+        int minRun = minRunLength(nRemaining);
+        do {
+            // Identify next run
+            int runLen = countRunAndMakeAscending(a, lo, hi);
+
+            // If run is short, extend to min(minRun, nRemaining)
+            if (runLen < minRun) {
+                int force = nRemaining <= minRun ? nRemaining : minRun;
+                binarySort(a, lo, lo + force, lo + runLen);
+                runLen = force;
+            }
+
+            // Push run onto pending-run stack, and maybe merge
+            ts.pushRun(lo, runLen);
+            ts.mergeCollapse();
+
+            // Advance to find next run
+            lo += runLen;
+            nRemaining -= runLen;
+        } while (nRemaining != 0);
+
+        // Merge all remaining runs to complete sort
+        assert lo == hi;
+        ts.mergeForceCollapse();
+        assert ts.stackSize == 1;
+    }
+
+    /**
+     * Sorts the specified portion of the specified array using a binary
+     * insertion sort.  This is the best method for sorting small numbers
+     * of elements.  It requires O(n log n) compares, but O(n^2) data
+     * movement (worst case).
+     *
+     * If the initial part of the specified range is already sorted,
+     * this method can take advantage of it: the method assumes that the
+     * elements from index {@code lo}, inclusive, to {@code start},
+     * exclusive are already sorted.
+     *
+     * @param a the array in which a range is to be sorted
+     * @param lo the index of the first element in the range to be sorted
+     * @param hi the index after the last element in the range to be sorted
+     * @param start the index of the first element in the range that is
+     *        not already known to be sorted ({@code lo <= start <= hi})
+     */
+    @SuppressWarnings({"fallthrough", "rawtypes", "unchecked"})
+    private static void binarySort(Object[] a, int lo, int hi, int start) {
+        assert lo <= start && start <= hi;
+        if (start == lo)
+            start++;
+        for ( ; start < hi; start++) {
+            Comparable pivot = (Comparable) a[start];
+
+            // Set left (and right) to the index where a[start] (pivot) belongs
+            int left = lo;
+            int right = start;
+            assert left <= right;
+            /*
+             * Invariants:
+             *   pivot >= all in [lo, left).
+             *   pivot <  all in [right, start).
+             */
+            while (left < right) {
+                int mid = (left + right) >>> 1;
+                if (pivot.compareTo(a[mid]) < 0)
+                    right = mid;
+                else
+                    left = mid + 1;
+            }
+            assert left == right;
+
+            /*
+             * The invariants still hold: pivot >= all in [lo, left) and
+             * pivot < all in [left, start), so pivot belongs at left.  Note
+             * that if there are elements equal to pivot, left points to the
+             * first slot after them -- that's why this sort is stable.
+             * Slide elements over to make room for pivot.
+             */
+            int n = start - left;  // The number of elements to move
+            // Switch is just an optimization for arraycopy in default case
+            switch (n) {
+                case 2:  a[left + 2] = a[left + 1];
+                case 1:  a[left + 1] = a[left];
+                         break;
+                default: System.arraycopy(a, left, a, left + 1, n);
+            }
+            a[left] = pivot;
+        }
+    }
+
+    /**
+     * Returns the length of the run beginning at the specified position in
+     * the specified array and reverses the run if it is descending (ensuring
+     * that the run will always be ascending when the method returns).
+     *
+     * A run is the longest ascending sequence with:
+     *
+     *    a[lo] <= a[lo + 1] <= a[lo + 2] <= ...
+     *
+     * or the longest descending sequence with:
+     *
+     *    a[lo] >  a[lo + 1] >  a[lo + 2] >  ...
+     *
+     * For its intended use in a stable mergesort, the strictness of the
+     * definition of "descending" is needed so that the call can safely
+     * reverse a descending sequence without violating stability.
+     *
+     * @param a the array in which a run is to be counted and possibly reversed
+     * @param lo index of the first element in the run
+     * @param hi index after the last element that may be contained in the run.
+              It is required that {@code lo < hi}.
+     * @return  the length of the run beginning at the specified position in
+     *          the specified array
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {
+        assert lo < hi;
+        int runHi = lo + 1;
+        if (runHi == hi)
+            return 1;
+
+        // Find end of run, and reverse range if descending
+        if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending
+            while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)
+                runHi++;
+            reverseRange(a, lo, runHi);
+        } else {                              // Ascending
+            while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 0)
+                runHi++;
+        }
+
+        return runHi - lo;
+    }
+
+    /**
+     * Reverse the specified range of the specified array.
+     *
+     * @param a the array in which a range is to be reversed
+     * @param lo the index of the first element in the range to be reversed
+     * @param hi the index after the last element in the range to be reversed
+     */
+    private static void reverseRange(Object[] a, int lo, int hi) {
+        hi--;
+        while (lo < hi) {
+            Object t = a[lo];
+            a[lo++] = a[hi];
+            a[hi--] = t;
+        }
+    }
+
+    /**
+     * Returns the minimum acceptable run length for an array of the specified
+     * length. Natural runs shorter than this will be extended with
+     * {@link #binarySort}.
+     *
+     * Roughly speaking, the computation is:
+     *
+     *  If n < MIN_MERGE, return n (it's too small to bother with fancy stuff).
+     *  Else if n is an exact power of 2, return MIN_MERGE/2.
+     *  Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k
+     *   is close to, but strictly less than, an exact power of 2.
+     *
+     * For the rationale, see listsort.txt.
+     *
+     * @param n the length of the array to be sorted
+     * @return the length of the minimum run to be merged
+     */
+    private static int minRunLength(int n) {
+        assert n >= 0;
+        int r = 0;      // Becomes 1 if any 1 bits are shifted off
+        while (n >= MIN_MERGE) {
+            r |= (n & 1);
+            n >>= 1;
+        }
+        return n + r;
+    }
+
+    /**
+     * Pushes the specified run onto the pending-run stack.
+     *
+     * @param runBase index of the first element in the run
+     * @param runLen  the number of elements in the run
+     */
+    private void pushRun(int runBase, int runLen) {
+        this.runBase[stackSize] = runBase;
+        this.runLen[stackSize] = runLen;
+        stackSize++;
+    }
+
+    /**
+     * Examines the stack of runs waiting to be merged and merges adjacent runs
+     * until the stack invariants are reestablished:
+     *
+     *     1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1]
+     *     2. runLen[i - 2] > runLen[i - 1]
+     *
+     * This method is called each time a new run is pushed onto the stack,
+     * so the invariants are guaranteed to hold for i < stackSize upon
+     * entry to the method.
+     */
+    private void mergeCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1]) {
+                if (runLen[n - 1] < runLen[n + 1])
+                    n--;
+                mergeAt(n);
+            } else if (runLen[n] <= runLen[n + 1]) {
+                mergeAt(n);
+            } else {
+                break; // Invariant is established
+            }
+        }
+    }
+
+    /**
+     * Merges all runs on the stack until only one remains.  This method is
+     * called once, to complete the sort.
+     */
+    private void mergeForceCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n - 1] < runLen[n + 1])
+                n--;
+            mergeAt(n);
+        }
+    }
+
+    /**
+     * Merges the two runs at stack indices i and i+1.  Run i must be
+     * the penultimate or antepenultimate run on the stack.  In other words,
+     * i must be equal to stackSize-2 or stackSize-3.
+     *
+     * @param i stack index of the first of the two runs to merge
+     */
+    @SuppressWarnings("unchecked")
+    private void mergeAt(int i) {
+        assert stackSize >= 2;
+        assert i >= 0;
+        assert i == stackSize - 2 || i == stackSize - 3;
+
+        int base1 = runBase[i];
+        int len1 = runLen[i];
+        int base2 = runBase[i + 1];
+        int len2 = runLen[i + 1];
+        assert len1 > 0 && len2 > 0;
+        assert base1 + len1 == base2;
+
+        /*
+         * Record the length of the combined runs; if i is the 3rd-last
+         * run now, also slide over the last run (which isn't involved
+         * in this merge).  The current run (i+1) goes away in any case.
+         */
+        runLen[i] = len1 + len2;
+        if (i == stackSize - 3) {
+            runBase[i + 1] = runBase[i + 2];
+            runLen[i + 1] = runLen[i + 2];
+        }
+        stackSize--;
+
+        /*
+         * Find where the first element of run2 goes in run1. Prior elements
+         * in run1 can be ignored (because they're already in place).
+         */
+        int k = gallopRight((Comparable<Object>) a[base2], a, base1, len1, 0);
+        assert k >= 0;
+        base1 += k;
+        len1 -= k;
+        if (len1 == 0)
+            return;
+
+        /*
+         * Find where the last element of run1 goes in run2. Subsequent elements
+         * in run2 can be ignored (because they're already in place).
+         */
+        len2 = gallopLeft((Comparable<Object>) a[base1 + len1 - 1], a,
+                base2, len2, len2 - 1);
+        assert len2 >= 0;
+        if (len2 == 0)
+            return;
+
+        // Merge remaining runs, using tmp array with min(len1, len2) elements
+        if (len1 <= len2)
+            mergeLo(base1, len1, base2, len2);
+        else
+            mergeHi(base1, len1, base2, len2);
+    }
+
+    /**
+     * Locates the position at which to insert the specified key into the
+     * specified sorted range; if the range contains an element equal to key,
+     * returns the index of the leftmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] < key <= a[b + k],
+     *    pretending that a[b - 1] is minus infinity and a[b + n] is infinity.
+     *    In other words, key belongs at index b + k; or in other words,
+     *    the first k elements of a should precede key, and the last n - k
+     *    should follow it.
+     */
+    private static int gallopLeft(Comparable<Object> key, Object[] a,
+            int base, int len, int hint) {
+        assert len > 0 && hint >= 0 && hint < len;
+
+        int lastOfs = 0;
+        int ofs = 1;
+        if (key.compareTo(a[base + hint]) > 0) {
+            // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && key.compareTo(a[base + hint + ofs]) > 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            lastOfs += hint;
+            ofs += hint;
+        } else { // key <= a[base + hint]
+            // Gallop left until a[base+hint-ofs] < key <= a[base+hint-lastOfs]
+            final int maxOfs = hint + 1;
+            while (ofs < maxOfs && key.compareTo(a[base + hint - ofs]) <= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[base+lastOfs] < key <= a[base+ofs], so key belongs somewhere
+         * to the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[base + lastOfs - 1] < key <= a[base + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (key.compareTo(a[base + m]) > 0)
+                lastOfs = m + 1;  // a[base + m] < key
+            else
+                ofs = m;          // key <= a[base + m]
+        }
+        assert lastOfs == ofs;    // so a[base + ofs - 1] < key <= a[base + ofs]
+        return ofs;
+    }
+
+    /**
+     * Like gallopLeft, except that if the range contains an element equal to
+     * key, gallopRight returns the index after the rightmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] <= key < a[b + k]
+     */
+    private static int gallopRight(Comparable<Object> key, Object[] a,
+            int base, int len, int hint) {
+        assert len > 0 && hint >= 0 && hint < len;
+
+        int ofs = 1;
+        int lastOfs = 0;
+        if (key.compareTo(a[base + hint]) < 0) {
+            // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs]
+            int maxOfs = hint + 1;
+            while (ofs < maxOfs && key.compareTo(a[base + hint - ofs]) < 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        } else { // a[b + hint] <= key
+            // Gallop right until a[b+hint + lastOfs] <= key < a[b+hint + ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && key.compareTo(a[base + hint + ofs]) >= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            lastOfs += hint;
+            ofs += hint;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[b + lastOfs] <= key < a[b + ofs], so key belongs somewhere to
+         * the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[b + lastOfs - 1] <= key < a[b + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (key.compareTo(a[base + m]) < 0)
+                ofs = m;          // key < a[b + m]
+            else
+                lastOfs = m + 1;  // a[b + m] <= key
+        }
+        assert lastOfs == ofs;    // so a[b + ofs - 1] <= key < a[b + ofs]
+        return ofs;
+    }
+
+    /**
+     * Merges two adjacent runs in place, in a stable fashion.  The first
+     * element of the first run must be greater than the first element of the
+     * second run (a[base1] > a[base2]), and the last element of the first run
+     * (a[base1 + len1-1]) must be greater than all elements of the second run.
+     *
+     * For performance, this method should be called only when len1 <= len2;
+     * its twin, mergeHi should be called if len1 >= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private void mergeLo(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy first run into temp array
+        Object[] a = this.a; // For performance
+        Object[] tmp = ensureCapacity(len1);
+
+        int cursor1 = tmpBase; // Indexes into tmp array
+        int cursor2 = base2;   // Indexes int a
+        int dest = base1;      // Indexes int a
+        System.arraycopy(a, base1, tmp, cursor1, len1);
+
+        // Move first element of second run and deal with degenerate cases
+        a[dest++] = a[cursor2++];
+        if (--len2 == 0) {
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+            return;
+        }
+        if (len1 == 1) {
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; // Last elt of run 1 to end of merge
+            return;
+        }
+
+        int minGallop = this.minGallop;  // Use local variable for performance
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run starts
+             * winning consistently.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                if (((Comparable) a[cursor2]).compareTo(tmp[cursor1]) < 0) {
+                    a[dest++] = a[cursor2++];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 0)
+                        break outer;
+                } else {
+                    a[dest++] = tmp[cursor1++];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                count1 = gallopRight((Comparable) a[cursor2], tmp, cursor1, len1, 0);
+                if (count1 != 0) {
+                    System.arraycopy(tmp, cursor1, a, dest, count1);
+                    dest += count1;
+                    cursor1 += count1;
+                    len1 -= count1;
+                    if (len1 <= 1)  // len1 == 1 || len1 == 0
+                        break outer;
+                }
+                a[dest++] = a[cursor2++];
+                if (--len2 == 0)
+                    break outer;
+
+                count2 = gallopLeft((Comparable) tmp[cursor1], a, cursor2, len2, 0);
+                if (count2 != 0) {
+                    System.arraycopy(a, cursor2, a, dest, count2);
+                    dest += count2;
+                    cursor2 += count2;
+                    len2 -= count2;
+                    if (len2 == 0)
+                        break outer;
+                }
+                a[dest++] = tmp[cursor1++];
+                if (--len1 == 1)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len1 == 1) {
+            assert len2 > 0;
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; //  Last elt of run 1 to end of merge
+        } else if (len1 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len2 == 0;
+            assert len1 > 1;
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+        }
+    }
+
+    /**
+     * Like mergeLo, except that this method should be called only if
+     * len1 >= len2; mergeLo should be called if len1 <= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private void mergeHi(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy second run into temp array
+        Object[] a = this.a; // For performance
+        Object[] tmp = ensureCapacity(len2);
+        int tmpBase = this.tmpBase;
+        System.arraycopy(a, base2, tmp, tmpBase, len2);
+
+        int cursor1 = base1 + len1 - 1;  // Indexes into a
+        int cursor2 = tmpBase + len2 - 1; // Indexes into tmp array
+        int dest = base2 + len2 - 1;     // Indexes into a
+
+        // Move last element of first run and deal with degenerate cases
+        a[dest--] = a[cursor1--];
+        if (--len1 == 0) {
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+            return;
+        }
+        if (len2 == 1) {
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];
+            return;
+        }
+
+        int minGallop = this.minGallop;  // Use local variable for performance
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run
+             * appears to win consistently.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                if (((Comparable) tmp[cursor2]).compareTo(a[cursor1]) < 0) {
+                    a[dest--] = a[cursor1--];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 0)
+                        break outer;
+                } else {
+                    a[dest--] = tmp[cursor2--];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                count1 = len1 - gallopRight((Comparable) tmp[cursor2], a, base1, len1, len1 - 1);
+                if (count1 != 0) {
+                    dest -= count1;
+                    cursor1 -= count1;
+                    len1 -= count1;
+                    System.arraycopy(a, cursor1 + 1, a, dest + 1, count1);
+                    if (len1 == 0)
+                        break outer;
+                }
+                a[dest--] = tmp[cursor2--];
+                if (--len2 == 1)
+                    break outer;
+
+                count2 = len2 - gallopLeft((Comparable) a[cursor1], tmp, tmpBase, len2, len2 - 1);
+                if (count2 != 0) {
+                    dest -= count2;
+                    cursor2 -= count2;
+                    len2 -= count2;
+                    System.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2);
+                    if (len2 <= 1)
+                        break outer; // len2 == 1 || len2 == 0
+                }
+                a[dest--] = a[cursor1--];
+                if (--len1 == 0)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len2 == 1) {
+            assert len1 > 0;
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];  // Move first elt of run2 to front of merge
+        } else if (len2 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len1 == 0;
+            assert len2 > 0;
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+        }
+    }
+
+    /**
+     * Ensures that the external array tmp has at least the specified
+     * number of elements, increasing its size if necessary.  The size
+     * increases exponentially to ensure amortized linear time complexity.
+     *
+     * @param minCapacity the minimum required capacity of the tmp array
+     * @return tmp, whether or not it grew
+     */
+    private Object[]  ensureCapacity(int minCapacity) {
+        if (tmpLen < minCapacity) {
+            // Compute smallest power of 2 > minCapacity
+            int newSize = minCapacity;
+            newSize |= newSize >> 1;
+            newSize |= newSize >> 2;
+            newSize |= newSize >> 4;
+            newSize |= newSize >> 8;
+            newSize |= newSize >> 16;
+            newSize++;
+
+            if (newSize < 0) // Not bloody likely!
+                newSize = minCapacity;
+            else
+                newSize = Math.min(newSize, a.length >>> 1);
+
+            @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
+            Object[] newArray = new Object[newSize];
+            tmp = newArray;
+            tmpLen = newSize;
+            tmpBase = 0;
+        }
+        return tmp;
+    }
+
+}
diff --git a/java/util/Comparator.java b/java/util/Comparator.java
new file mode 100644
index 0000000..ecf8d64
--- /dev/null
+++ b/java/util/Comparator.java
@@ -0,0 +1,534 @@
+/*
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.Function;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+import java.util.function.ToDoubleFunction;
+import java.util.Comparators;
+
+/**
+ * A comparison function, which imposes a <i>total ordering</i> on some
+ * collection of objects.  Comparators can be passed to a sort method (such
+ * as {@link Collections#sort(List,Comparator) Collections.sort} or {@link
+ * Arrays#sort(Object[],Comparator) Arrays.sort}) to allow precise control
+ * over the sort order.  Comparators can also be used to control the order of
+ * certain data structures (such as {@link SortedSet sorted sets} or {@link
+ * SortedMap sorted maps}), or to provide an ordering for collections of
+ * objects that don't have a {@link Comparable natural ordering}.<p>
+ *
+ * The ordering imposed by a comparator <tt>c</tt> on a set of elements
+ * <tt>S</tt> is said to be <i>consistent with equals</i> if and only if
+ * <tt>c.compare(e1, e2)==0</tt> has the same boolean value as
+ * <tt>e1.equals(e2)</tt> for every <tt>e1</tt> and <tt>e2</tt> in
+ * <tt>S</tt>.<p>
+ *
+ * Caution should be exercised when using a comparator capable of imposing an
+ * ordering inconsistent with equals to order a sorted set (or sorted map).
+ * Suppose a sorted set (or sorted map) with an explicit comparator <tt>c</tt>
+ * is used with elements (or keys) drawn from a set <tt>S</tt>.  If the
+ * ordering imposed by <tt>c</tt> on <tt>S</tt> is inconsistent with equals,
+ * the sorted set (or sorted map) will behave "strangely."  In particular the
+ * sorted set (or sorted map) will violate the general contract for set (or
+ * map), which is defined in terms of <tt>equals</tt>.<p>
+ *
+ * For example, suppose one adds two elements {@code a} and {@code b} such that
+ * {@code (a.equals(b) && c.compare(a, b) != 0)}
+ * to an empty {@code TreeSet} with comparator {@code c}.
+ * The second {@code add} operation will return
+ * true (and the size of the tree set will increase) because {@code a} and
+ * {@code b} are not equivalent from the tree set's perspective, even though
+ * this is contrary to the specification of the
+ * {@link Set#add Set.add} method.<p>
+ *
+ * Note: It is generally a good idea for comparators to also implement
+ * <tt>java.io.Serializable</tt>, as they may be used as ordering methods in
+ * serializable data structures (like {@link TreeSet}, {@link TreeMap}).  In
+ * order for the data structure to serialize successfully, the comparator (if
+ * provided) must implement <tt>Serializable</tt>.<p>
+ *
+ * For the mathematically inclined, the <i>relation</i> that defines the
+ * <i>imposed ordering</i> that a given comparator <tt>c</tt> imposes on a
+ * given set of objects <tt>S</tt> is:<pre>
+ *       {(x, y) such that c.compare(x, y) &lt;= 0}.
+ * </pre> The <i>quotient</i> for this total order is:<pre>
+ *       {(x, y) such that c.compare(x, y) == 0}.
+ * </pre>
+ *
+ * It follows immediately from the contract for <tt>compare</tt> that the
+ * quotient is an <i>equivalence relation</i> on <tt>S</tt>, and that the
+ * imposed ordering is a <i>total order</i> on <tt>S</tt>.  When we say that
+ * the ordering imposed by <tt>c</tt> on <tt>S</tt> is <i>consistent with
+ * equals</i>, we mean that the quotient for the ordering is the equivalence
+ * relation defined by the objects' {@link Object#equals(Object)
+ * equals(Object)} method(s):<pre>
+ *     {(x, y) such that x.equals(y)}. </pre>
+ *
+ * <p>Unlike {@code Comparable}, a comparator may optionally permit
+ * comparison of null arguments, while maintaining the requirements for
+ * an equivalence relation.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <T> the type of objects that may be compared by this comparator
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Comparable
+ * @see java.io.Serializable
+ * @since 1.2
+ */
+@FunctionalInterface
+public interface Comparator<T> {
+    /**
+     * Compares its two arguments for order.  Returns a negative integer,
+     * zero, or a positive integer as the first argument is less than, equal
+     * to, or greater than the second.<p>
+     *
+     * In the foregoing description, the notation
+     * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
+     * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
+     * <tt>0</tt>, or <tt>1</tt> according to whether the value of
+     * <i>expression</i> is negative, zero or positive.<p>
+     *
+     * The implementor must ensure that <tt>sgn(compare(x, y)) ==
+     * -sgn(compare(y, x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
+     * implies that <tt>compare(x, y)</tt> must throw an exception if and only
+     * if <tt>compare(y, x)</tt> throws an exception.)<p>
+     *
+     * The implementor must also ensure that the relation is transitive:
+     * <tt>((compare(x, y)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt> implies
+     * <tt>compare(x, z)&gt;0</tt>.<p>
+     *
+     * Finally, the implementor must ensure that <tt>compare(x, y)==0</tt>
+     * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all
+     * <tt>z</tt>.<p>
+     *
+     * It is generally the case, but <i>not</i> strictly required that
+     * <tt>(compare(x, y)==0) == (x.equals(y))</tt>.  Generally speaking,
+     * any comparator that violates this condition should clearly indicate
+     * this fact.  The recommended language is "Note: this comparator
+     * imposes orderings that are inconsistent with equals."
+     *
+     * @param o1 the first object to be compared.
+     * @param o2 the second object to be compared.
+     * @return a negative integer, zero, or a positive integer as the
+     *         first argument is less than, equal to, or greater than the
+     *         second.
+     * @throws NullPointerException if an argument is null and this
+     *         comparator does not permit null arguments
+     * @throws ClassCastException if the arguments' types prevent them from
+     *         being compared by this comparator.
+     */
+    int compare(T o1, T o2);
+
+    /**
+     * Indicates whether some other object is &quot;equal to&quot; this
+     * comparator.  This method must obey the general contract of
+     * {@link Object#equals(Object)}.  Additionally, this method can return
+     * <tt>true</tt> <i>only</i> if the specified object is also a comparator
+     * and it imposes the same ordering as this comparator.  Thus,
+     * <code>comp1.equals(comp2)</code> implies that <tt>sgn(comp1.compare(o1,
+     * o2))==sgn(comp2.compare(o1, o2))</tt> for every object reference
+     * <tt>o1</tt> and <tt>o2</tt>.<p>
+     *
+     * Note that it is <i>always</i> safe <i>not</i> to override
+     * <tt>Object.equals(Object)</tt>.  However, overriding this method may,
+     * in some cases, improve performance by allowing programs to determine
+     * that two distinct comparators impose the same order.
+     *
+     * @param   obj   the reference object with which to compare.
+     * @return  <code>true</code> only if the specified object is also
+     *          a comparator and it imposes the same ordering as this
+     *          comparator.
+     * @see Object#equals(Object)
+     * @see Object#hashCode()
+     */
+    boolean equals(Object obj);
+
+    /**
+     * Returns a comparator that imposes the reverse ordering of this
+     * comparator.
+     *
+     * @return a comparator that imposes the reverse ordering of this
+     *         comparator.
+     * @since 1.8
+     */
+    default Comparator<T> reversed() {
+        return Collections.reverseOrder(this);
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with another comparator.
+     * If this {@code Comparator} considers two elements equal, i.e.
+     * {@code compare(a, b) == 0}, {@code other} is used to determine the order.
+     *
+     * <p>The returned comparator is serializable if the specified comparator
+     * is also serializable.
+     *
+     * @apiNote
+     * For example, to sort a collection of {@code String} based on the length
+     * and then case-insensitive natural ordering, the comparator can be
+     * composed using following code,
+     *
+     * <pre>{@code
+     *     Comparator<String> cmp = Comparator.comparingInt(String::length)
+     *             .thenComparing(String.CASE_INSENSITIVE_ORDER);
+     * }</pre>
+     *
+     * @param  other the other comparator to be used when this comparator
+     *         compares two objects that are equal.
+     * @return a lexicographic-order comparator composed of this and then the
+     *         other comparator
+     * @throws NullPointerException if the argument is null.
+     * @since 1.8
+     */
+    default Comparator<T> thenComparing(Comparator<? super T> other) {
+        Objects.requireNonNull(other);
+        return (Comparator<T> & Serializable) (c1, c2) -> {
+            int res = compare(c1, c2);
+            return (res != 0) ? res : other.compare(c1, c2);
+        };
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a key to be compared with the given {@code Comparator}.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparing(keyExtractor, cmp))}.
+     *
+     * @param  <U>  the type of the sort key
+     * @param  keyExtractor the function used to extract the sort key
+     * @param  keyComparator the {@code Comparator} used to compare the sort key
+     * @return a lexicographic-order comparator composed of this comparator
+     *         and then comparing on the key extracted by the keyExtractor function
+     * @throws NullPointerException if either argument is null.
+     * @see #comparing(Function, Comparator)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default <U> Comparator<T> thenComparing(
+            Function<? super T, ? extends U> keyExtractor,
+            Comparator<? super U> keyComparator)
+    {
+        return thenComparing(comparing(keyExtractor, keyComparator));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a {@code Comparable} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparing(keyExtractor))}.
+     *
+     * @param  <U>  the type of the {@link Comparable} sort key
+     * @param  keyExtractor the function used to extract the {@link
+     *         Comparable} sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@link Comparable} sort key.
+     * @throws NullPointerException if the argument is null.
+     * @see #comparing(Function)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default <U extends Comparable<? super U>> Comparator<T> thenComparing(
+            Function<? super T, ? extends U> keyExtractor)
+    {
+        return thenComparing(comparing(keyExtractor));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a {@code int} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparingInt(keyExtractor))}.
+     *
+     * @param  keyExtractor the function used to extract the integer sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@code int} sort key
+     * @throws NullPointerException if the argument is null.
+     * @see #comparingInt(ToIntFunction)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
+        return thenComparing(comparingInt(keyExtractor));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a {@code long} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparingLong(keyExtractor))}.
+     *
+     * @param  keyExtractor the function used to extract the long sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@code long} sort key
+     * @throws NullPointerException if the argument is null.
+     * @see #comparingLong(ToLongFunction)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
+        return thenComparing(comparingLong(keyExtractor));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a {@code double} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparingDouble(keyExtractor))}.
+     *
+     * @param  keyExtractor the function used to extract the double sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@code double} sort key
+     * @throws NullPointerException if the argument is null.
+     * @see #comparingDouble(ToDoubleFunction)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
+        return thenComparing(comparingDouble(keyExtractor));
+    }
+
+    /**
+     * Returns a comparator that imposes the reverse of the <em>natural
+     * ordering</em>.
+     *
+     * <p>The returned comparator is serializable and throws {@link
+     * NullPointerException} when comparing {@code null}.
+     *
+     * @param  <T> the {@link Comparable} type of element to be compared
+     * @return a comparator that imposes the reverse of the <i>natural
+     *         ordering</i> on {@code Comparable} objects.
+     * @see Comparable
+     * @since 1.8
+     */
+    public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
+        return Collections.reverseOrder();
+    }
+
+    /**
+     * Returns a comparator that compares {@link Comparable} objects in natural
+     * order.
+     *
+     * <p>The returned comparator is serializable and throws {@link
+     * NullPointerException} when comparing {@code null}.
+     *
+     * @param  <T> the {@link Comparable} type of element to be compared
+     * @return a comparator that imposes the <i>natural ordering</i> on {@code
+     *         Comparable} objects.
+     * @see Comparable
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
+        return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
+    }
+
+    /**
+     * Returns a null-friendly comparator that considers {@code null} to be
+     * less than non-null. When both are {@code null}, they are considered
+     * equal. If both are non-null, the specified {@code Comparator} is used
+     * to determine the order. If the specified comparator is {@code null},
+     * then the returned comparator considers all non-null values to be equal.
+     *
+     * <p>The returned comparator is serializable if the specified comparator
+     * is serializable.
+     *
+     * @param  <T> the type of the elements to be compared
+     * @param  comparator a {@code Comparator} for comparing non-null values
+     * @return a comparator that considers {@code null} to be less than
+     *         non-null, and compares non-null objects with the supplied
+     *         {@code Comparator}.
+     * @since 1.8
+     */
+    public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
+        return new Comparators.NullComparator<>(true, comparator);
+    }
+
+    /**
+     * Returns a null-friendly comparator that considers {@code null} to be
+     * greater than non-null. When both are {@code null}, they are considered
+     * equal. If both are non-null, the specified {@code Comparator} is used
+     * to determine the order. If the specified comparator is {@code null},
+     * then the returned comparator considers all non-null values to be equal.
+     *
+     * <p>The returned comparator is serializable if the specified comparator
+     * is serializable.
+     *
+     * @param  <T> the type of the elements to be compared
+     * @param  comparator a {@code Comparator} for comparing non-null values
+     * @return a comparator that considers {@code null} to be greater than
+     *         non-null, and compares non-null objects with the supplied
+     *         {@code Comparator}.
+     * @since 1.8
+     */
+    public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
+        return new Comparators.NullComparator<>(false, comparator);
+    }
+
+    /**
+     * Accepts a function that extracts a sort key from a type {@code T}, and
+     * returns a {@code Comparator<T>} that compares by that sort key using
+     * the specified {@link Comparator}.
+      *
+     * <p>The returned comparator is serializable if the specified function
+     * and comparator are both serializable.
+     *
+     * @apiNote
+     * For example, to obtain a {@code Comparator} that compares {@code
+     * Person} objects by their last name ignoring case differences,
+     *
+     * <pre>{@code
+     *     Comparator<Person> cmp = Comparator.comparing(
+     *             Person::getLastName,
+     *             String.CASE_INSENSITIVE_ORDER);
+     * }</pre>
+     *
+     * @param  <T> the type of element to be compared
+     * @param  <U> the type of the sort key
+     * @param  keyExtractor the function used to extract the sort key
+     * @param  keyComparator the {@code Comparator} used to compare the sort key
+     * @return a comparator that compares by an extracted key using the
+     *         specified {@code Comparator}
+     * @throws NullPointerException if either argument is null
+     * @since 1.8
+     */
+    public static <T, U> Comparator<T> comparing(
+            Function<? super T, ? extends U> keyExtractor,
+            Comparator<? super U> keyComparator)
+    {
+        Objects.requireNonNull(keyExtractor);
+        Objects.requireNonNull(keyComparator);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
+                                              keyExtractor.apply(c2));
+    }
+
+    /**
+     * Accepts a function that extracts a {@link java.lang.Comparable
+     * Comparable} sort key from a type {@code T}, and returns a {@code
+     * Comparator<T>} that compares by that sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function
+     * is also serializable.
+     *
+     * @apiNote
+     * For example, to obtain a {@code Comparator} that compares {@code
+     * Person} objects by their last name,
+     *
+     * <pre>{@code
+     *     Comparator<Person> byLastName = Comparator.comparing(Person::getLastName);
+     * }</pre>
+     *
+     * @param  <T> the type of element to be compared
+     * @param  <U> the type of the {@code Comparable} sort key
+     * @param  keyExtractor the function used to extract the {@link
+     *         Comparable} sort key
+     * @return a comparator that compares by an extracted key
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
+            Function<? super T, ? extends U> keyExtractor)
+    {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
+    }
+
+    /**
+     * Accepts a function that extracts an {@code int} sort key from a type
+     * {@code T}, and returns a {@code Comparator<T>} that compares by that
+     * sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function
+     * is also serializable.
+     *
+     * @param  <T> the type of element to be compared
+     * @param  keyExtractor the function used to extract the integer sort key
+     * @return a comparator that compares by an extracted key
+     * @see #comparing(Function)
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
+    }
+
+    /**
+     * Accepts a function that extracts a {@code long} sort key from a type
+     * {@code T}, and returns a {@code Comparator<T>} that compares by that
+     * sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function is
+     * also serializable.
+     *
+     * @param  <T> the type of element to be compared
+     * @param  keyExtractor the function used to extract the long sort key
+     * @return a comparator that compares by an extracted key
+     * @see #comparing(Function)
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
+    }
+
+    /**
+     * Accepts a function that extracts a {@code double} sort key from a type
+     * {@code T}, and returns a {@code Comparator<T>} that compares by that
+     * sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function
+     * is also serializable.
+     *
+     * @param  <T> the type of element to be compared
+     * @param  keyExtractor the function used to extract the double sort key
+     * @return a comparator that compares by an extracted key
+     * @see #comparing(Function)
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
+    }
+}
diff --git a/java/util/Comparators.java b/java/util/Comparators.java
new file mode 100644
index 0000000..ee80679
--- /dev/null
+++ b/java/util/Comparators.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+/**
+ * Package private supporting class for {@link Comparator}.
+ */
+class Comparators {
+    private Comparators() {
+        throw new AssertionError("no instances");
+    }
+
+    /**
+     * Compares {@link Comparable} objects in natural order.
+     *
+     * @see Comparable
+     */
+    enum NaturalOrderComparator implements Comparator<Comparable<Object>> {
+        INSTANCE;
+
+        @Override
+        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
+            return c1.compareTo(c2);
+        }
+
+        @Override
+        public Comparator<Comparable<Object>> reversed() {
+            return Comparator.reverseOrder();
+        }
+    }
+
+    /**
+     * Null-friendly comparators
+     */
+    final static class NullComparator<T> implements Comparator<T>, Serializable {
+        private static final long serialVersionUID = -7569533591570686392L;
+        private final boolean nullFirst;
+        // if null, non-null Ts are considered equal
+        private final Comparator<T> real;
+
+        @SuppressWarnings("unchecked")
+        NullComparator(boolean nullFirst, Comparator<? super T> real) {
+            this.nullFirst = nullFirst;
+            this.real = (Comparator<T>) real;
+        }
+
+        @Override
+        public int compare(T a, T b) {
+            if (a == null) {
+                return (b == null) ? 0 : (nullFirst ? -1 : 1);
+            } else if (b == null) {
+                return nullFirst ? 1: -1;
+            } else {
+                return (real == null) ? 0 : real.compare(a, b);
+            }
+        }
+
+        @Override
+        public Comparator<T> thenComparing(Comparator<? super T> other) {
+            Objects.requireNonNull(other);
+            return new NullComparator<>(nullFirst, real == null ? other : real.thenComparing(other));
+        }
+
+        @Override
+        public Comparator<T> reversed() {
+            return new NullComparator<>(!nullFirst, real == null ? null : real.reversed());
+        }
+    }
+}
diff --git a/java/util/ConcurrentModificationException.java b/java/util/ConcurrentModificationException.java
new file mode 100644
index 0000000..7e65d2a
--- /dev/null
+++ b/java/util/ConcurrentModificationException.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This exception may be thrown by methods that have detected concurrent
+ * modification of an object when such modification is not permissible.
+ * <p>
+ * For example, it is not generally permissible for one thread to modify a Collection
+ * while another thread is iterating over it.  In general, the results of the
+ * iteration are undefined under these circumstances.  Some Iterator
+ * implementations (including those of all the general purpose collection implementations
+ * provided by the JRE) may choose to throw this exception if this behavior is
+ * detected.  Iterators that do this are known as <i>fail-fast</i> iterators,
+ * as they fail quickly and cleanly, rather that risking arbitrary,
+ * non-deterministic behavior at an undetermined time in the future.
+ * <p>
+ * Note that this exception does not always indicate that an object has
+ * been concurrently modified by a <i>different</i> thread.  If a single
+ * thread issues a sequence of method invocations that violates the
+ * contract of an object, the object may throw this exception.  For
+ * example, if a thread modifies a collection directly while it is
+ * iterating over the collection with a fail-fast iterator, the iterator
+ * will throw this exception.
+ *
+ * <p>Note that fail-fast behavior cannot be guaranteed as it is, generally
+ * speaking, impossible to make any hard guarantees in the presence of
+ * unsynchronized concurrent modification.  Fail-fast operations
+ * 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>{@code ConcurrentModificationException}
+ * should be used only to detect bugs.</i>
+ *
+ * @author  Josh Bloch
+ * @see     Collection
+ * @see     Iterator
+ * @see     Spliterator
+ * @see     ListIterator
+ * @see     Vector
+ * @see     LinkedList
+ * @see     HashSet
+ * @see     Hashtable
+ * @see     TreeMap
+ * @see     AbstractList
+ * @since   1.2
+ */
+public class ConcurrentModificationException extends RuntimeException {
+    private static final long serialVersionUID = -3666751008965953603L;
+
+    /**
+     * Constructs a ConcurrentModificationException with no
+     * detail message.
+     */
+    public ConcurrentModificationException() {
+    }
+
+    /**
+     * Constructs a {@code ConcurrentModificationException} with the
+     * specified detail message.
+     *
+     * @param message the detail message pertaining to this exception.
+     */
+    public ConcurrentModificationException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of {@code (cause==null ? null : cause.toString())} (which
+     * typically contains the class and detail message of {@code cause}.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.7
+     */
+    public ConcurrentModificationException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.
+     *
+     * <p>Note that the detail message associated with <code>cause</code> is
+     * <i>not</i> automatically incorporated in this exception's detail
+     * message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link Throwable#getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A {@code null} value
+     *         is permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since 1.7
+     */
+    public ConcurrentModificationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/java/util/Currency.java b/java/util/Currency.java
new file mode 100644
index 0000000..94629c7
--- /dev/null
+++ b/java/util/Currency.java
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.Serializable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import libcore.icu.ICU;
+
+// BEGIN Android-changed: Removed docs about superseding runtime currency data.
+// Doing so via a properties file is not supported on Android.
+/**
+ * Represents a currency. Currencies are identified by their ISO 4217 currency
+ * codes. Visit the <a href="http://www.iso.org/iso/home/standards/currency_codes.htm">
+ * ISO web site</a> for more information.
+ * <p>
+ * The class is designed so that there's never more than one
+ * <code>Currency</code> instance for any given currency. Therefore, there's
+ * no public constructor. You obtain a <code>Currency</code> instance using
+ * the <code>getInstance</code> methods.
+ *
+ * @since 1.4
+ */
+// END Android-changed: Removed docs about superseding runtime currency data.
+public final class Currency implements Serializable {
+
+    private static final long serialVersionUID = -158308464356906721L;
+
+    /**
+     * ISO 4217 currency code for this currency.
+     *
+     * @serial
+     */
+    private final String currencyCode;
+
+    // BEGIN Android-changed: Use ICU.
+    // We do not keep track of defaultFractionDigits and numericCode separately.
+    /*
+    /**
+     * Default fraction digits for this currency.
+     * Set from currency data tables.
+     *
+    transient private final int defaultFractionDigits;
+
+    /**
+     * ISO 4217 numeric code for this currency.
+     * Set from currency data tables.
+     *
+    transient private final int numericCode;
+    */
+    private transient final android.icu.util.Currency icuCurrency;
+    // END Android-changed: Use ICU.
+
+
+    // class data: instance map
+
+    private static ConcurrentMap<String, Currency> instances = new ConcurrentHashMap<>(7);
+    private static HashSet<Currency> available;
+
+    // BEGIN Android-removed: Use ICU.
+    // We don't need any of these static fields nor the static initializer.
+    /*
+    // Class data: currency data obtained from currency.data file.
+    // Purpose:
+    // - determine valid country codes
+    // - determine valid currency codes
+    // - map country codes to currency codes
+    // - obtain default fraction digits for currency codes
+    //
+    // sc = special case; dfd = default fraction digits
+    // Simple countries are those where the country code is a prefix of the
+    // currency code, and there are no known plans to change the currency.
+    //
+    // table formats:
+    // - mainTable:
+    //   - maps country code to 32-bit int
+    //   - 26*26 entries, corresponding to [A-Z]*[A-Z]
+    //   - \u007F -> not valid country
+    //   - bits 20-31: unused
+    //   - bits 10-19: numeric code (0 to 1023)
+    //   - bit 9: 1 - special case, bits 0-4 indicate which one
+    //            0 - simple country, bits 0-4 indicate final char of currency code
+    //   - bits 5-8: fraction digits for simple countries, 0 for special cases
+    //   - bits 0-4: final char for currency code for simple country, or ID of special case
+    // - special case IDs:
+    //   - 0: country has no currency
+    //   - other: index into sc* arrays + 1
+    // - scCutOverTimes: cut-over time in millis as returned by
+    //   System.currentTimeMillis for special case countries that are changing
+    //   currencies; Long.MAX_VALUE for countries that are not changing currencies
+    // - scOldCurrencies: old currencies for special case countries
+    // - scNewCurrencies: new currencies for special case countries that are
+    //   changing currencies; null for others
+    // - scOldCurrenciesDFD: default fraction digits for old currencies
+    // - scNewCurrenciesDFD: default fraction digits for new currencies, 0 for
+    //   countries that are not changing currencies
+    // - otherCurrencies: concatenation of all currency codes that are not the
+    //   main currency of a simple country, separated by "-"
+    // - otherCurrenciesDFD: decimal format digits for currencies in otherCurrencies, same order
+
+    static int formatVersion;
+    static int dataVersion;
+    static int[] mainTable;
+    static long[] scCutOverTimes;
+    static String[] scOldCurrencies;
+    static String[] scNewCurrencies;
+    static int[] scOldCurrenciesDFD;
+    static int[] scNewCurrenciesDFD;
+    static int[] scOldCurrenciesNumericCode;
+    static int[] scNewCurrenciesNumericCode;
+    static String otherCurrencies;
+    static int[] otherCurrenciesDFD;
+    static int[] otherCurrenciesNumericCode;
+
+    // handy constants - must match definitions in GenerateCurrencyData
+    // magic number
+    private static final int MAGIC_NUMBER = 0x43757244;
+    // number of characters from A to Z
+    private static final int A_TO_Z = ('Z' - 'A') + 1;
+    // entry for invalid country codes
+    private static final int INVALID_COUNTRY_ENTRY = 0x0000007F;
+    // entry for countries without currency
+    private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x00000200;
+    // mask for simple case country entries
+    private static final int SIMPLE_CASE_COUNTRY_MASK = 0x00000000;
+    // mask for simple case country entry final character
+    private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x0000001F;
+    // mask for simple case country entry default currency digits
+    private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x000001E0;
+    // shift count for simple case country entry default currency digits
+    private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5;
+    // maximum number for simple case country entry default currency digits
+    private static final int SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS = 9;
+    // mask for special case country entries
+    private static final int SPECIAL_CASE_COUNTRY_MASK = 0x00000200;
+    // mask for special case country index
+    private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x0000001F;
+    // delta from entry index component in main table to index into special case tables
+    private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1;
+    // mask for distinguishing simple and special case countries
+    private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK;
+    // mask for the numeric code of the currency
+    private static final int NUMERIC_CODE_MASK = 0x000FFC00;
+    // shift count for the numeric code of the currency
+    private static final int NUMERIC_CODE_SHIFT = 10;
+
+    // Currency data format version
+    private static final int VALID_FORMAT_VERSION = 2;
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                String homeDir = System.getProperty("java.home");
+                try {
+                    String dataFile = homeDir + File.separator +
+                            "lib" + File.separator + "currency.data";
+                    try (DataInputStream dis = new DataInputStream(
+                             new BufferedInputStream(
+                             new FileInputStream(dataFile)))) {
+                        if (dis.readInt() != MAGIC_NUMBER) {
+                            throw new InternalError("Currency data is possibly corrupted");
+                        }
+                        formatVersion = dis.readInt();
+                        if (formatVersion != VALID_FORMAT_VERSION) {
+                            throw new InternalError("Currency data format is incorrect");
+                        }
+                        dataVersion = dis.readInt();
+                        mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
+                        int scCount = dis.readInt();
+                        scCutOverTimes = readLongArray(dis, scCount);
+                        scOldCurrencies = readStringArray(dis, scCount);
+                        scNewCurrencies = readStringArray(dis, scCount);
+                        scOldCurrenciesDFD = readIntArray(dis, scCount);
+                        scNewCurrenciesDFD = readIntArray(dis, scCount);
+                        scOldCurrenciesNumericCode = readIntArray(dis, scCount);
+                        scNewCurrenciesNumericCode = readIntArray(dis, scCount);
+                        int ocCount = dis.readInt();
+                        otherCurrencies = dis.readUTF();
+                        otherCurrenciesDFD = readIntArray(dis, ocCount);
+                        otherCurrenciesNumericCode = readIntArray(dis, ocCount);
+                    }
+                } catch (IOException e) {
+                    throw new InternalError(e);
+                }
+
+                // look for the properties file for overrides
+                String propsFile = System.getProperty("java.util.currency.data");
+                if (propsFile == null) {
+                    propsFile = homeDir + File.separator + "lib" +
+                        File.separator + "currency.properties";
+                }
+                try {
+                    File propFile = new File(propsFile);
+                    if (propFile.exists()) {
+                        Properties props = new Properties();
+                        try (FileReader fr = new FileReader(propFile)) {
+                            props.load(fr);
+                        }
+                        Set<String> keys = props.stringPropertyNames();
+                        Pattern propertiesPattern =
+                            Pattern.compile("([A-Z]{3})\\s*,\\s*(\\d{3})\\s*,\\s*" +
+                                "(\\d+)\\s*,?\\s*(\\d{4}-\\d{2}-\\d{2}T\\d{2}:" +
+                                "\\d{2}:\\d{2})?");
+                        for (String key : keys) {
+                           replaceCurrencyData(propertiesPattern,
+                               key.toUpperCase(Locale.ROOT),
+                               props.getProperty(key).toUpperCase(Locale.ROOT));
+                        }
+                    }
+                } catch (IOException e) {
+                    info("currency.properties is ignored because of an IOException", e);
+                }
+                return null;
+            }
+        });
+    }
+
+    /**
+     * Constants for retrieving localized names from the name providers.
+     *
+    private static final int SYMBOL = 0;
+    private static final int DISPLAYNAME = 1;
+    */
+    // END Android-removed: Use ICU.
+
+    /**
+     * Constructs a <code>Currency</code> instance. The constructor is private
+     * so that we can insure that there's never more than one instance for a
+     * given currency.
+     */
+    // BEGIN Android-changed: Use ICU.
+    // We do not keep track of defaultFractionDigits and numericCode separately.
+    /*
+    private Currency(String currencyCode, int defaultFractionDigits, int numericCode) {
+        this.currencyCode = currencyCode;
+        this.defaultFractionDigits = defaultFractionDigits;
+        this.numericCode = numericCode;
+    }
+    */
+    private Currency(android.icu.util.Currency icuCurrency) {
+        this.icuCurrency = icuCurrency;
+        this.currencyCode = icuCurrency.getCurrencyCode();
+    }
+    // END Android-changed: Use ICU.
+
+    /**
+     * Returns the <code>Currency</code> instance for the given currency code.
+     *
+     * @param currencyCode the ISO 4217 code of the currency
+     * @return the <code>Currency</code> instance for the given currency code
+     * @exception NullPointerException if <code>currencyCode</code> is null
+     * @exception IllegalArgumentException if <code>currencyCode</code> is not
+     * a supported ISO 4217 code.
+     */
+    public static Currency getInstance(String currencyCode) {
+        // BEGIN Android-changed: Use ICU.
+        // Upstream uses a private static helper method, implemented differently.
+        Currency instance = instances.get(currencyCode);
+        if (instance != null) {
+            return instance;
+        }
+        android.icu.util.Currency icuInstance =
+                  android.icu.util.Currency.getInstance(currencyCode);
+        if (icuInstance == null) {
+            return null;
+        }
+        Currency currencyVal = new Currency(icuInstance);
+        // END Android-changed: Use ICU.
+        instance = instances.putIfAbsent(currencyCode, currencyVal);
+        return (instance != null ? instance : currencyVal);
+    }
+
+    /**
+     * Returns the <code>Currency</code> instance for the country of the
+     * given locale. The language and variant components of the locale
+     * are ignored. The result may vary over time, as countries change their
+     * currencies. For example, for the original member countries of the
+     * European Monetary Union, the method returns the old national currencies
+     * until December 31, 2001, and the Euro from January 1, 2002, local time
+     * of the respective countries.
+     * <p>
+     * The method returns <code>null</code> for territories that don't
+     * have a currency, such as Antarctica.
+     *
+     * @param locale the locale for whose country a <code>Currency</code>
+     * instance is needed
+     * @return the <code>Currency</code> instance for the country of the given
+     * locale, or {@code null}
+     * @exception NullPointerException if <code>locale</code> or its country
+     * code is {@code null}
+     * @exception IllegalArgumentException if the country of the given {@code locale}
+     * is not a supported ISO 3166 country code.
+     */
+    public static Currency getInstance(Locale locale) {
+        String country = locale.getCountry();
+        if (country == null) {
+            throw new NullPointerException();
+        }
+
+        // BEGIN Android-changed: Use ICU.
+        /*
+        if (country.length() != 2) {
+            throw new IllegalArgumentException();
+        }
+
+        char char1 = country.charAt(0);
+        char char2 = country.charAt(1);
+        int tableEntry = getMainTableEntry(char1, char2);
+        if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
+                    && tableEntry != INVALID_COUNTRY_ENTRY) {
+            char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
+            int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
+            int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
+            StringBuilder sb = new StringBuilder(country);
+            sb.append(finalChar);
+            return getInstance(sb.toString(), defaultFractionDigits, numericCode);
+        } else {
+            // special cases
+            if (tableEntry == INVALID_COUNTRY_ENTRY) {
+                throw new IllegalArgumentException();
+            }
+            if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
+                return null;
+            } else {
+                int index = (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
+                if (scCutOverTimes[index] == Long.MAX_VALUE || System.currentTimeMillis() < scCutOverTimes[index]) {
+                    return getInstance(scOldCurrencies[index], scOldCurrenciesDFD[index],
+                        scOldCurrenciesNumericCode[index]);
+                } else {
+                    return getInstance(scNewCurrencies[index], scNewCurrenciesDFD[index],
+                        scNewCurrenciesNumericCode[index]);
+                }
+            }
+        }
+        */
+        android.icu.util.Currency icuInstance =
+                android.icu.util.Currency.getInstance(locale);
+        String variant = locale.getVariant();
+        if (!variant.isEmpty() && (variant.equals("EURO") || variant.equals("HK") ||
+                variant.equals("PREEURO"))) {
+            country = country + "_" + variant;
+        }
+        String currencyCode = ICU.getCurrencyCode(country);
+        if (currencyCode == null) {
+            throw new IllegalArgumentException("Unsupported ISO 3166 country: " + locale);
+        }
+        if (icuInstance == null || icuInstance.getCurrencyCode().equals("XXX")) {
+            return null;
+        }
+        return getInstance(currencyCode);
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Gets the set of available currencies.  The returned set of currencies
+     * contains all of the available currencies, which may include currencies
+     * that represent obsolete ISO 4217 codes.  The set can be modified
+     * without affecting the available currencies in the runtime.
+     *
+     * @return the set of available currencies.  If there is no currency
+     *    available in the runtime, the returned set is empty.
+     * @since 1.7
+     */
+    public static Set<Currency> getAvailableCurrencies() {
+        synchronized(Currency.class) {
+            if (available == null) {
+                // BEGIN Android-changed: Use ICU.
+                /*
+                available = new HashSet<>(256);
+
+                // Add simple currencies first
+                for (char c1 = 'A'; c1 <= 'Z'; c1 ++) {
+                    for (char c2 = 'A'; c2 <= 'Z'; c2 ++) {
+                        int tableEntry = getMainTableEntry(c1, c2);
+                        if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
+                             && tableEntry != INVALID_COUNTRY_ENTRY) {
+                            char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
+                            int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
+                            int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
+                            StringBuilder sb = new StringBuilder();
+                            sb.append(c1);
+                            sb.append(c2);
+                            sb.append(finalChar);
+                            available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
+                        }
+                    }
+                }
+
+                // Now add other currencies
+                StringTokenizer st = new StringTokenizer(otherCurrencies, "-");
+                while (st.hasMoreElements()) {
+                    available.add(getInstance((String)st.nextElement()));
+                }
+                */
+                available = new HashSet<>();
+                Set<android.icu.util.Currency> icuAvailableCurrencies
+                        = android.icu.util.Currency.getAvailableCurrencies();
+                for (android.icu.util.Currency icuCurrency : icuAvailableCurrencies) {
+                    Currency currency = getInstance(icuCurrency.getCurrencyCode());
+                    if (currency == null) {
+                        currency = new Currency(icuCurrency);
+                        instances.put(currency.currencyCode, currency);
+                    }
+                    available.add(currency);
+                }
+                // END Android-changed: Use ICU.
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        Set<Currency> result = (Set<Currency>) available.clone();
+        return result;
+    }
+
+    /**
+     * Gets the ISO 4217 currency code of this currency.
+     *
+     * @return the ISO 4217 currency code of this currency.
+     */
+    public String getCurrencyCode() {
+        return currencyCode;
+    }
+
+    /**
+     * Gets the symbol of this currency for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * For example, for the US Dollar, the symbol is "$" if the default
+     * locale is the US, while for other locales it may be "US$". If no
+     * symbol can be determined, the ISO 4217 currency code is returned.
+     * <p>
+     * This is equivalent to calling
+     * {@link #getSymbol(Locale)
+     *     getSymbol(Locale.getDefault(Locale.Category.DISPLAY))}.
+     *
+     * @return the symbol of this currency for the default
+     *     {@link Locale.Category#DISPLAY DISPLAY} locale
+     */
+    public String getSymbol() {
+        return getSymbol(Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    /**
+     * Gets the symbol of this currency for the specified locale.
+     * For example, for the US Dollar, the symbol is "$" if the specified
+     * locale is the US, while for other locales it may be "US$". If no
+     * symbol can be determined, the ISO 4217 currency code is returned.
+     *
+     * @param locale the locale for which a display name for this currency is
+     * needed
+     * @return the symbol of this currency for the specified locale
+     * @exception NullPointerException if <code>locale</code> is null
+     */
+    public String getSymbol(Locale locale) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        LocaleServiceProviderPool pool =
+            LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
+        String symbol = pool.getLocalizedObject(
+                                CurrencyNameGetter.INSTANCE,
+                                locale, currencyCode, SYMBOL);
+        if (symbol != null) {
+            return symbol;
+        }
+
+        // use currency code as symbol of last resort
+        return currencyCode;
+        */
+        if (locale == null) {
+            throw new NullPointerException("locale == null");
+        }
+        return icuCurrency.getSymbol(locale);
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Gets the default number of fraction digits used with this currency.
+     * For example, the default number of fraction digits for the Euro is 2,
+     * while for the Japanese Yen it's 0.
+     * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
+     * -1 is returned.
+     *
+     * @return the default number of fraction digits used with this currency
+     */
+    public int getDefaultFractionDigits() {
+        // BEGIN Android-changed: Use ICU.
+        // return defaultFractionDigits;
+        if (icuCurrency.getCurrencyCode().equals("XXX")) {
+            return -1;
+        }
+        return icuCurrency.getDefaultFractionDigits();
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Returns the ISO 4217 numeric code of this currency.
+     *
+     * @return the ISO 4217 numeric code of this currency
+     * @since 1.7
+     */
+    public int getNumericCode() {
+        // Android-changed: Use ICU.
+        // return numericCode;
+        return icuCurrency.getNumericCode();
+    }
+
+    /**
+     * Gets the name that is suitable for displaying this currency for
+     * the default {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * If there is no suitable display name found
+     * for the default locale, the ISO 4217 currency code is returned.
+     * <p>
+     * This is equivalent to calling
+     * {@link #getDisplayName(Locale)
+     *     getDisplayName(Locale.getDefault(Locale.Category.DISPLAY))}.
+     *
+     * @return the display name of this currency for the default
+     *     {@link Locale.Category#DISPLAY DISPLAY} locale
+     * @since 1.7
+     */
+    public String getDisplayName() {
+        return getDisplayName(Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    /**
+     * Gets the name that is suitable for displaying this currency for
+     * the specified locale.  If there is no suitable display name found
+     * for the specified locale, the ISO 4217 currency code is returned.
+     *
+     * @param locale the locale for which a display name for this currency is
+     * needed
+     * @return the display name of this currency for the specified locale
+     * @exception NullPointerException if <code>locale</code> is null
+     * @since 1.7
+     */
+    public String getDisplayName(Locale locale) {
+        // Android-changed: Use ICU.
+        /*
+        LocaleServiceProviderPool pool =
+            LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
+        String result = pool.getLocalizedObject(
+                                CurrencyNameGetter.INSTANCE,
+                                locale, currencyCode, DISPLAYNAME);
+        if (result != null) {
+            return result;
+        }
+
+        // use currency code as symbol of last resort
+        return currencyCode;
+        */
+        return icuCurrency.getDisplayName(Objects.requireNonNull(locale));
+    }
+
+    /**
+     * Returns the ISO 4217 currency code of this currency.
+     *
+     * @return the ISO 4217 currency code of this currency
+     */
+    @Override
+    public String toString() {
+        // Android-changed: Use ICU.
+        // return currencyCode;
+        return icuCurrency.toString();
+    }
+
+    /**
+     * Resolves instances being deserialized to a single instance per currency.
+     */
+    private Object readResolve() {
+        return getInstance(currencyCode);
+    }
+
+    // Android-removed: Use ICU.
+    // Removed a bunch of private helper methods that are unused on Android.
+}
diff --git a/java/util/Date.java b/java/util/Date.java
new file mode 100644
index 0000000..f7a576d
--- /dev/null
+++ b/java/util/Date.java
@@ -0,0 +1,1394 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.text.DateFormat;
+import java.time.LocalDate;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.lang.ref.SoftReference;
+import java.time.Instant;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.CalendarDate;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.Era;
+import sun.util.calendar.Gregorian;
+
+/**
+ * The class <code>Date</code> represents a specific instant
+ * in time, with millisecond precision.
+ * <p>
+ * Prior to JDK&nbsp;1.1, the class <code>Date</code> had two additional
+ * functions.  It allowed the interpretation of dates as year, month, day, hour,
+ * minute, and second values.  It also allowed the formatting and parsing
+ * of date strings.  Unfortunately, the API for these functions was not
+ * amenable to internationalization.  As of JDK&nbsp;1.1, the
+ * <code>Calendar</code> class should be used to convert between dates and time
+ * fields and the <code>DateFormat</code> class should be used to format and
+ * parse date strings.
+ * The corresponding methods in <code>Date</code> are deprecated.
+ * <p>
+ * Although the <code>Date</code> class is intended to reflect
+ * coordinated universal time (UTC), it may not do so exactly,
+ * depending on the host environment of the Java Virtual Machine.
+ * Nearly all modern operating systems assume that 1&nbsp;day&nbsp;=
+ * 24&nbsp;&times;&nbsp;60&nbsp;&times;&nbsp;60&nbsp;= 86400 seconds
+ * in all cases. In UTC, however, about once every year or two there
+ * is an extra second, called a "leap second." The leap
+ * second is always added as the last second of the day, and always
+ * on December 31 or June 30. For example, the last minute of the
+ * year 1995 was 61 seconds long, thanks to an added leap second.
+ * Most computer clocks are not accurate enough to be able to reflect
+ * the leap-second distinction.
+ * <p>
+ * Some computer standards are defined in terms of Greenwich mean
+ * time (GMT), which is equivalent to universal time (UT).  GMT is
+ * the "civil" name for the standard; UT is the
+ * "scientific" name for the same standard. The
+ * distinction between UTC and UT is that UTC is based on an atomic
+ * clock and UT is based on astronomical observations, which for all
+ * practical purposes is an invisibly fine hair to split. Because the
+ * earth's rotation is not uniform (it slows down and speeds up
+ * in complicated ways), UT does not always flow uniformly. Leap
+ * seconds are introduced as needed into UTC so as to keep UTC within
+ * 0.9 seconds of UT1, which is a version of UT with certain
+ * corrections applied. There are other time and date systems as
+ * well; for example, the time scale used by the satellite-based
+ * global positioning system (GPS) is synchronized to UTC but is
+ * <i>not</i> adjusted for leap seconds. An interesting source of
+ * further information is the U.S. Naval Observatory, particularly
+ * the Directorate of Time at:
+ * <blockquote><pre>
+ *     <a href=http://tycho.usno.navy.mil>http://tycho.usno.navy.mil</a>
+ * </pre></blockquote>
+ * <p>
+ * and their definitions of "Systems of Time" at:
+ * <blockquote><pre>
+ *     <a href=http://tycho.usno.navy.mil/systime.html>http://tycho.usno.navy.mil/systime.html</a>
+ * </pre></blockquote>
+ * <p>
+ * In all methods of class <code>Date</code> that accept or return
+ * year, month, date, hours, minutes, and seconds values, the
+ * following representations are used:
+ * <ul>
+ * <li>A year <i>y</i> is represented by the integer
+ *     <i>y</i>&nbsp;<code>-&nbsp;1900</code>.
+ * <li>A month is represented by an integer from 0 to 11; 0 is January,
+ *     1 is February, and so forth; thus 11 is December.
+ * <li>A date (day of month) is represented by an integer from 1 to 31
+ *     in the usual manner.
+ * <li>An hour is represented by an integer from 0 to 23. Thus, the hour
+ *     from midnight to 1 a.m. is hour 0, and the hour from noon to 1
+ *     p.m. is hour 12.
+ * <li>A minute is represented by an integer from 0 to 59 in the usual manner.
+ * <li>A second is represented by an integer from 0 to 61; the values 60 and
+ *     61 occur only for leap seconds and even then only in Java
+ *     implementations that actually track leap seconds correctly. Because
+ *     of the manner in which leap seconds are currently introduced, it is
+ *     extremely unlikely that two leap seconds will occur in the same
+ *     minute, but this specification follows the date and time conventions
+ *     for ISO C.
+ * </ul>
+ * <p>
+ * In all cases, arguments given to methods for these purposes need
+ * not fall within the indicated ranges; for example, a date may be
+ * specified as January 32 and is interpreted as meaning February 1.
+ *
+ * @author  James Gosling
+ * @author  Arthur van Hoff
+ * @author  Alan Liu
+ * @see     java.text.DateFormat
+ * @see     java.util.Calendar
+ * @see     java.util.TimeZone
+ * @since   JDK1.0
+ */
+public class Date
+    implements java.io.Serializable, Cloneable, Comparable<Date>
+{
+    private static final BaseCalendar gcal =
+                                CalendarSystem.getGregorianCalendar();
+    private static BaseCalendar jcal;
+
+    private transient long fastTime;
+
+    /*
+     * If cdate is null, then fastTime indicates the time in millis.
+     * If cdate.isNormalized() is true, then fastTime and cdate are in
+     * synch. Otherwise, fastTime is ignored, and cdate indicates the
+     * time.
+     */
+    private transient BaseCalendar.Date cdate;
+
+    // Initialized just before the value is used. See parse().
+    private static int defaultCenturyStart;
+
+    /* use serialVersionUID from modified java.util.Date for
+     * interoperability with JDK1.1. The Date was modified to write
+     * and read only the UTC time.
+     */
+    private static final long serialVersionUID = 7523967970034938905L;
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it so that
+     * it represents the time at which it was allocated, measured to the
+     * nearest millisecond.
+     *
+     * @see     java.lang.System#currentTimeMillis()
+     */
+    public Date() {
+        this(System.currentTimeMillis());
+    }
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it to
+     * represent the specified number of milliseconds since the
+     * standard base time known as "the epoch", namely January 1,
+     * 1970, 00:00:00 GMT.
+     *
+     * @param   date   the milliseconds since January 1, 1970, 00:00:00 GMT.
+     * @see     java.lang.System#currentTimeMillis()
+     */
+    public Date(long date) {
+        fastTime = date;
+    }
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it so that
+     * it represents midnight, local time, at the beginning of the day
+     * specified by the <code>year</code>, <code>month</code>, and
+     * <code>date</code> arguments.
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(year + 1900, month, date)</code>
+     * or <code>GregorianCalendar(year + 1900, month, date)</code>.
+     */
+    @Deprecated
+    public Date(int year, int month, int date) {
+        this(year, month, date, 0, 0, 0);
+    }
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it so that
+     * it represents the instant at the start of the minute specified by
+     * the <code>year</code>, <code>month</code>, <code>date</code>,
+     * <code>hrs</code>, and <code>min</code> arguments, in the local
+     * time zone.
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @param   hrs     the hours between 0-23.
+     * @param   min     the minutes between 0-59.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(year + 1900, month, date,
+     * hrs, min)</code> or <code>GregorianCalendar(year + 1900,
+     * month, date, hrs, min)</code>.
+     */
+    @Deprecated
+    public Date(int year, int month, int date, int hrs, int min) {
+        this(year, month, date, hrs, min, 0);
+    }
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it so that
+     * it represents the instant at the start of the second specified
+     * by the <code>year</code>, <code>month</code>, <code>date</code>,
+     * <code>hrs</code>, <code>min</code>, and <code>sec</code> arguments,
+     * in the local time zone.
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @param   hrs     the hours between 0-23.
+     * @param   min     the minutes between 0-59.
+     * @param   sec     the seconds between 0-59.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(year + 1900, month, date,
+     * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
+     * month, date, hrs, min, sec)</code>.
+     */
+    @Deprecated
+    public Date(int year, int month, int date, int hrs, int min, int sec) {
+        int y = year + 1900;
+        // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
+        if (month >= 12) {
+            y += month / 12;
+            month %= 12;
+        } else if (month < 0) {
+            y += CalendarUtils.floorDivide(month, 12);
+            month = CalendarUtils.mod(month, 12);
+        }
+        BaseCalendar cal = getCalendarSystem(y);
+        cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
+        cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
+        getTimeImpl();
+        cdate = null;
+    }
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it so that
+     * it represents the date and time indicated by the string
+     * <code>s</code>, which is interpreted as if by the
+     * {@link Date#parse} method.
+     *
+     * @param   s   a string representation of the date.
+     * @see     java.text.DateFormat
+     * @see     java.util.Date#parse(java.lang.String)
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>DateFormat.parse(String s)</code>.
+     */
+    @Deprecated
+    public Date(String s) {
+        this(parse(s));
+    }
+
+    /**
+     * Return a copy of this object.
+     */
+    public Object clone() {
+        Date d = null;
+        try {
+            d = (Date)super.clone();
+            if (cdate != null) {
+                d.cdate = (BaseCalendar.Date) cdate.clone();
+            }
+        } catch (CloneNotSupportedException e) {} // Won't happen
+        return d;
+    }
+
+    /**
+     * Determines the date and time based on the arguments. The
+     * arguments are interpreted as a year, month, day of the month,
+     * hour of the day, minute within the hour, and second within the
+     * minute, exactly as for the <tt>Date</tt> constructor with six
+     * arguments, except that the arguments are interpreted relative
+     * to UTC rather than to the local time zone. The time indicated is
+     * returned represented as the distance, measured in milliseconds,
+     * of that time from the epoch (00:00:00 GMT on January 1, 1970).
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @param   hrs     the hours between 0-23.
+     * @param   min     the minutes between 0-59.
+     * @param   sec     the seconds between 0-59.
+     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT for
+     *          the date and time specified by the arguments.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(year + 1900, month, date,
+     * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
+     * month, date, hrs, min, sec)</code>, using a UTC
+     * <code>TimeZone</code>, followed by <code>Calendar.getTime().getTime()</code>.
+     */
+    @Deprecated
+    public static long UTC(int year, int month, int date,
+                           int hrs, int min, int sec) {
+        int y = year + 1900;
+        // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
+        if (month >= 12) {
+            y += month / 12;
+            month %= 12;
+        } else if (month < 0) {
+            y += CalendarUtils.floorDivide(month, 12);
+            month = CalendarUtils.mod(month, 12);
+        }
+        int m = month + 1;
+        BaseCalendar cal = getCalendarSystem(y);
+        BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null);
+        udate.setNormalizedDate(y, m, date).setTimeOfDay(hrs, min, sec, 0);
+
+        // Use a Date instance to perform normalization. Its fastTime
+        // is the UTC value after the normalization.
+        Date d = new Date(0);
+        d.normalize(udate);
+        return d.fastTime;
+    }
+
+    /**
+     * Attempts to interpret the string <tt>s</tt> as a representation
+     * of a date and time. If the attempt is successful, the time
+     * indicated is returned represented as the distance, measured in
+     * milliseconds, of that time from the epoch (00:00:00 GMT on
+     * January 1, 1970). If the attempt fails, an
+     * <tt>IllegalArgumentException</tt> is thrown.
+     * <p>
+     * It accepts many syntaxes; in particular, it recognizes the IETF
+     * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also
+     * understands the continental U.S. time-zone abbreviations, but for
+     * general use, a time-zone offset should be used: "Sat, 12 Aug 1995
+     * 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich
+     * meridian). If no time zone is specified, the local time zone is
+     * assumed. GMT and UTC are considered equivalent.
+     * <p>
+     * The string <tt>s</tt> is processed from left to right, looking for
+     * data of interest. Any material in <tt>s</tt> that is within the
+     * ASCII parenthesis characters <tt>(</tt> and <tt>)</tt> is ignored.
+     * Parentheses may be nested. Otherwise, the only characters permitted
+     * within <tt>s</tt> are these ASCII characters:
+     * <blockquote><pre>
+     * abcdefghijklmnopqrstuvwxyz
+     * ABCDEFGHIJKLMNOPQRSTUVWXYZ
+     * 0123456789,+-:/</pre></blockquote>
+     * and whitespace characters.<p>
+     * A consecutive sequence of decimal digits is treated as a decimal
+     * number:<ul>
+     * <li>If a number is preceded by <tt>+</tt> or <tt>-</tt> and a year
+     *     has already been recognized, then the number is a time-zone
+     *     offset. If the number is less than 24, it is an offset measured
+     *     in hours. Otherwise, it is regarded as an offset in minutes,
+     *     expressed in 24-hour time format without punctuation. A
+     *     preceding <tt>-</tt> means a westward offset. Time zone offsets
+     *     are always relative to UTC (Greenwich). Thus, for example,
+     *     <tt>-5</tt> occurring in the string would mean "five hours west
+     *     of Greenwich" and <tt>+0430</tt> would mean "four hours and
+     *     thirty minutes east of Greenwich." It is permitted for the
+     *     string to specify <tt>GMT</tt>, <tt>UT</tt>, or <tt>UTC</tt>
+     *     redundantly-for example, <tt>GMT-5</tt> or <tt>utc+0430</tt>.
+     * <li>The number is regarded as a year number if one of the
+     *     following conditions is true:
+     * <ul>
+     *     <li>The number is equal to or greater than 70 and followed by a
+     *         space, comma, slash, or end of string
+     *     <li>The number is less than 70, and both a month and a day of
+     *         the month have already been recognized</li>
+     * </ul>
+     *     If the recognized year number is less than 100, it is
+     *     interpreted as an abbreviated year relative to a century of
+     *     which dates are within 80 years before and 19 years after
+     *     the time when the Date class is initialized.
+     *     After adjusting the year number, 1900 is subtracted from
+     *     it. For example, if the current year is 1999 then years in
+     *     the range 19 to 99 are assumed to mean 1919 to 1999, while
+     *     years from 0 to 18 are assumed to mean 2000 to 2018.  Note
+     *     that this is slightly different from the interpretation of
+     *     years less than 100 that is used in {@link java.text.SimpleDateFormat}.
+     * <li>If the number is followed by a colon, it is regarded as an hour,
+     *     unless an hour has already been recognized, in which case it is
+     *     regarded as a minute.
+     * <li>If the number is followed by a slash, it is regarded as a month
+     *     (it is decreased by 1 to produce a number in the range <tt>0</tt>
+     *     to <tt>11</tt>), unless a month has already been recognized, in
+     *     which case it is regarded as a day of the month.
+     * <li>If the number is followed by whitespace, a comma, a hyphen, or
+     *     end of string, then if an hour has been recognized but not a
+     *     minute, it is regarded as a minute; otherwise, if a minute has
+     *     been recognized but not a second, it is regarded as a second;
+     *     otherwise, it is regarded as a day of the month. </ul><p>
+     * A consecutive sequence of letters is regarded as a word and treated
+     * as follows:<ul>
+     * <li>A word that matches <tt>AM</tt>, ignoring case, is ignored (but
+     *     the parse fails if an hour has not been recognized or is less
+     *     than <tt>1</tt> or greater than <tt>12</tt>).
+     * <li>A word that matches <tt>PM</tt>, ignoring case, adds <tt>12</tt>
+     *     to the hour (but the parse fails if an hour has not been
+     *     recognized or is less than <tt>1</tt> or greater than <tt>12</tt>).
+     * <li>Any word that matches any prefix of <tt>SUNDAY, MONDAY, TUESDAY,
+     *     WEDNESDAY, THURSDAY, FRIDAY</tt>, or <tt>SATURDAY</tt>, ignoring
+     *     case, is ignored. For example, <tt>sat, Friday, TUE</tt>, and
+     *     <tt>Thurs</tt> are ignored.
+     * <li>Otherwise, any word that matches any prefix of <tt>JANUARY,
+     *     FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER,
+     *     OCTOBER, NOVEMBER</tt>, or <tt>DECEMBER</tt>, ignoring case, and
+     *     considering them in the order given here, is recognized as
+     *     specifying a month and is converted to a number (<tt>0</tt> to
+     *     <tt>11</tt>). For example, <tt>aug, Sept, april</tt>, and
+     *     <tt>NOV</tt> are recognized as months. So is <tt>Ma</tt>, which
+     *     is recognized as <tt>MARCH</tt>, not <tt>MAY</tt>.
+     * <li>Any word that matches <tt>GMT, UT</tt>, or <tt>UTC</tt>, ignoring
+     *     case, is treated as referring to UTC.
+     * <li>Any word that matches <tt>EST, CST, MST</tt>, or <tt>PST</tt>,
+     *     ignoring case, is recognized as referring to the time zone in
+     *     North America that is five, six, seven, or eight hours west of
+     *     Greenwich, respectively. Any word that matches <tt>EDT, CDT,
+     *     MDT</tt>, or <tt>PDT</tt>, ignoring case, is recognized as
+     *     referring to the same time zone, respectively, during daylight
+     *     saving time.</ul><p>
+     * Once the entire string s has been scanned, it is converted to a time
+     * result in one of two ways. If a time zone or time-zone offset has been
+     * recognized, then the year, month, day of month, hour, minute, and
+     * second are interpreted in UTC and then the time-zone offset is
+     * applied. Otherwise, the year, month, day of month, hour, minute, and
+     * second are interpreted in the local time zone.
+     *
+     * @param   s   a string to be parsed as a date.
+     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
+     *          represented by the string argument.
+     * @see     java.text.DateFormat
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>DateFormat.parse(String s)</code>.
+     */
+    @Deprecated
+    public static long parse(String s) {
+        int year = Integer.MIN_VALUE;
+        int mon = -1;
+        int mday = -1;
+        int hour = -1;
+        int min = -1;
+        int sec = -1;
+        int millis = -1;
+        int c = -1;
+        int i = 0;
+        int n = -1;
+        int wst = -1;
+        int tzoffset = -1;
+        int prevc = 0;
+    syntax:
+        {
+            if (s == null)
+                break syntax;
+            int limit = s.length();
+            while (i < limit) {
+                c = s.charAt(i);
+                i++;
+                if (c <= ' ' || c == ',')
+                    continue;
+                if (c == '(') { // skip comments
+                    int depth = 1;
+                    while (i < limit) {
+                        c = s.charAt(i);
+                        i++;
+                        if (c == '(') depth++;
+                        else if (c == ')')
+                            if (--depth <= 0)
+                                break;
+                    }
+                    continue;
+                }
+                if ('0' <= c && c <= '9') {
+                    n = c - '0';
+                    while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
+                        n = n * 10 + c - '0';
+                        i++;
+                    }
+                    if (prevc == '+' || prevc == '-' && year != Integer.MIN_VALUE) {
+                        // BEGIN Android-changed: Android specific time zone logic
+
+                        if (tzoffset != 0 && tzoffset != -1)
+                            break syntax;
+
+                        // timezone offset
+                        if (n < 24) {
+                            n = n * 60; // EG. "GMT-3"
+
+                            // Support for Timezones of the form GMT-3:30. We look for an ':" and
+                            // parse the number following it as loosely as the original hours
+                            // section (i.e, no range or validity checks).
+                            int minutesPart = 0;
+                            if (i < limit && (s.charAt(i) == ':')) {
+                                i++;
+                                while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
+                                    minutesPart = (minutesPart * 10) + (c - '0');
+                                    i++;
+                                }
+                            }
+
+                            n += minutesPart;
+                        } else {
+                            n = (n % 100) + ((n / 100) * 60); // eg "GMT-0430"
+                        }
+
+                        if (prevc == '+')   // plus means east of GMT
+                            n = -n;
+                        // END Android-changed: Android specific time zone logic
+
+                        tzoffset = n;
+                    } else if (n >= 70)
+                        if (year != Integer.MIN_VALUE)
+                            break syntax;
+                        else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
+                            // year = n < 1900 ? n : n - 1900;
+                            year = n;
+                        else
+                            break syntax;
+                    else if (c == ':')
+                        if (hour < 0)
+                            hour = (byte) n;
+                        else if (min < 0)
+                            min = (byte) n;
+                        else
+                            break syntax;
+                    else if (c == '/')
+                        if (mon < 0)
+                            mon = (byte) (n - 1);
+                        else if (mday < 0)
+                            mday = (byte) n;
+                        else
+                            break syntax;
+                    else if (i < limit && c != ',' && c > ' ' && c != '-')
+                        break syntax;
+                    else if (hour >= 0 && min < 0)
+                        min = (byte) n;
+                    else if (min >= 0 && sec < 0)
+                        sec = (byte) n;
+                    else if (mday < 0)
+                        mday = (byte) n;
+                    // Handle two-digit years < 70 (70-99 handled above).
+                    else if (year == Integer.MIN_VALUE && mon >= 0 && mday >= 0)
+                        year = n;
+                    else
+                        break syntax;
+                    prevc = 0;
+                } else if (c == '/' || c == ':' || c == '+' || c == '-')
+                    prevc = c;
+                else {
+                    int st = i - 1;
+                    while (i < limit) {
+                        c = s.charAt(i);
+                        if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
+                            break;
+                        i++;
+                    }
+                    if (i <= st + 1)
+                        break syntax;
+                    int k;
+                    for (k = wtb.length; --k >= 0;)
+                        if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
+                            int action = ttb[k];
+                            if (action != 0) {
+                                if (action == 1) {  // pm
+                                    if (hour > 12 || hour < 1)
+                                        break syntax;
+                                    else if (hour < 12)
+                                        hour += 12;
+                                } else if (action == 14) {  // am
+                                    if (hour > 12 || hour < 1)
+                                        break syntax;
+                                    else if (hour == 12)
+                                        hour = 0;
+                                } else if (action <= 13) {  // month!
+                                    if (mon < 0)
+                                        mon = (byte) (action - 2);
+                                    else
+                                        break syntax;
+                                } else {
+                                    tzoffset = action - 10000;
+                                }
+                            }
+                            break;
+                        }
+                    if (k < 0)
+                        break syntax;
+                    prevc = 0;
+                }
+            }
+            if (year == Integer.MIN_VALUE || mon < 0 || mday < 0)
+                break syntax;
+            // Parse 2-digit years within the correct default century.
+            if (year < 100) {
+                synchronized (Date.class) {
+                    if (defaultCenturyStart == 0) {
+                        defaultCenturyStart = gcal.getCalendarDate().getYear() - 80;
+                    }
+                }
+                year += (defaultCenturyStart / 100) * 100;
+                if (year < defaultCenturyStart) year += 100;
+            }
+            if (sec < 0)
+                sec = 0;
+            if (min < 0)
+                min = 0;
+            if (hour < 0)
+                hour = 0;
+            BaseCalendar cal = getCalendarSystem(year);
+            if (tzoffset == -1)  { // no time zone specified, have to use local
+                BaseCalendar.Date ldate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
+                ldate.setDate(year, mon + 1, mday);
+                ldate.setTimeOfDay(hour, min, sec, 0);
+                return cal.getTime(ldate);
+            }
+            BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null); // no time zone
+            udate.setDate(year, mon + 1, mday);
+            udate.setTimeOfDay(hour, min, sec, 0);
+            return cal.getTime(udate) + tzoffset * (60 * 1000);
+        }
+        // syntax error
+        throw new IllegalArgumentException();
+    }
+    private final static String wtb[] = {
+        "am", "pm",
+        "monday", "tuesday", "wednesday", "thursday", "friday",
+        "saturday", "sunday",
+        "january", "february", "march", "april", "may", "june",
+        "july", "august", "september", "october", "november", "december",
+        "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
+        "mst", "mdt", "pst", "pdt"
+    };
+    private final static int ttb[] = {
+        14, 1, 0, 0, 0, 0, 0, 0, 0,
+        2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+        10000 + 0, 10000 + 0, 10000 + 0,    // GMT/UT/UTC
+        10000 + 5 * 60, 10000 + 4 * 60,     // EST/EDT
+        10000 + 6 * 60, 10000 + 5 * 60,     // CST/CDT
+        10000 + 7 * 60, 10000 + 6 * 60,     // MST/MDT
+        10000 + 8 * 60, 10000 + 7 * 60      // PST/PDT
+    };
+
+    /**
+     * Returns a value that is the result of subtracting 1900 from the
+     * year that contains or begins with the instant in time represented
+     * by this <code>Date</code> object, as interpreted in the local
+     * time zone.
+     *
+     * @return  the year represented by this date, minus 1900.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.YEAR) - 1900</code>.
+     */
+    @Deprecated
+    public int getYear() {
+        return normalize().getYear() - 1900;
+    }
+
+    /**
+     * Sets the year of this <tt>Date</tt> object to be the specified
+     * value plus 1900. This <code>Date</code> object is modified so
+     * that it represents a point in time within the specified year,
+     * with the month, date, hour, minute, and second the same as
+     * before, as interpreted in the local time zone. (Of course, if
+     * the date was February 29, for example, and the year is set to a
+     * non-leap year, then the new date will be treated as if it were
+     * on March 1.)
+     *
+     * @param   year    the year value.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.YEAR, year + 1900)</code>.
+     */
+    @Deprecated
+    public void setYear(int year) {
+        getCalendarDate().setNormalizedYear(year + 1900);
+    }
+
+    /**
+     * Returns a number representing the month that contains or begins
+     * with the instant in time represented by this <tt>Date</tt> object.
+     * The value returned is between <code>0</code> and <code>11</code>,
+     * with the value <code>0</code> representing January.
+     *
+     * @return  the month represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
+     */
+    @Deprecated
+    public int getMonth() {
+        return normalize().getMonth() - 1; // adjust 1-based to 0-based
+    }
+
+    /**
+     * Sets the month of this date to the specified value. This
+     * <tt>Date</tt> object is modified so that it represents a point
+     * in time within the specified month, with the year, date, hour,
+     * minute, and second the same as before, as interpreted in the
+     * local time zone. If the date was October 31, for example, and
+     * the month is set to June, then the new date will be treated as
+     * if it were on July 1, because June has only 30 days.
+     *
+     * @param   month   the month value between 0-11.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.MONTH, int month)</code>.
+     */
+    @Deprecated
+    public void setMonth(int month) {
+        int y = 0;
+        if (month >= 12) {
+            y = month / 12;
+            month %= 12;
+        } else if (month < 0) {
+            y = CalendarUtils.floorDivide(month, 12);
+            month = CalendarUtils.mod(month, 12);
+        }
+        BaseCalendar.Date d = getCalendarDate();
+        if (y != 0) {
+            d.setNormalizedYear(d.getNormalizedYear() + y);
+        }
+        d.setMonth(month + 1); // adjust 0-based to 1-based month numbering
+    }
+
+    /**
+     * Returns the day of the month represented by this <tt>Date</tt> object.
+     * The value returned is between <code>1</code> and <code>31</code>
+     * representing the day of the month that contains or begins with the
+     * instant in time represented by this <tt>Date</tt> object, as
+     * interpreted in the local time zone.
+     *
+     * @return  the day of the month represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.DAY_OF_MONTH)</code>.
+     */
+    @Deprecated
+    // Android-removed stray @deprecated tag.
+    public int getDate() {
+        return normalize().getDayOfMonth();
+    }
+
+    /**
+     * Sets the day of the month of this <tt>Date</tt> object to the
+     * specified value. This <tt>Date</tt> object is modified so that
+     * it represents a point in time within the specified day of the
+     * month, with the year, month, hour, minute, and second the same
+     * as before, as interpreted in the local time zone. If the date
+     * was April 30, for example, and the date is set to 31, then it
+     * will be treated as if it were on May 1, because April has only
+     * 30 days.
+     *
+     * @param   date   the day of the month value between 1-31.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.DAY_OF_MONTH, int date)</code>.
+     */
+    @Deprecated
+    public void setDate(int date) {
+        getCalendarDate().setDayOfMonth(date);
+    }
+
+    /**
+     * Returns the day of the week represented by this date. The
+     * returned value (<tt>0</tt> = Sunday, <tt>1</tt> = Monday,
+     * <tt>2</tt> = Tuesday, <tt>3</tt> = Wednesday, <tt>4</tt> =
+     * Thursday, <tt>5</tt> = Friday, <tt>6</tt> = Saturday)
+     * represents the day of the week that contains or begins with
+     * the instant in time represented by this <tt>Date</tt> object,
+     * as interpreted in the local time zone.
+     *
+     * @return  the day of the week represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.DAY_OF_WEEK)</code>.
+     */
+    @Deprecated
+    public int getDay() {
+        return normalize().getDayOfWeek() - BaseCalendar.SUNDAY;
+    }
+
+    /**
+     * Returns the hour represented by this <tt>Date</tt> object. The
+     * returned value is a number (<tt>0</tt> through <tt>23</tt>)
+     * representing the hour within the day that contains or begins
+     * with the instant in time represented by this <tt>Date</tt>
+     * object, as interpreted in the local time zone.
+     *
+     * @return  the hour represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.HOUR_OF_DAY)</code>.
+     */
+    @Deprecated
+    public int getHours() {
+        return normalize().getHours();
+    }
+
+    /**
+     * Sets the hour of this <tt>Date</tt> object to the specified value.
+     * This <tt>Date</tt> object is modified so that it represents a point
+     * in time within the specified hour of the day, with the year, month,
+     * date, minute, and second the same as before, as interpreted in the
+     * local time zone.
+     *
+     * @param   hours   the hour value.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.HOUR_OF_DAY, int hours)</code>.
+     */
+    @Deprecated
+    public void setHours(int hours) {
+        getCalendarDate().setHours(hours);
+    }
+
+    /**
+     * Returns the number of minutes past the hour represented by this date,
+     * as interpreted in the local time zone.
+     * The value returned is between <code>0</code> and <code>59</code>.
+     *
+     * @return  the number of minutes past the hour represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.MINUTE)</code>.
+     */
+    @Deprecated
+    public int getMinutes() {
+        return normalize().getMinutes();
+    }
+
+    /**
+     * Sets the minutes of this <tt>Date</tt> object to the specified value.
+     * This <tt>Date</tt> object is modified so that it represents a point
+     * in time within the specified minute of the hour, with the year, month,
+     * date, hour, and second the same as before, as interpreted in the
+     * local time zone.
+     *
+     * @param   minutes   the value of the minutes.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.MINUTE, int minutes)</code>.
+     */
+    @Deprecated
+    public void setMinutes(int minutes) {
+        getCalendarDate().setMinutes(minutes);
+    }
+
+    /**
+     * Returns the number of seconds past the minute represented by this date.
+     * The value returned is between <code>0</code> and <code>61</code>. The
+     * values <code>60</code> and <code>61</code> can only occur on those
+     * Java Virtual Machines that take leap seconds into account.
+     *
+     * @return  the number of seconds past the minute represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.SECOND)</code>.
+     */
+    @Deprecated
+    public int getSeconds() {
+        return normalize().getSeconds();
+    }
+
+    /**
+     * Sets the seconds of this <tt>Date</tt> to the specified value.
+     * This <tt>Date</tt> object is modified so that it represents a
+     * point in time within the specified second of the minute, with
+     * the year, month, date, hour, and minute the same as before, as
+     * interpreted in the local time zone.
+     *
+     * @param   seconds   the seconds value.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.SECOND, int seconds)</code>.
+     */
+    @Deprecated
+    public void setSeconds(int seconds) {
+        getCalendarDate().setSeconds(seconds);
+    }
+
+    /**
+     * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
+     * represented by this <tt>Date</tt> object.
+     *
+     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
+     *          represented by this date.
+     */
+    public long getTime() {
+        return getTimeImpl();
+    }
+
+    private final long getTimeImpl() {
+        if (cdate != null && !cdate.isNormalized()) {
+            normalize();
+        }
+        return fastTime;
+    }
+
+    /**
+     * Sets this <code>Date</code> object to represent a point in time that is
+     * <code>time</code> milliseconds after January 1, 1970 00:00:00 GMT.
+     *
+     * @param   time   the number of milliseconds.
+     */
+    public void setTime(long time) {
+        fastTime = time;
+        cdate = null;
+    }
+
+    /**
+     * Tests if this date is before the specified date.
+     *
+     * @param   when   a date.
+     * @return  <code>true</code> if and only if the instant of time
+     *            represented by this <tt>Date</tt> object is strictly
+     *            earlier than the instant represented by <tt>when</tt>;
+     *          <code>false</code> otherwise.
+     * @exception NullPointerException if <code>when</code> is null.
+     */
+    public boolean before(Date when) {
+        return getMillisOf(this) < getMillisOf(when);
+    }
+
+    /**
+     * Tests if this date is after the specified date.
+     *
+     * @param   when   a date.
+     * @return  <code>true</code> if and only if the instant represented
+     *          by this <tt>Date</tt> object is strictly later than the
+     *          instant represented by <tt>when</tt>;
+     *          <code>false</code> otherwise.
+     * @exception NullPointerException if <code>when</code> is null.
+     */
+    public boolean after(Date when) {
+        return getMillisOf(this) > getMillisOf(when);
+    }
+
+    /**
+     * Compares two dates for equality.
+     * The result is <code>true</code> if and only if the argument is
+     * not <code>null</code> and is a <code>Date</code> object that
+     * represents the same point in time, to the millisecond, as this object.
+     * <p>
+     * Thus, two <code>Date</code> objects are equal if and only if the
+     * <code>getTime</code> method returns the same <code>long</code>
+     * value for both.
+     *
+     * @param   obj   the object to compare with.
+     * @return  <code>true</code> if the objects are the same;
+     *          <code>false</code> otherwise.
+     * @see     java.util.Date#getTime()
+     */
+    public boolean equals(Object obj) {
+        return obj instanceof Date && getTime() == ((Date) obj).getTime();
+    }
+
+    /**
+     * Returns the millisecond value of this <code>Date</code> object
+     * without affecting its internal state.
+     */
+    static final long getMillisOf(Date date) {
+        if (date.cdate == null || date.cdate.isNormalized()) {
+            return date.fastTime;
+        }
+        BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
+        return gcal.getTime(d);
+    }
+
+    /**
+     * Compares two Dates for ordering.
+     *
+     * @param   anotherDate   the <code>Date</code> to be compared.
+     * @return  the value <code>0</code> if the argument Date is equal to
+     *          this Date; a value less than <code>0</code> if this Date
+     *          is before the Date argument; and a value greater than
+     *      <code>0</code> if this Date is after the Date argument.
+     * @since   1.2
+     * @exception NullPointerException if <code>anotherDate</code> is null.
+     */
+    public int compareTo(Date anotherDate) {
+        long thisTime = getMillisOf(this);
+        long anotherTime = getMillisOf(anotherDate);
+        return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
+    }
+
+    /**
+     * Returns a hash code value for this object. The result is the
+     * exclusive OR of the two halves of the primitive <tt>long</tt>
+     * value returned by the {@link Date#getTime}
+     * method. That is, the hash code is the value of the expression:
+     * <blockquote><pre>{@code
+     * (int)(this.getTime()^(this.getTime() >>> 32))
+     * }</pre></blockquote>
+     *
+     * @return  a hash code value for this object.
+     */
+    public int hashCode() {
+        long ht = this.getTime();
+        return (int) ht ^ (int) (ht >> 32);
+    }
+
+    /**
+     * Converts this <code>Date</code> object to a <code>String</code>
+     * of the form:
+     * <blockquote><pre>
+     * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
+     * where:<ul>
+     * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed,
+     *     Thu, Fri, Sat</tt>).
+     * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun,
+     *     Jul, Aug, Sep, Oct, Nov, Dec</tt>).
+     * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through
+     *     <tt>31</tt>), as two decimal digits.
+     * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through
+     *     <tt>23</tt>), as two decimal digits.
+     * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through
+     *     <tt>59</tt>), as two decimal digits.
+     * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through
+     *     <tt>61</tt>, as two decimal digits.
+     * <li><tt>zzz</tt> is the time zone (and may reflect daylight saving
+     *     time). Standard time zone abbreviations include those
+     *     recognized by the method <tt>parse</tt>. If time zone
+     *     information is not available, then <tt>zzz</tt> is empty -
+     *     that is, it consists of no characters at all.
+     * <li><tt>yyyy</tt> is the year, as four decimal digits.
+     * </ul>
+     *
+     * @return  a string representation of this date.
+     * @see     java.util.Date#toLocaleString()
+     * @see     java.util.Date#toGMTString()
+     */
+    public String toString() {
+        // "EEE MMM dd HH:mm:ss zzz yyyy";
+        BaseCalendar.Date date = normalize();
+        StringBuilder sb = new StringBuilder(28);
+        int index = date.getDayOfWeek();
+        if (index == BaseCalendar.SUNDAY) {
+            index = 8;
+        }
+        convertToAbbr(sb, wtb[index]).append(' ');                        // EEE
+        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
+        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
+
+        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');   // HH
+        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
+        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
+        TimeZone zi = date.getZone();
+        if (zi != null) {
+            sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
+        } else {
+            sb.append("GMT");
+        }
+        sb.append(' ').append(date.getYear());  // yyyy
+        return sb.toString();
+    }
+
+    /**
+     * Converts the given name to its 3-letter abbreviation (e.g.,
+     * "monday" -> "Mon") and stored the abbreviation in the given
+     * <code>StringBuilder</code>.
+     */
+    private static final StringBuilder convertToAbbr(StringBuilder sb, String name) {
+        sb.append(Character.toUpperCase(name.charAt(0)));
+        sb.append(name.charAt(1)).append(name.charAt(2));
+        return sb;
+    }
+
+    /**
+     * Creates a string representation of this <tt>Date</tt> object in an
+     * implementation-dependent form. The intent is that the form should
+     * be familiar to the user of the Java application, wherever it may
+     * happen to be running. The intent is comparable to that of the
+     * "<code>%c</code>" format supported by the <code>strftime()</code>
+     * function of ISO&nbsp;C.
+     *
+     * @return  a string representation of this date, using the locale
+     *          conventions.
+     * @see     java.text.DateFormat
+     * @see     java.util.Date#toString()
+     * @see     java.util.Date#toGMTString()
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>DateFormat.format(Date date)</code>.
+     */
+    @Deprecated
+    public String toLocaleString() {
+        DateFormat formatter = DateFormat.getDateTimeInstance();
+        return formatter.format(this);
+    }
+
+    /**
+     * Creates a string representation of this <tt>Date</tt> object of
+     * the form:
+     * <blockquote><pre>
+     * d mon yyyy hh:mm:ss GMT</pre></blockquote>
+     * where:<ul>
+     * <li><i>d</i> is the day of the month (<tt>1</tt> through <tt>31</tt>),
+     *     as one or two decimal digits.
+     * <li><i>mon</i> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, Jul,
+     *     Aug, Sep, Oct, Nov, Dec</tt>).
+     * <li><i>yyyy</i> is the year, as four decimal digits.
+     * <li><i>hh</i> is the hour of the day (<tt>00</tt> through <tt>23</tt>),
+     *     as two decimal digits.
+     * <li><i>mm</i> is the minute within the hour (<tt>00</tt> through
+     *     <tt>59</tt>), as two decimal digits.
+     * <li><i>ss</i> is the second within the minute (<tt>00</tt> through
+     *     <tt>61</tt>), as two decimal digits.
+     * <li><i>GMT</i> is exactly the ASCII letters "<tt>GMT</tt>" to indicate
+     *     Greenwich Mean Time.
+     * </ul><p>
+     * The result does not depend on the local time zone.
+     *
+     * @return  a string representation of this date, using the Internet GMT
+     *          conventions.
+     * @see     java.text.DateFormat
+     * @see     java.util.Date#toString()
+     * @see     java.util.Date#toLocaleString()
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>DateFormat.format(Date date)</code>, using a
+     * GMT <code>TimeZone</code>.
+     */
+    @Deprecated
+    public String toGMTString() {
+        // d MMM yyyy HH:mm:ss 'GMT'
+        long t = getTime();
+        BaseCalendar cal = getCalendarSystem(t);
+        BaseCalendar.Date date =
+            (BaseCalendar.Date) cal.getCalendarDate(getTime(), (TimeZone)null);
+        StringBuilder sb = new StringBuilder(32);
+        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
+        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
+        sb.append(date.getYear()).append(' ');                            // yyyy
+        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');      // HH
+        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':');    // mm
+        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2);                // ss
+        sb.append(" GMT");                                                // ' GMT'
+        return sb.toString();
+    }
+
+    /**
+     * Returns the offset, measured in minutes, for the local time zone
+     * relative to UTC that is appropriate for the time represented by
+     * this <code>Date</code> object.
+     * <p>
+     * For example, in Massachusetts, five time zones west of Greenwich:
+     * <blockquote><pre>
+     * new Date(96, 1, 14).getTimezoneOffset() returns 300</pre></blockquote>
+     * because on February 14, 1996, standard time (Eastern Standard Time)
+     * is in use, which is offset five hours from UTC; but:
+     * <blockquote><pre>
+     * new Date(96, 5, 1).getTimezoneOffset() returns 240</pre></blockquote>
+     * because on June 1, 1996, daylight saving time (Eastern Daylight Time)
+     * is in use, which is offset only four hours from UTC.<p>
+     * This method produces the same result as if it computed:
+     * <blockquote><pre>
+     * (this.getTime() - UTC(this.getYear(),
+     *                       this.getMonth(),
+     *                       this.getDate(),
+     *                       this.getHours(),
+     *                       this.getMinutes(),
+     *                       this.getSeconds())) / (60 * 1000)
+     * </pre></blockquote>
+     *
+     * @return  the time-zone offset, in minutes, for the current time zone.
+     * @see     java.util.Calendar#ZONE_OFFSET
+     * @see     java.util.Calendar#DST_OFFSET
+     * @see     java.util.TimeZone#getDefault
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>-(Calendar.get(Calendar.ZONE_OFFSET) +
+     * Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)</code>.
+     */
+    @Deprecated
+    public int getTimezoneOffset() {
+        int zoneOffset;
+        if (cdate == null) {
+            // Android-changed: Android specific time zone logic
+            GregorianCalendar cal = new GregorianCalendar(fastTime);
+            zoneOffset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET));
+        } else {
+            normalize();
+            zoneOffset = cdate.getZoneOffset();
+        }
+        return -zoneOffset/60000;  // convert to minutes
+    }
+
+    private final BaseCalendar.Date getCalendarDate() {
+        if (cdate == null) {
+            BaseCalendar cal = getCalendarSystem(fastTime);
+            cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
+                                                            TimeZone.getDefaultRef());
+        }
+        return cdate;
+    }
+
+    private final BaseCalendar.Date normalize() {
+        if (cdate == null) {
+            BaseCalendar cal = getCalendarSystem(fastTime);
+            cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
+                                                            TimeZone.getDefaultRef());
+            return cdate;
+        }
+
+        // Normalize cdate with the TimeZone in cdate first. This is
+        // required for the compatible behavior.
+        if (!cdate.isNormalized()) {
+            cdate = normalize(cdate);
+        }
+
+        // If the default TimeZone has changed, then recalculate the
+        // fields with the new TimeZone.
+        TimeZone tz = TimeZone.getDefaultRef();
+        if (tz != cdate.getZone()) {
+            cdate.setZone(tz);
+            CalendarSystem cal = getCalendarSystem(cdate);
+            cal.getCalendarDate(fastTime, cdate);
+        }
+        return cdate;
+    }
+
+    // fastTime and the returned data are in sync upon return.
+    private final BaseCalendar.Date normalize(BaseCalendar.Date date) {
+        int y = date.getNormalizedYear();
+        int m = date.getMonth();
+        int d = date.getDayOfMonth();
+        int hh = date.getHours();
+        int mm = date.getMinutes();
+        int ss = date.getSeconds();
+        int ms = date.getMillis();
+        TimeZone tz = date.getZone();
+
+        // If the specified year can't be handled using a long value
+        // in milliseconds, GregorianCalendar is used for full
+        // compatibility with underflow and overflow. This is required
+        // by some JCK tests. The limits are based max year values -
+        // years that can be represented by max values of d, hh, mm,
+        // ss and ms. Also, let GregorianCalendar handle the default
+        // cutover year so that we don't need to worry about the
+        // transition here.
+        if (y == 1582 || y > 280000000 || y < -280000000) {
+            if (tz == null) {
+                tz = TimeZone.getTimeZone("GMT");
+            }
+            GregorianCalendar gc = new GregorianCalendar(tz);
+            gc.clear();
+            gc.set(GregorianCalendar.MILLISECOND, ms);
+            gc.set(y, m-1, d, hh, mm, ss);
+            fastTime = gc.getTimeInMillis();
+            BaseCalendar cal = getCalendarSystem(fastTime);
+            date = (BaseCalendar.Date) cal.getCalendarDate(fastTime, tz);
+            return date;
+        }
+
+        BaseCalendar cal = getCalendarSystem(y);
+        if (cal != getCalendarSystem(date)) {
+            date = (BaseCalendar.Date) cal.newCalendarDate(tz);
+            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
+        }
+        // Perform the GregorianCalendar-style normalization.
+        fastTime = cal.getTime(date);
+
+        // In case the normalized date requires the other calendar
+        // system, we need to recalculate it using the other one.
+        BaseCalendar ncal = getCalendarSystem(fastTime);
+        if (ncal != cal) {
+            date = (BaseCalendar.Date) ncal.newCalendarDate(tz);
+            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
+            fastTime = ncal.getTime(date);
+        }
+        return date;
+    }
+
+    /**
+     * Returns the Gregorian or Julian calendar system to use with the
+     * given date. Use Gregorian from October 15, 1582.
+     *
+     * @param year normalized calendar year (not -1900)
+     * @return the CalendarSystem to use for the specified date
+     */
+    private static final BaseCalendar getCalendarSystem(int year) {
+        if (year >= 1582) {
+            return gcal;
+        }
+        return getJulianCalendar();
+    }
+
+    private static final BaseCalendar getCalendarSystem(long utc) {
+        // Quickly check if the time stamp given by `utc' is the Epoch
+        // or later. If it's before 1970, we convert the cutover to
+        // local time to compare.
+        if (utc >= 0
+            || utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
+                        - TimeZone.getDefaultRef().getOffset(utc)) {
+            return gcal;
+        }
+        return getJulianCalendar();
+    }
+
+    private static final BaseCalendar getCalendarSystem(BaseCalendar.Date cdate) {
+        if (jcal == null) {
+            return gcal;
+        }
+        if (cdate.getEra() != null) {
+            return jcal;
+        }
+        return gcal;
+    }
+
+    synchronized private static final BaseCalendar getJulianCalendar() {
+        if (jcal == null) {
+            jcal = (BaseCalendar) CalendarSystem.forName("julian");
+        }
+        return jcal;
+    }
+
+    /**
+     * Save the state of this object to a stream (i.e., serialize it).
+     *
+     * @serialData The value returned by <code>getTime()</code>
+     *             is emitted (long).  This represents the offset from
+     *             January 1, 1970, 00:00:00 GMT in milliseconds.
+     */
+    private void writeObject(ObjectOutputStream s)
+         throws IOException
+    {
+        s.writeLong(getTimeImpl());
+    }
+
+    /**
+     * Reconstitute this object from a stream (i.e., deserialize it).
+     */
+    private void readObject(ObjectInputStream s)
+         throws IOException, ClassNotFoundException
+    {
+        fastTime = s.readLong();
+    }
+
+    /**
+     * Obtains an instance of {@code Date} from an {@code Instant} object.
+     * <p>
+     * {@code Instant} uses a precision of nanoseconds, whereas {@code Date}
+     * uses a precision of milliseconds.  The conversion will trancate any
+     * excess precision information as though the amount in nanoseconds was
+     * subject to integer division by one million.
+     * <p>
+     * {@code Instant} can store points on the time-line further in the future
+     * and further in the past than {@code Date}. In this scenario, this method
+     * will throw an exception.
+     *
+     * @param instant  the instant to convert
+     * @return a {@code Date} representing the same point on the time-line as
+     *  the provided instant
+     * @exception NullPointerException if {@code instant} is null.
+     * @exception IllegalArgumentException if the instant is too large to
+     *  represent as a {@code Date}
+     * @since 1.8
+     */
+    public static Date from(Instant instant) {
+        try {
+            return new Date(instant.toEpochMilli());
+        } catch (ArithmeticException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+    }
+
+    /**
+     * Converts this {@code Date} object to an {@code Instant}.
+     * <p>
+     * The conversion creates an {@code Instant} that represents the same
+     * point on the time-line as this {@code Date}.
+     *
+     * @return an instant representing the same point on the time-line as
+     *  this {@code Date} object
+     * @since 1.8
+     */
+    public Instant toInstant() {
+        return Instant.ofEpochMilli(getTime());
+    }
+}
diff --git a/java/util/Deque.annotated.java b/java/util/Deque.annotated.java
new file mode 100644
index 0000000..d93d5a2
--- /dev/null
+++ b/java/util/Deque.annotated.java
@@ -0,0 +1,96 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Josh Bloch with assistance from members of
+ * JCP JSR-166 Expert Group and released to the public domain, as explained
+ * at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Deque<E> extends java.util.Queue<E> {
+
+public void addFirst(@libcore.util.NullFromTypeParam E e);
+
+public void addLast(@libcore.util.NullFromTypeParam E e);
+
+public boolean offerFirst(@libcore.util.NullFromTypeParam E e);
+
+public boolean offerLast(@libcore.util.NullFromTypeParam E e);
+
[email protected] public E removeFirst();
+
[email protected] public E removeLast();
+
[email protected] public E pollFirst();
+
[email protected] public E pollLast();
+
[email protected] public E getFirst();
+
[email protected] public E getLast();
+
[email protected] public E peekFirst();
+
[email protected] public E peekLast();
+
+public boolean removeFirstOccurrence(@libcore.util.Nullable java.lang.Object o);
+
+public boolean removeLastOccurrence(@libcore.util.Nullable java.lang.Object o);
+
+public boolean add(@libcore.util.NullFromTypeParam E e);
+
+public boolean offer(@libcore.util.NullFromTypeParam E e);
+
[email protected] public E remove();
+
[email protected] public E poll();
+
[email protected] public E element();
+
[email protected] public E peek();
+
+public void push(@libcore.util.NullFromTypeParam E e);
+
[email protected] public E pop();
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o);
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o);
+
+public int size();
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator();
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> descendingIterator();
+}
diff --git a/java/util/Deque.java b/java/util/Deque.java
new file mode 100644
index 0000000..3d79952
--- /dev/null
+++ b/java/util/Deque.java
@@ -0,0 +1,580 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Josh Bloch with assistance from members of
+ * JCP JSR-166 Expert Group and released to the public domain, as explained
+ * at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// Android-changed: removed link to collections framework docs
+/**
+ * A linear collection that supports element insertion and removal at
+ * both ends.  The name <i>deque</i> is short for "double ended queue"
+ * and is usually pronounced "deck".  Most {@code Deque}
+ * implementations place no fixed limits on the number of elements
+ * they may contain, but this interface supports capacity-restricted
+ * deques as well as those with no fixed size limit.
+ *
+ * <p>This interface defines methods to access the elements at both
+ * ends of the deque.  Methods are provided to insert, remove, and
+ * examine the element.  Each of these methods exists in two forms:
+ * one throws an exception if the operation fails, the other returns a
+ * special value (either {@code null} or {@code false}, depending on
+ * the operation).  The latter form of the insert operation is
+ * designed specifically for use with capacity-restricted
+ * {@code Deque} implementations; in most implementations, insert
+ * operations cannot fail.
+ *
+ * <p>The twelve methods described above are summarized in the
+ * following table:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of Deque methods</caption>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>First Element (Head)</b></td>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>Last Element (Tail)</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link Deque#addFirst addFirst(e)}</td>
+ *    <td>{@link Deque#offerFirst offerFirst(e)}</td>
+ *    <td>{@link Deque#addLast addLast(e)}</td>
+ *    <td>{@link Deque#offerLast offerLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link Deque#removeFirst removeFirst()}</td>
+ *    <td>{@link Deque#pollFirst pollFirst()}</td>
+ *    <td>{@link Deque#removeLast removeLast()}</td>
+ *    <td>{@link Deque#pollLast pollLast()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link Deque#getFirst getFirst()}</td>
+ *    <td>{@link Deque#peekFirst peekFirst()}</td>
+ *    <td>{@link Deque#getLast getLast()}</td>
+ *    <td>{@link Deque#peekLast peekLast()}</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>This interface extends the {@link Queue} interface.  When a deque is
+ * used as a queue, FIFO (First-In-First-Out) behavior results.  Elements are
+ * added at the end of the deque and removed from the beginning.  The methods
+ * inherited from the {@code Queue} interface are precisely equivalent to
+ * {@code Deque} methods as indicated in the following table:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Comparison of Queue and Deque methods</caption>
+ *  <tr>
+ *    <td ALIGN=CENTER> <b>{@code Queue} Method</b></td>
+ *    <td ALIGN=CENTER> <b>Equivalent {@code Deque} Method</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#add add(e)}</td>
+ *    <td>{@link #addLast addLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#offer offer(e)}</td>
+ *    <td>{@link #offerLast offerLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#remove remove()}</td>
+ *    <td>{@link #removeFirst removeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#poll poll()}</td>
+ *    <td>{@link #pollFirst pollFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#element element()}</td>
+ *    <td>{@link #getFirst getFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#peek peek()}</td>
+ *    <td>{@link #peek peekFirst()}</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Deques can also be used as LIFO (Last-In-First-Out) stacks.  This
+ * interface should be used in preference to the legacy {@link Stack} class.
+ * When a deque is used as a stack, elements are pushed and popped from the
+ * beginning of the deque.  Stack methods are precisely equivalent to
+ * {@code Deque} methods as indicated in the table below:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Comparison of Stack and Deque methods</caption>
+ *  <tr>
+ *    <td ALIGN=CENTER> <b>Stack Method</b></td>
+ *    <td ALIGN=CENTER> <b>Equivalent {@code Deque} Method</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #push push(e)}</td>
+ *    <td>{@link #addFirst addFirst(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #pop pop()}</td>
+ *    <td>{@link #removeFirst removeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #peek peek()}</td>
+ *    <td>{@link #peekFirst peekFirst()}</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Note that the {@link #peek peek} method works equally well when
+ * a deque is used as a queue or a stack; in either case, elements are
+ * drawn from the beginning of the deque.
+ *
+ * <p>This interface provides two methods to remove interior
+ * elements, {@link #removeFirstOccurrence removeFirstOccurrence} and
+ * {@link #removeLastOccurrence removeLastOccurrence}.
+ *
+ * <p>Unlike the {@link List} interface, this interface does not
+ * provide support for indexed access to elements.
+ *
+ * <p>While {@code Deque} implementations are not strictly required
+ * to prohibit the insertion of null elements, they are strongly
+ * encouraged to do so.  Users of any {@code Deque} implementations
+ * that do allow null elements are strongly encouraged <i>not</i> to
+ * take advantage of the ability to insert nulls.  This is so because
+ * {@code null} is used as a special return value by various methods
+ * to indicated that the deque is empty.
+ *
+ * <p>{@code Deque} implementations generally do not define
+ * element-based versions of the {@code equals} and {@code hashCode}
+ * methods, but instead inherit the identity-based versions from class
+ * {@code Object}.
+ *
+ * @author Doug Lea
+ * @author Josh Bloch
+ * @since  1.6
+ * @param <E> the type of elements held in this deque
+ */
+public interface Deque<E> extends Queue<E> {
+    // Android-changed: fix framework docs link to "Collection#optional-restrictions"
+    // Several occurrences of the link have been fixed throughout.
+
+    /**
+     * Inserts the specified element at the front of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use method {@link #offerFirst}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void addFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use method {@link #offerLast}.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void addLast(E e);
+
+    /**
+     * Inserts the specified element at the front of this deque unless it would
+     * violate capacity restrictions.  When using a capacity-restricted deque,
+     * this method is generally preferable to the {@link #addFirst} method,
+     * which can fail to insert an element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque unless it would
+     * violate capacity restrictions.  When using a capacity-restricted deque,
+     * this method is generally preferable to the {@link #addLast} method,
+     * which can fail to insert an element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerLast(E e);
+
+    /**
+     * Retrieves and removes the first element of this deque.  This method
+     * differs from {@link #pollFirst pollFirst} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * @return the head of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E removeFirst();
+
+    /**
+     * Retrieves and removes the last element of this deque.  This method
+     * differs from {@link #pollLast pollLast} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * @return the tail of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E removeLast();
+
+    /**
+     * Retrieves and removes the first element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E pollFirst();
+
+    /**
+     * Retrieves and removes the last element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the tail of this deque, or {@code null} if this deque is empty
+     */
+    E pollLast();
+
+    /**
+     * Retrieves, but does not remove, the first element of this deque.
+     *
+     * This method differs from {@link #peekFirst peekFirst} only in that it
+     * throws an exception if this deque is empty.
+     *
+     * @return the head of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E getFirst();
+
+    /**
+     * Retrieves, but does not remove, the last element of this deque.
+     * This method differs from {@link #peekLast peekLast} only in that it
+     * throws an exception if this deque is empty.
+     *
+     * @return the tail of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E getLast();
+
+    /**
+     * Retrieves, but does not remove, the first element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E peekFirst();
+
+    /**
+     * Retrieves, but does not remove, the last element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the tail of this deque, or {@code null} if this deque is empty
+     */
+    E peekLast();
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code Objects.equals(o, e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if an element was removed as a result of this call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean removeFirstOccurrence(Object o);
+
+    /**
+     * Removes the last occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code Objects.equals(o, e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if an element was removed as a result of this call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean removeLastOccurrence(Object o);
+
+    // *** Queue methods ***
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     * When using a capacity-restricted deque, it is generally preferable to
+     * use {@link #offer(Object) offer}.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean add(E e);
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and {@code false} if no space is currently
+     * available.  When using a capacity-restricted deque, this method is
+     * generally preferable to the {@link #add} method, which can fail to
+     * insert an element only by throwing an exception.
+     *
+     * <p>This method is equivalent to {@link #offerLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offer(E e);
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque).
+     * This method differs from {@link #poll poll} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E remove();
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), or returns
+     * {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #pollFirst()}.
+     *
+     * @return the first element of this deque, or {@code null} if
+     *         this deque is empty
+     */
+    E poll();
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque).
+     * This method differs from {@link #peek peek} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst()}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E element();
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque), or
+     * returns {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #peekFirst()}.
+     *
+     * @return the head of the queue represented by this deque, or
+     *         {@code null} if this deque is empty
+     */
+    E peek();
+
+
+    // *** Stack methods ***
+
+    /**
+     * Pushes an element onto the stack represented by this deque (in other
+     * words, at the head of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     *
+     * <p>This method is equivalent to {@link #addFirst}.
+     *
+     * @param e the element to push
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void push(E e);
+
+    /**
+     * Pops an element from the stack represented by this deque.  In other
+     * words, removes and returns the first element of this deque.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the element at the front of this deque (which is the top
+     *         of the stack represented by this deque)
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E pop();
+
+
+    // *** Collection methods ***
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code Objects.equals(o, e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if an element was removed as a result of this call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean remove(Object o);
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this deque is to be tested
+     * @return {@code true} if this deque contains the specified element
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    int size();
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an iterator over the elements in this deque in reverse
+     * sequential order.  The elements will be returned in order from
+     * last (tail) to first (head).
+     *
+     * @return an iterator over the elements in this deque in reverse
+     * sequence
+     */
+    Iterator<E> descendingIterator();
+
+}
diff --git a/java/util/Dictionary.java b/java/util/Dictionary.java
new file mode 100644
index 0000000..4c4574b
--- /dev/null
+++ b/java/util/Dictionary.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * The <code>Dictionary</code> class is the abstract parent of any
+ * class, such as <code>Hashtable</code>, which maps keys to values.
+ * Every key and every value is an object. In any one <tt>Dictionary</tt>
+ * object, every key is associated with at most one value. Given a
+ * <tt>Dictionary</tt> and a key, the associated element can be looked up.
+ * Any non-<code>null</code> object can be used as a key and as a value.
+ * <p>
+ * As a rule, the <code>equals</code> method should be used by
+ * implementations of this class to decide if two keys are the same.
+ * <p>
+ * <strong>NOTE: This class is obsolete.  New implementations should
+ * implement the Map interface, rather than extending this class.</strong>
+ *
+ * @author  unascribed
+ * @see     java.util.Map
+ * @see     java.lang.Object#equals(java.lang.Object)
+ * @see     java.lang.Object#hashCode()
+ * @see     java.util.Hashtable
+ * @since   JDK1.0
+ */
+public abstract
+class Dictionary<K,V> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public Dictionary() {
+    }
+
+    /**
+     * Returns the number of entries (distinct keys) in this dictionary.
+     *
+     * @return  the number of keys in this dictionary.
+     */
+    abstract public int size();
+
+    /**
+     * Tests if this dictionary maps no keys to value. The general contract
+     * for the <tt>isEmpty</tt> method is that the result is true if and only
+     * if this dictionary contains no entries.
+     *
+     * @return  <code>true</code> if this dictionary maps no keys to values;
+     *          <code>false</code> otherwise.
+     */
+    abstract public boolean isEmpty();
+
+    /**
+     * Returns an enumeration of the keys in this dictionary. The general
+     * contract for the keys method is that an <tt>Enumeration</tt> object
+     * is returned that will generate all the keys for which this dictionary
+     * contains entries.
+     *
+     * @return  an enumeration of the keys in this dictionary.
+     * @see     java.util.Dictionary#elements()
+     * @see     java.util.Enumeration
+     */
+    abstract public Enumeration<K> keys();
+
+    /**
+     * Returns an enumeration of the values in this dictionary. The general
+     * contract for the <tt>elements</tt> method is that an
+     * <tt>Enumeration</tt> is returned that will generate all the elements
+     * contained in entries in this dictionary.
+     *
+     * @return  an enumeration of the values in this dictionary.
+     * @see     java.util.Dictionary#keys()
+     * @see     java.util.Enumeration
+     */
+    abstract public Enumeration<V> elements();
+
+    /**
+     * Returns the value to which the key is mapped in this dictionary.
+     * The general contract for the <tt>isEmpty</tt> method is that if this
+     * dictionary contains an entry for the specified key, the associated
+     * value is returned; otherwise, <tt>null</tt> is returned.
+     *
+     * @return  the value to which the key is mapped in this dictionary;
+     * @param   key   a key in this dictionary.
+     *          <code>null</code> if the key is not mapped to any value in
+     *          this dictionary.
+     * @exception NullPointerException if the <tt>key</tt> is <tt>null</tt>.
+     * @see     java.util.Dictionary#put(java.lang.Object, java.lang.Object)
+     */
+    abstract public V get(Object key);
+
+    /**
+     * Maps the specified <code>key</code> to the specified
+     * <code>value</code> in this dictionary. Neither the key nor the
+     * value can be <code>null</code>.
+     * <p>
+     * If this dictionary already contains an entry for the specified
+     * <tt>key</tt>, the value already in this dictionary for that
+     * <tt>key</tt> is returned, after modifying the entry to contain the
+     *  new element. <p>If this dictionary does not already have an entry
+     *  for the specified <tt>key</tt>, an entry is created for the
+     *  specified <tt>key</tt> and <tt>value</tt>, and <tt>null</tt> is
+     *  returned.
+     * <p>
+     * The <code>value</code> can be retrieved by calling the
+     * <code>get</code> method with a <code>key</code> that is equal to
+     * the original <code>key</code>.
+     *
+     * @param      key     the hashtable key.
+     * @param      value   the value.
+     * @return     the previous value to which the <code>key</code> was mapped
+     *             in this dictionary, or <code>null</code> if the key did not
+     *             have a previous mapping.
+     * @exception  NullPointerException  if the <code>key</code> or
+     *               <code>value</code> is <code>null</code>.
+     * @see        java.lang.Object#equals(java.lang.Object)
+     * @see        java.util.Dictionary#get(java.lang.Object)
+     */
+    abstract public V put(K key, V value);
+
+    /**
+     * Removes the <code>key</code> (and its corresponding
+     * <code>value</code>) from this dictionary. This method does nothing
+     * if the <code>key</code> is not in this dictionary.
+     *
+     * @param   key   the key that needs to be removed.
+     * @return  the value to which the <code>key</code> had been mapped in this
+     *          dictionary, or <code>null</code> if the key did not have a
+     *          mapping.
+     * @exception NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    abstract public V remove(Object key);
+}
diff --git a/java/util/DoubleSummaryStatistics.java b/java/util/DoubleSummaryStatistics.java
new file mode 100644
index 0000000..222d967
--- /dev/null
+++ b/java/util/DoubleSummaryStatistics.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.DoubleConsumer;
+import java.util.stream.Collector;
+
+/**
+ * A state object for collecting statistics such as count, min, max, sum, and
+ * average.
+ *
+ * <p>This class is designed to work with (though does not require)
+ * {@linkplain java.util.stream streams}. For example, you can compute
+ * summary statistics on a stream of doubles with:
+ * <pre> {@code
+ * DoubleSummaryStatistics stats = doubleStream.collect(DoubleSummaryStatistics::new,
+ *                                                      DoubleSummaryStatistics::accept,
+ *                                                      DoubleSummaryStatistics::combine);
+ * }</pre>
+ *
+ * <p>{@code DoubleSummaryStatistics} can be used as a
+ * {@linkplain java.util.stream.Stream#collect(Collector) reduction}
+ * target for a {@linkplain java.util.stream.Stream stream}. For example:
+ *
+ * <pre> {@code
+ * DoubleSummaryStatistics stats = people.stream()
+ *     .collect(Collectors.summarizingDouble(Person::getWeight));
+ *}</pre>
+ *
+ * This computes, in a single pass, the count of people, as well as the minimum,
+ * maximum, sum, and average of their weights.
+ *
+ * @implNote This implementation is not thread safe. However, it is safe to use
+ * {@link java.util.stream.Collectors#summarizingDouble(java.util.function.ToDoubleFunction)
+ * Collectors.toDoubleStatistics()} on a parallel stream, because the parallel
+ * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
+ * provides the necessary partitioning, isolation, and merging of results for
+ * safe and efficient parallel execution.
+ * @since 1.8
+ */
+public class DoubleSummaryStatistics implements DoubleConsumer {
+    private long count;
+    private double sum;
+    private double sumCompensation; // Low order bits of sum
+    private double simpleSum; // Used to compute right sum for non-finite inputs
+    private double min = Double.POSITIVE_INFINITY;
+    private double max = Double.NEGATIVE_INFINITY;
+
+    /**
+     * Construct an empty instance with zero count, zero sum,
+     * {@code Double.POSITIVE_INFINITY} min, {@code Double.NEGATIVE_INFINITY}
+     * max and zero average.
+     */
+    public DoubleSummaryStatistics() { }
+
+    /**
+     * Records another value into the summary information.
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(double value) {
+        ++count;
+        simpleSum += value;
+        sumWithCompensation(value);
+        min = Math.min(min, value);
+        max = Math.max(max, value);
+    }
+
+    /**
+     * Combines the state of another {@code DoubleSummaryStatistics} into this
+     * one.
+     *
+     * @param other another {@code DoubleSummaryStatistics}
+     * @throws NullPointerException if {@code other} is null
+     */
+    public void combine(DoubleSummaryStatistics other) {
+        count += other.count;
+        simpleSum += other.simpleSum;
+        sumWithCompensation(other.sum);
+        sumWithCompensation(other.sumCompensation);
+        min = Math.min(min, other.min);
+        max = Math.max(max, other.max);
+    }
+
+    /**
+     * Incorporate a new double value using Kahan summation /
+     * compensated summation.
+     */
+    private void sumWithCompensation(double value) {
+        double tmp = value - sumCompensation;
+        double velvel = sum + tmp; // Little wolf of rounding error
+        sumCompensation = (velvel - sum) - tmp;
+        sum = velvel;
+    }
+
+    /**
+     * Return the count of values recorded.
+     *
+     * @return the count of values
+     */
+    public final long getCount() {
+        return count;
+    }
+
+    /**
+     * Returns the sum of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * If any recorded value is a NaN or the sum is at any point a NaN
+     * then the sum will be NaN.
+     *
+     * <p> The value of a floating-point sum is a function both of the
+     * input values as well as the order of addition operations. The
+     * order of addition operations of this method is intentionally
+     * not defined to allow for implementation flexibility to improve
+     * the speed and accuracy of the computed result.
+     *
+     * In particular, this method may be implemented using compensated
+     * summation or other technique to reduce the error bound in the
+     * numerical sum compared to a simple summation of {@code double}
+     * values.
+     *
+     * @apiNote Values sorted by increasing absolute magnitude tend to yield
+     * more accurate results.
+     *
+     * @return the sum of values, or zero if none
+     */
+    public final double getSum() {
+        // Better error bounds to add both terms as the final sum
+        double tmp =  sum + sumCompensation;
+        if (Double.isNaN(tmp) && Double.isInfinite(simpleSum))
+            // If the compensated sum is spuriously NaN from
+            // accumulating one or more same-signed infinite values,
+            // return the correctly-signed infinity stored in
+            // simpleSum.
+            return simpleSum;
+        else
+            return tmp;
+    }
+
+    /**
+     * Returns the minimum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
+     * recorded. Unlike the numerical comparison operators, this method
+     * considers negative zero to be strictly smaller than positive zero.
+     *
+     * @return the minimum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
+     * recorded
+     */
+    public final double getMin() {
+        return min;
+    }
+
+    /**
+     * Returns the maximum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were
+     * recorded. Unlike the numerical comparison operators, this method
+     * considers negative zero to be strictly smaller than positive zero.
+     *
+     * @return the maximum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were
+     * recorded
+     */
+    public final double getMax() {
+        return max;
+    }
+
+    /**
+     * Returns the arithmetic mean of values recorded, or zero if no
+     * values have been recorded.
+     *
+     * If any recorded value is a NaN or the sum is at any point a NaN
+     * then the average will be code NaN.
+     *
+     * <p>The average returned can vary depending upon the order in
+     * which values are recorded.
+     *
+     * This method may be implemented using compensated summation or
+     * other technique to reduce the error bound in the {@link #getSum
+     * numerical sum} used to compute the average.
+     *
+     * @apiNote Values sorted by increasing absolute magnitude tend to yield
+     * more accurate results.
+     *
+     * @return the arithmetic mean of values, or zero if none
+     */
+    public final double getAverage() {
+        return getCount() > 0 ? getSum() / getCount() : 0.0d;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     */
+    @Override
+    public String toString() {
+        return String.format(
+            "%s{count=%d, sum=%f, min=%f, average=%f, max=%f}",
+            this.getClass().getSimpleName(),
+            getCount(),
+            getSum(),
+            getMin(),
+            getAverage(),
+            getMax());
+    }
+}
diff --git a/java/util/DualPivotQuicksort.java b/java/util/DualPivotQuicksort.java
new file mode 100644
index 0000000..4682dde
--- /dev/null
+++ b/java/util/DualPivotQuicksort.java
@@ -0,0 +1,3078 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class implements the Dual-Pivot Quicksort algorithm by
+ * Vladimir Yaroslavskiy, Jon Bentley, and Josh Bloch. The algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
+ *
+ * All exposed methods are package-private, designed to be invoked
+ * from public methods (in class Arrays) after performing any
+ * necessary array bounds checks and expanding parameters into the
+ * required forms.
+ *
+ * @author Vladimir Yaroslavskiy
+ * @author Jon Bentley
+ * @author Josh Bloch
+ *
+ * @version 2011.02.11 m765.827.12i:5\7pm
+ * @since 1.7
+ */
+final class DualPivotQuicksort {
+
+    /**
+     * Prevents instantiation.
+     */
+    private DualPivotQuicksort() {}
+
+    /*
+     * Tuning parameters.
+     */
+
+    /**
+     * The maximum number of runs in merge sort.
+     */
+    private static final int MAX_RUN_COUNT = 67;
+
+    /**
+     * The maximum length of run in merge sort.
+     */
+    private static final int MAX_RUN_LENGTH = 33;
+
+    /**
+     * If the length of an array to be sorted is less than this
+     * constant, Quicksort is used in preference to merge sort.
+     */
+    private static final int QUICKSORT_THRESHOLD = 286;
+
+    /**
+     * If the length of an array to be sorted is less than this
+     * constant, insertion sort is used in preference to Quicksort.
+     */
+    private static final int INSERTION_SORT_THRESHOLD = 47;
+
+    /**
+     * If the length of a byte array to be sorted is greater than this
+     * constant, counting sort is used in preference to insertion sort.
+     */
+    private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 29;
+
+    /**
+     * If the length of a short or char array to be sorted is greater
+     * than this constant, counting sort is used in preference to Quicksort.
+     */
+    private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 3200;
+
+    /*
+     * Sorting methods for seven primitive types.
+     */
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(int[] a, int left, int right,
+                     int[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    int t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        int[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new int[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            int[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(int[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    int ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    int a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                int last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { int t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { int t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { int t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { int t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            int pivot1 = a[e2];
+            int pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                int ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    int ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = pivot1;
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            int pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                int ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = pivot;
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(long[] a, int left, int right,
+                     long[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    long t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        long[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new long[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            long[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(long[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    long ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    long a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                long last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { long t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { long t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { long t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            long pivot1 = a[e2];
+            long pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                long ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    long ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = pivot1;
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            long pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                long ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = pivot;
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(short[] a, int left, int right,
+                     short[] work, int workBase, int workLen) {
+        // Use counting sort on large arrays
+        if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+            int[] count = new int[NUM_SHORT_VALUES];
+
+            for (int i = left - 1; ++i <= right;
+                count[a[i] - Short.MIN_VALUE]++
+            );
+            for (int i = NUM_SHORT_VALUES, k = right + 1; k > left; ) {
+                while (count[--i] == 0);
+                short value = (short) (i + Short.MIN_VALUE);
+                int s = count[i];
+
+                do {
+                    a[--k] = value;
+                } while (--s > 0);
+            }
+        } else { // Use Dual-Pivot Quicksort on small arrays
+            doSort(a, left, right, work, workBase, workLen);
+        }
+    }
+
+    /** The number of distinct short values. */
+    private static final int NUM_SHORT_VALUES = 1 << 16;
+
+    /**
+     * Sorts the specified range of the array.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private static void doSort(short[] a, int left, int right,
+                               short[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    short t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        short[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new short[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            short[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(short[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    short ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    short a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                short last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { short t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { short t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { short t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            short pivot1 = a[e2];
+            short pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                short ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    short ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = pivot1;
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            short pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                short ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = pivot;
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(char[] a, int left, int right,
+                     char[] work, int workBase, int workLen) {
+        // Use counting sort on large arrays
+        if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+            int[] count = new int[NUM_CHAR_VALUES];
+
+            for (int i = left - 1; ++i <= right;
+                count[a[i]]++
+            );
+            for (int i = NUM_CHAR_VALUES, k = right + 1; k > left; ) {
+                while (count[--i] == 0);
+                char value = (char) i;
+                int s = count[i];
+
+                do {
+                    a[--k] = value;
+                } while (--s > 0);
+            }
+        } else { // Use Dual-Pivot Quicksort on small arrays
+            doSort(a, left, right, work, workBase, workLen);
+        }
+    }
+
+    /** The number of distinct char values. */
+    private static final int NUM_CHAR_VALUES = 1 << 16;
+
+    /**
+     * Sorts the specified range of the array.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private static void doSort(char[] a, int left, int right,
+                               char[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    char t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        char[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new char[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            char[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(char[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    char ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    char a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                char last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { char t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { char t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { char t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            char pivot1 = a[e2];
+            char pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                char ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    char ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = pivot1;
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            char pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                char ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = pivot;
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+
+    /** The number of distinct byte values. */
+    private static final int NUM_BYTE_VALUES = 1 << 8;
+
+    /**
+     * Sorts the specified range of the array.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     */
+    static void sort(byte[] a, int left, int right) {
+        // Use counting sort on large arrays
+        if (right - left > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
+            int[] count = new int[NUM_BYTE_VALUES];
+
+            for (int i = left - 1; ++i <= right;
+                count[a[i] - Byte.MIN_VALUE]++
+            );
+            for (int i = NUM_BYTE_VALUES, k = right + 1; k > left; ) {
+                while (count[--i] == 0);
+                byte value = (byte) (i + Byte.MIN_VALUE);
+                int s = count[i];
+
+                do {
+                    a[--k] = value;
+                } while (--s > 0);
+            }
+        } else { // Use insertion sort on small arrays
+            for (int i = left, j = i; i < right; j = ++i) {
+                byte ai = a[i + 1];
+                while (ai < a[j]) {
+                    a[j + 1] = a[j];
+                    if (j-- == left) {
+                        break;
+                    }
+                }
+                a[j + 1] = ai;
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(float[] a, int left, int right,
+                     float[] work, int workBase, int workLen) {
+        /*
+         * Phase 1: Move NaNs to the end of the array.
+         */
+        while (left <= right && Float.isNaN(a[right])) {
+            --right;
+        }
+        for (int k = right; --k >= left; ) {
+            float ak = a[k];
+            if (ak != ak) { // a[k] is NaN
+                a[k] = a[right];
+                a[right] = ak;
+                --right;
+            }
+        }
+
+        /*
+         * Phase 2: Sort everything except NaNs (which are already in place).
+         */
+        doSort(a, left, right, work, workBase, workLen);
+
+        /*
+         * Phase 3: Place negative zeros before positive zeros.
+         */
+        int hi = right;
+
+        /*
+         * Find the first zero, or first positive, or last negative element.
+         */
+        while (left < hi) {
+            int middle = (left + hi) >>> 1;
+            float middleValue = a[middle];
+
+            if (middleValue < 0.0f) {
+                left = middle + 1;
+            } else {
+                hi = middle;
+            }
+        }
+
+        /*
+         * Skip the last negative value (if any) or all leading negative zeros.
+         */
+        while (left <= right && Float.floatToRawIntBits(a[left]) < 0) {
+            ++left;
+        }
+
+        /*
+         * Move negative zeros to the beginning of the sub-range.
+         *
+         * Partitioning:
+         *
+         * +----------------------------------------------------+
+         * |   < 0.0   |   -0.0   |   0.0   |   ?  ( >= 0.0 )   |
+         * +----------------------------------------------------+
+         *              ^          ^         ^
+         *              |          |         |
+         *             left        p         k
+         *
+         * Invariants:
+         *
+         *   all in (*,  left)  <  0.0
+         *   all in [left,  p) == -0.0
+         *   all in [p,     k) ==  0.0
+         *   all in [k, right] >=  0.0
+         *
+         * Pointer k is the first index of ?-part.
+         */
+        for (int k = left, p = left - 1; ++k <= right; ) {
+            float ak = a[k];
+            if (ak != 0.0f) {
+                break;
+            }
+            if (Float.floatToRawIntBits(ak) < 0) { // ak is -0.0f
+                a[k] = 0.0f;
+                a[++p] = -0.0f;
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private static void doSort(float[] a, int left, int right,
+                               float[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    float t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        float[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new float[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            float[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(float[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    float ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    float a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                float last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { float t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { float t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { float t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { float t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            float pivot1 = a[e2];
+            float pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                float ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    float ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = a[great];
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            float pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                float ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = a[great];
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(double[] a, int left, int right,
+                     double[] work, int workBase, int workLen) {
+        /*
+         * Phase 1: Move NaNs to the end of the array.
+         */
+        while (left <= right && Double.isNaN(a[right])) {
+            --right;
+        }
+        for (int k = right; --k >= left; ) {
+            double ak = a[k];
+            if (ak != ak) { // a[k] is NaN
+                a[k] = a[right];
+                a[right] = ak;
+                --right;
+            }
+        }
+
+        /*
+         * Phase 2: Sort everything except NaNs (which are already in place).
+         */
+        doSort(a, left, right, work, workBase, workLen);
+
+        /*
+         * Phase 3: Place negative zeros before positive zeros.
+         */
+        int hi = right;
+
+        /*
+         * Find the first zero, or first positive, or last negative element.
+         */
+        while (left < hi) {
+            int middle = (left + hi) >>> 1;
+            double middleValue = a[middle];
+
+            if (middleValue < 0.0d) {
+                left = middle + 1;
+            } else {
+                hi = middle;
+            }
+        }
+
+        /*
+         * Skip the last negative value (if any) or all leading negative zeros.
+         */
+        while (left <= right && Double.doubleToRawLongBits(a[left]) < 0) {
+            ++left;
+        }
+
+        /*
+         * Move negative zeros to the beginning of the sub-range.
+         *
+         * Partitioning:
+         *
+         * +----------------------------------------------------+
+         * |   < 0.0   |   -0.0   |   0.0   |   ?  ( >= 0.0 )   |
+         * +----------------------------------------------------+
+         *              ^          ^         ^
+         *              |          |         |
+         *             left        p         k
+         *
+         * Invariants:
+         *
+         *   all in (*,  left)  <  0.0
+         *   all in [left,  p) == -0.0
+         *   all in [p,     k) ==  0.0
+         *   all in [k, right] >=  0.0
+         *
+         * Pointer k is the first index of ?-part.
+         */
+        for (int k = left, p = left - 1; ++k <= right; ) {
+            double ak = a[k];
+            if (ak != 0.0d) {
+                break;
+            }
+            if (Double.doubleToRawLongBits(ak) < 0) { // ak is -0.0d
+                a[k] = 0.0d;
+                a[++p] = -0.0d;
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private static void doSort(double[] a, int left, int right,
+                               double[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    double t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        double[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new double[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            double[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(double[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    double ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    double a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                double last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { double t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { double t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { double t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { double t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            double pivot1 = a[e2];
+            double pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                double ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    double ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = a[great];
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            double pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                double ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = a[great];
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+}
diff --git a/java/util/DuplicateFormatFlagsException.java b/java/util/DuplicateFormatFlagsException.java
new file mode 100644
index 0000000..0dcdf37
--- /dev/null
+++ b/java/util/DuplicateFormatFlagsException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when duplicate flags are provided in the format
+ * specifier.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class DuplicateFormatFlagsException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 18890531L;
+
+    private String flags;
+
+    /**
+     * Constructs an instance of this class with the specified flags.
+     *
+     * @param  f
+     *         The set of format flags which contain a duplicate flag.
+     */
+    public DuplicateFormatFlagsException(String f) {
+        if (f == null)
+            throw new NullPointerException();
+        this.flags = f;
+    }
+
+    /**
+     * Returns the set of flags which contains a duplicate flag.
+     *
+     * @return  The flags
+     */
+    public String getFlags() {
+        return flags;
+    }
+
+    public String getMessage() {
+        return String.format("Flags = '%s'", flags);
+    }
+}
diff --git a/java/util/EmptyStackException.java b/java/util/EmptyStackException.java
new file mode 100644
index 0000000..1f1e878
--- /dev/null
+++ b/java/util/EmptyStackException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Thrown by methods in the <code>Stack</code> class to indicate
+ * that the stack is empty.
+ *
+ * @author  Jonathan Payne
+ * @see     java.util.Stack
+ * @since   JDK1.0
+ */
+public
+class EmptyStackException extends RuntimeException {
+    private static final long serialVersionUID = 5084686378493302095L;
+
+    /**
+     * Constructs a new <code>EmptyStackException</code> with <tt>null</tt>
+     * as its error message string.
+     */
+    public EmptyStackException() {
+    }
+}
diff --git a/java/util/EnumMap.java b/java/util/EnumMap.java
new file mode 100644
index 0000000..cd1c5fe
--- /dev/null
+++ b/java/util/EnumMap.java
@@ -0,0 +1,813 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.Map.Entry;
+
+/**
+ * A specialized {@link Map} implementation for use with enum type keys.  All
+ * of the keys in an enum map must come from a single enum type that is
+ * specified, explicitly or implicitly, when the map is created.  Enum maps
+ * are represented internally as arrays.  This representation is extremely
+ * compact and efficient.
+ *
+ * <p>Enum maps are maintained in the <i>natural order</i> of their keys
+ * (the order in which the enum constants are declared).  This is reflected
+ * in the iterators returned by the collections views ({@link #keySet()},
+ * {@link #entrySet()}, and {@link #values()}).
+ *
+ * <p>Iterators returned by the collection views are <i>weakly consistent</i>:
+ * they will never throw {@link ConcurrentModificationException} and they may
+ * or may not show the effects of any modifications to the map that occur while
+ * the iteration is in progress.
+ *
+ * <p>Null keys are not permitted.  Attempts to insert a null key will
+ * throw {@link NullPointerException}.  Attempts to test for the
+ * presence of a null key or to remove one will, however, function properly.
+ * Null values are permitted.
+
+ * <P>Like most collection implementations <tt>EnumMap</tt> is not
+ * synchronized. If multiple threads access an enum map concurrently, and at
+ * least one of the threads modifies the map, it should be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the enum map.  If no such object exists,
+ * the map should be "wrapped" using the {@link Collections#synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access:
+ *
+ * <pre>
+ *     Map&lt;EnumKey, V&gt; m
+ *         = Collections.synchronizedMap(new EnumMap&lt;EnumKey, V&gt;(...));
+ * </pre>
+ *
+ * <p>Implementation note: All basic operations execute in constant time.
+ * They are likely (though not guaranteed) to be faster than their
+ * {@link HashMap} counterparts.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author Josh Bloch
+ * @see EnumSet
+ * @since 1.5
+ */
+public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
+    implements java.io.Serializable, Cloneable
+{
+    /**
+     * The <tt>Class</tt> object for the enum type of all the keys of this map.
+     *
+     * @serial
+     */
+    private final Class<K> keyType;
+
+    /**
+     * All of the values comprising K.  (Cached for performance.)
+     */
+    private transient K[] keyUniverse;
+
+    /**
+     * Array representation of this map.  The ith element is the value
+     * to which universe[i] is currently mapped, or null if it isn't
+     * mapped to anything, or NULL if it's mapped to null.
+     */
+    private transient Object[] vals;
+
+    /**
+     * The number of mappings in this map.
+     */
+    private transient int size = 0;
+
+    /**
+     * Distinguished non-null value for representing null values.
+     */
+    private static final Object NULL = new Object() {
+        public int hashCode() {
+            return 0;
+        }
+
+        public String toString() {
+            return "java.util.EnumMap.NULL";
+        }
+    };
+
+    private Object maskNull(Object value) {
+        return (value == null ? NULL : value);
+    }
+
+    @SuppressWarnings("unchecked")
+    private V unmaskNull(Object value) {
+        return (V)(value == NULL ? null : value);
+    }
+
+    private static final Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
+
+    /**
+     * Creates an empty enum map with the specified key type.
+     *
+     * @param keyType the class object of the key type for this enum map
+     * @throws NullPointerException if <tt>keyType</tt> is null
+     */
+    public EnumMap(Class<K> keyType) {
+        this.keyType = keyType;
+        keyUniverse = getKeyUniverse(keyType);
+        vals = new Object[keyUniverse.length];
+    }
+
+    /**
+     * Creates an enum map with the same key type as the specified enum
+     * map, initially containing the same mappings (if any).
+     *
+     * @param m the enum map from which to initialize this enum map
+     * @throws NullPointerException if <tt>m</tt> is null
+     */
+    public EnumMap(EnumMap<K, ? extends V> m) {
+        keyType = m.keyType;
+        keyUniverse = m.keyUniverse;
+        vals = m.vals.clone();
+        size = m.size;
+    }
+
+    /**
+     * Creates an enum map initialized from the specified map.  If the
+     * specified map is an <tt>EnumMap</tt> instance, this constructor behaves
+     * identically to {@link #EnumMap(EnumMap)}.  Otherwise, the specified map
+     * must contain at least one mapping (in order to determine the new
+     * enum map's key type).
+     *
+     * @param m the map from which to initialize this enum map
+     * @throws IllegalArgumentException if <tt>m</tt> is not an
+     *     <tt>EnumMap</tt> instance and contains no mappings
+     * @throws NullPointerException if <tt>m</tt> is null
+     */
+    public EnumMap(Map<K, ? extends V> m) {
+        if (m instanceof EnumMap) {
+            EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;
+            keyType = em.keyType;
+            keyUniverse = em.keyUniverse;
+            vals = em.vals.clone();
+            size = em.size;
+        } else {
+            if (m.isEmpty())
+                throw new IllegalArgumentException("Specified map is empty");
+            keyType = m.keySet().iterator().next().getDeclaringClass();
+            keyUniverse = getKeyUniverse(keyType);
+            vals = new Object[keyUniverse.length];
+            putAll(m);
+        }
+    }
+
+    // Query Operations
+
+    /**
+     * 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 maps one or more keys to the
+     * specified value.
+     *
+     * @param value the value whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map maps one or more keys to this value
+     */
+    public boolean containsValue(Object value) {
+        value = maskNull(value);
+
+        for (Object val : vals)
+            if (value.equals(val))
+                return true;
+
+        return false;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains a mapping for the specified
+     * key.
+     *
+     * @param key the key whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map contains a mapping for the specified
+     *            key
+     */
+    public boolean containsKey(Object key) {
+        return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null;
+    }
+
+    private boolean containsMapping(Object key, Object value) {
+        return isValidKey(key) &&
+            maskNull(value).equals(vals[((Enum<?>)key).ordinal()]);
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key == k)},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} 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 {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     */
+    public V get(Object key) {
+        return (isValidKey(key) ?
+                unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
+    }
+
+    // Modification Operations
+
+    /**
+     * 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 the key with which the specified value is to be associated
+     * @param value the value to be associated with the specified key
+     *
+     * @return the 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.)
+     * @throws NullPointerException if the specified key is null
+     */
+    public V put(K key, V value) {
+        typeCheck(key);
+
+        int index = key.ordinal();
+        Object oldValue = vals[index];
+        vals[index] = maskNull(value);
+        if (oldValue == null)
+            size++;
+        return unmaskNull(oldValue);
+    }
+
+    /**
+     * Removes the mapping for this key from this map if present.
+     *
+     * @param key the key whose mapping is to be removed from the map
+     * @return the previous value associated with specified key, or
+     *     <tt>null</tt> if there was no entry for key.  (A <tt>null</tt>
+     *     return can also indicate that the map previously associated
+     *     <tt>null</tt> with the specified key.)
+     */
+    public V remove(Object key) {
+        if (!isValidKey(key))
+            return null;
+        int index = ((Enum<?>)key).ordinal();
+        Object oldValue = vals[index];
+        vals[index] = null;
+        if (oldValue != null)
+            size--;
+        return unmaskNull(oldValue);
+    }
+
+    private boolean removeMapping(Object key, Object value) {
+        if (!isValidKey(key))
+            return false;
+        int index = ((Enum<?>)key).ordinal();
+        if (maskNull(value).equals(vals[index])) {
+            vals[index] = null;
+            size--;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if key is of the proper type to be a key in this
+     * enum map.
+     */
+    private boolean isValidKey(Object key) {
+        if (key == null)
+            return false;
+
+        // Cheaper than instanceof Enum followed by getDeclaringClass
+        Class<?> keyClass = key.getClass();
+        return keyClass == keyType || keyClass.getSuperclass() == keyType;
+    }
+
+    // Bulk Operations
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for
+     * any of the keys currently in the specified map.
+     *
+     * @param m the mappings to be stored in this map
+     * @throws NullPointerException the specified map is null, or if
+     *     one or more keys in the specified map are null
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        if (m instanceof EnumMap) {
+            EnumMap<?, ?> em = (EnumMap<?, ?>)m;
+            if (em.keyType != keyType) {
+                if (em.isEmpty())
+                    return;
+                throw new ClassCastException(em.keyType + " != " + keyType);
+            }
+
+            for (int i = 0; i < keyUniverse.length; i++) {
+                Object emValue = em.vals[i];
+                if (emValue != null) {
+                    if (vals[i] == null)
+                        size++;
+                    vals[i] = emValue;
+                }
+            }
+        } else {
+            super.putAll(m);
+        }
+    }
+
+    /**
+     * Removes all mappings from this map.
+     */
+    public void clear() {
+        Arrays.fill(vals, null);
+        size = 0;
+    }
+
+    // Views
+
+    /**
+     * This field is initialized to contain an instance of the entry set
+     * view the first time this view is requested.  The view is stateless,
+     * so there's no reason to create more than one.
+     */
+    private transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The returned set obeys the general contract outlined in
+     * {@link Map#keySet()}.  The set's iterator will return the keys
+     * in their natural order (the order in which the enum constants
+     * are declared).
+     *
+     * @return a set view of the keys contained in this enum map
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return new KeyIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+        public boolean remove(Object o) {
+            int oldSize = size;
+            EnumMap.this.remove(o);
+            return size != oldSize;
+        }
+        public void clear() {
+            EnumMap.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The returned collection obeys the general contract outlined in
+     * {@link Map#values()}.  The collection's iterator will return the
+     * values in the order their corresponding keys appear in map,
+     * which is their natural order (the order in which the enum constants
+     * are declared).
+     *
+     * @return a collection view of the values contained in this map
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    private class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+        public boolean remove(Object o) {
+            o = maskNull(o);
+
+            for (int i = 0; i < vals.length; i++) {
+                if (o.equals(vals[i])) {
+                    vals[i] = null;
+                    size--;
+                    return true;
+                }
+            }
+            return false;
+        }
+        public void clear() {
+            EnumMap.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The returned set obeys the general contract outlined in
+     * {@link Map#keySet()}.  The set's iterator will return the
+     * mappings in the order their keys appear in map, which is their
+     * natural order (the order in which the enum constants are declared).
+     *
+     * @return a set view of the mappings contained in this enum map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es = entrySet;
+        if (es != null)
+            return es;
+        else
+            return entrySet = new EntrySet();
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+            return containsMapping(entry.getKey(), entry.getValue());
+        }
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+            return removeMapping(entry.getKey(), entry.getValue());
+        }
+        public int size() {
+            return size;
+        }
+        public void clear() {
+            EnumMap.this.clear();
+        }
+        public Object[] toArray() {
+            return fillEntryArray(new Object[size]);
+        }
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int size = size();
+            if (a.length < size)
+                a = (T[])java.lang.reflect.Array
+                    .newInstance(a.getClass().getComponentType(), size);
+            if (a.length > size)
+                a[size] = null;
+            return (T[]) fillEntryArray(a);
+        }
+        private Object[] fillEntryArray(Object[] a) {
+            int j = 0;
+            for (int i = 0; i < vals.length; i++)
+                if (vals[i] != null)
+                    a[j++] = new AbstractMap.SimpleEntry<>(
+                        keyUniverse[i], unmaskNull(vals[i]));
+            return a;
+        }
+    }
+
+    private abstract class EnumMapIterator<T> implements Iterator<T> {
+        // Lower bound on index of next element to return
+        int index = 0;
+
+        // Index of last returned element, or -1 if none
+        int lastReturnedIndex = -1;
+
+        public boolean hasNext() {
+            while (index < vals.length && vals[index] == null)
+                index++;
+            return index != vals.length;
+        }
+
+        public void remove() {
+            checkLastReturnedIndex();
+
+            if (vals[lastReturnedIndex] != null) {
+                vals[lastReturnedIndex] = null;
+                size--;
+            }
+            lastReturnedIndex = -1;
+        }
+
+        private void checkLastReturnedIndex() {
+            if (lastReturnedIndex < 0)
+                throw new IllegalStateException();
+        }
+    }
+
+    private class KeyIterator extends EnumMapIterator<K> {
+        public K next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturnedIndex = index++;
+            return keyUniverse[lastReturnedIndex];
+        }
+    }
+
+    private class ValueIterator extends EnumMapIterator<V> {
+        public V next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturnedIndex = index++;
+            return unmaskNull(vals[lastReturnedIndex]);
+        }
+    }
+
+    private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {
+        private Entry lastReturnedEntry;
+
+        public Map.Entry<K,V> next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturnedEntry = new Entry(index++);
+            return lastReturnedEntry;
+        }
+
+        public void remove() {
+            lastReturnedIndex =
+                ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
+            super.remove();
+            lastReturnedEntry.index = lastReturnedIndex;
+            lastReturnedEntry = null;
+        }
+
+        private class Entry implements Map.Entry<K,V> {
+            private int index;
+
+            private Entry(int index) {
+                this.index = index;
+            }
+
+            public K getKey() {
+                checkIndexForEntryUse();
+                return keyUniverse[index];
+            }
+
+            public V getValue() {
+                checkIndexForEntryUse();
+                return unmaskNull(vals[index]);
+            }
+
+            public V setValue(V value) {
+                checkIndexForEntryUse();
+                V oldValue = unmaskNull(vals[index]);
+                vals[index] = maskNull(value);
+                return oldValue;
+            }
+
+            public boolean equals(Object o) {
+                if (index < 0)
+                    return o == this;
+
+                if (!(o instanceof Map.Entry))
+                    return false;
+
+                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+                V ourValue = unmaskNull(vals[index]);
+                Object hisValue = e.getValue();
+                return (e.getKey() == keyUniverse[index] &&
+                        (ourValue == hisValue ||
+                         (ourValue != null && ourValue.equals(hisValue))));
+            }
+
+            public int hashCode() {
+                if (index < 0)
+                    return super.hashCode();
+
+                return entryHashCode(index);
+            }
+
+            public String toString() {
+                if (index < 0)
+                    return super.toString();
+
+                return keyUniverse[index] + "="
+                    + unmaskNull(vals[index]);
+            }
+
+            private void checkIndexForEntryUse() {
+                if (index < 0)
+                    throw new IllegalStateException("Entry was removed");
+            }
+        }
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * <tt>true</tt> if the given object is also a map and the two maps
+     * represent the same mappings, as specified in the {@link
+     * Map#equals(Object)} contract.
+     *
+     * @param o the object to be compared for equality with this map
+     * @return <tt>true</tt> if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o instanceof EnumMap)
+            return equals((EnumMap<?,?>)o);
+        if (!(o instanceof Map))
+            return false;
+
+        Map<?,?> m = (Map<?,?>)o;
+        if (size != m.size())
+            return false;
+
+        for (int i = 0; i < keyUniverse.length; i++) {
+            if (null != vals[i]) {
+                K key = keyUniverse[i];
+                V value = unmaskNull(vals[i]);
+                if (null == value) {
+                    if (!((null == m.get(key)) && m.containsKey(key)))
+                       return false;
+                } else {
+                   if (!value.equals(m.get(key)))
+                      return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    private boolean equals(EnumMap<?,?> em) {
+        if (em.keyType != keyType)
+            return size == 0 && em.size == 0;
+
+        // Key types match, compare each value
+        for (int i = 0; i < keyUniverse.length; i++) {
+            Object ourValue =    vals[i];
+            Object hisValue = em.vals[i];
+            if (hisValue != ourValue &&
+                (hisValue == null || !hisValue.equals(ourValue)))
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map.
+     */
+    public int hashCode() {
+        int h = 0;
+
+        for (int i = 0; i < keyUniverse.length; i++) {
+            if (null != vals[i]) {
+                h += entryHashCode(i);
+            }
+        }
+
+        return h;
+    }
+
+    private int entryHashCode(int index) {
+        return (keyUniverse[index].hashCode() ^ vals[index].hashCode());
+    }
+
+    /**
+     * Returns a shallow copy of this enum map.  (The values themselves
+     * are not cloned.
+     *
+     * @return a shallow copy of this enum map
+     */
+    @SuppressWarnings("unchecked")
+    public EnumMap<K, V> clone() {
+        EnumMap<K, V> result = null;
+        try {
+            result = (EnumMap<K, V>) super.clone();
+        } catch(CloneNotSupportedException e) {
+            throw new AssertionError();
+        }
+        result.vals = result.vals.clone();
+        result.entrySet = null;
+        return result;
+    }
+
+    /**
+     * Throws an exception if e is not of the correct type for this enum set.
+     */
+    private void typeCheck(K key) {
+        Class<?> keyClass = key.getClass();
+        if (keyClass != keyType && keyClass.getSuperclass() != keyType)
+            throw new ClassCastException(keyClass + " != " + keyType);
+    }
+
+    /**
+     * Returns all of the values comprising K.
+     * The result is uncloned, cached, and shared by all callers.
+     */
+    private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) {
+        // Android-changed: Use getEnumConstantsShared directly instead of going
+        // through SharedSecrets.
+        return keyType.getEnumConstantsShared();
+    }
+
+    private static final long serialVersionUID = 458661240069192865L;
+
+    /**
+     * Save the state of the <tt>EnumMap</tt> instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <i>size</i> of the enum map (the number of key-value
+     *             mappings) is emitted (int), followed by the key (Object)
+     *             and value (Object) for each key-value mapping represented
+     *             by the enum map.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException
+    {
+        // Write out the key type and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out size (number of Mappings)
+        s.writeInt(size);
+
+        // Write out keys and values (alternating)
+        int entriesToBeWritten = size;
+        for (int i = 0; entriesToBeWritten > 0; i++) {
+            if (null != vals[i]) {
+                s.writeObject(keyUniverse[i]);
+                s.writeObject(unmaskNull(vals[i]));
+                entriesToBeWritten--;
+            }
+        }
+    }
+
+    /**
+     * Reconstitute the <tt>EnumMap</tt> instance from a stream (i.e.,
+     * deserialize it).
+     */
+    @SuppressWarnings("unchecked")
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException
+    {
+        // Read in the key type and any hidden stuff
+        s.defaultReadObject();
+
+        keyUniverse = getKeyUniverse(keyType);
+        vals = new Object[keyUniverse.length];
+
+        // Read in size (number of Mappings)
+        int size = s.readInt();
+
+        // Read the keys and values, and put the mappings in the HashMap
+        for (int i = 0; i < size; i++) {
+            K key = (K) s.readObject();
+            V value = (V) s.readObject();
+            put(key, value);
+        }
+    }
+}
diff --git a/java/util/EnumSet.java b/java/util/EnumSet.java
new file mode 100644
index 0000000..95e0124
--- /dev/null
+++ b/java/util/EnumSet.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A specialized {@link Set} implementation for use with enum types.  All of
+ * the elements in an enum set must come from a single enum type that is
+ * specified, explicitly or implicitly, when the set is created.  Enum sets
+ * are represented internally as bit vectors.  This representation is
+ * extremely compact and efficient. The space and time performance of this
+ * class should be good enough to allow its use as a high-quality, typesafe
+ * alternative to traditional <tt>int</tt>-based "bit flags."  Even bulk
+ * operations (such as <tt>containsAll</tt> and <tt>retainAll</tt>) should
+ * run very quickly if their argument is also an enum set.
+ *
+ * <p>The iterator returned by the <tt>iterator</tt> method traverses the
+ * elements in their <i>natural order</i> (the order in which the enum
+ * constants are declared).  The returned iterator is <i>weakly
+ * consistent</i>: it will never throw {@link ConcurrentModificationException}
+ * and it may or may not show the effects of any modifications to the set that
+ * occur while the iteration is in progress.
+ *
+ * <p>Null elements are not permitted.  Attempts to insert a null element
+ * will throw {@link NullPointerException}.  Attempts to test for the
+ * presence of a null element or to remove one will, however, function
+ * properly.
+ *
+ * <P>Like most collection implementations, <tt>EnumSet</tt> is not
+ * synchronized.  If multiple threads access an enum set concurrently, and at
+ * least one of the threads modifies the set, it should be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the enum set.  If no such object exists,
+ * the set should be "wrapped" using the {@link Collections#synchronizedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access:
+ *
+ * <pre>
+ * Set&lt;MyEnum&gt; s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));
+ * </pre>
+ *
+ * <p>Implementation note: All basic operations execute in constant time.
+ * They are likely (though not guaranteed) to be much faster than their
+ * {@link HashSet} counterparts.  Even bulk operations execute in
+ * constant time if their argument is also an enum set.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author Josh Bloch
+ * @since 1.5
+ * @see EnumMap
+ * @serial exclude
+ */
+public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
+    implements Cloneable, java.io.Serializable
+{
+    /**
+     * The class of all the elements of this set.
+     */
+    final Class<E> elementType;
+
+    /**
+     * All of the values comprising T.  (Cached for performance.)
+     */
+    final Enum<?>[] universe;
+
+    private static Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
+
+    EnumSet(Class<E>elementType, Enum<?>[] universe) {
+        this.elementType = elementType;
+        this.universe    = universe;
+    }
+
+    /**
+     * Creates an empty enum set with the specified element type.
+     *
+     * @param <E> The class of the elements in the set
+     * @param elementType the class object of the element type for this enum
+     *     set
+     * @return An empty enum set of the specified type.
+     * @throws NullPointerException if <tt>elementType</tt> is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
+        Enum<?>[] universe = getUniverse(elementType);
+        if (universe == null)
+            throw new ClassCastException(elementType + " not an enum");
+
+        if (universe.length <= 64)
+            return new RegularEnumSet<>(elementType, universe);
+        else
+            return new JumboEnumSet<>(elementType, universe);
+    }
+
+    /**
+     * Creates an enum set containing all of the elements in the specified
+     * element type.
+     *
+     * @param <E> The class of the elements in the set
+     * @param elementType the class object of the element type for this enum
+     *     set
+     * @return An enum set containing all the elements in the specified type.
+     * @throws NullPointerException if <tt>elementType</tt> is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
+        EnumSet<E> result = noneOf(elementType);
+        result.addAll();
+        return result;
+    }
+
+    /**
+     * Adds all of the elements from the appropriate enum type to this enum
+     * set, which is empty prior to the call.
+     */
+    abstract void addAll();
+
+    /**
+     * Creates an enum set with the same element type as the specified enum
+     * set, initially containing the same elements (if any).
+     *
+     * @param <E> The class of the elements in the set
+     * @param s the enum set from which to initialize this enum set
+     * @return A copy of the specified enum set.
+     * @throws NullPointerException if <tt>s</tt> is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
+        return s.clone();
+    }
+
+    /**
+     * Creates an enum set initialized from the specified collection.  If
+     * the specified collection is an <tt>EnumSet</tt> instance, this static
+     * factory method behaves identically to {@link #copyOf(EnumSet)}.
+     * Otherwise, the specified collection must contain at least one element
+     * (in order to determine the new enum set's element type).
+     *
+     * @param <E> The class of the elements in the collection
+     * @param c the collection from which to initialize this enum set
+     * @return An enum set initialized from the given collection.
+     * @throws IllegalArgumentException if <tt>c</tt> is not an
+     *     <tt>EnumSet</tt> instance and contains no elements
+     * @throws NullPointerException if <tt>c</tt> is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {
+        if (c instanceof EnumSet) {
+            return ((EnumSet<E>)c).clone();
+        } else {
+            if (c.isEmpty())
+                throw new IllegalArgumentException("Collection is empty");
+            Iterator<E> i = c.iterator();
+            E first = i.next();
+            EnumSet<E> result = EnumSet.of(first);
+            while (i.hasNext())
+                result.add(i.next());
+            return result;
+        }
+    }
+
+    /**
+     * Creates an enum set with the same element type as the specified enum
+     * set, initially containing all the elements of this type that are
+     * <i>not</i> contained in the specified set.
+     *
+     * @param <E> The class of the elements in the enum set
+     * @param s the enum set from whose complement to initialize this enum set
+     * @return The complement of the specified set in this set
+     * @throws NullPointerException if <tt>s</tt> is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {
+        EnumSet<E> result = copyOf(s);
+        result.complement();
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified element.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the specified element and of the set
+     * @param e the element that this set is to contain initially
+     * @throws NullPointerException if <tt>e</tt> is null
+     * @return an enum set initially containing the specified element
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e) {
+        EnumSet<E> result = noneOf(e.getDeclaringClass());
+        result.add(e);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @param e3 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        result.add(e3);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @param e3 another element that this set is to contain initially
+     * @param e4 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        result.add(e3);
+        result.add(e4);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @param e3 another element that this set is to contain initially
+     * @param e4 another element that this set is to contain initially
+     * @param e5 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4,
+                                                    E e5)
+    {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        result.add(e3);
+        result.add(e4);
+        result.add(e5);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     * This factory, whose parameter list uses the varargs feature, may
+     * be used to create an enum set initially containing an arbitrary
+     * number of elements, but it is likely to run slower than the overloadings
+     * that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param first an element that the set is to contain initially
+     * @param rest the remaining elements the set is to contain initially
+     * @throws NullPointerException if any of the specified elements are null,
+     *     or if <tt>rest</tt> is null
+     * @return an enum set initially containing the specified elements
+     */
+    @SafeVarargs
+    public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
+        EnumSet<E> result = noneOf(first.getDeclaringClass());
+        result.add(first);
+        for (E e : rest)
+            result.add(e);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing all of the elements in the
+     * range defined by the two specified endpoints.  The returned set will
+     * contain the endpoints themselves, which may be identical but must not
+     * be out of order.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param from the first element in the range
+     * @param to the last element in the range
+     * @throws NullPointerException if {@code from} or {@code to} are null
+     * @throws IllegalArgumentException if {@code from.compareTo(to) > 0}
+     * @return an enum set initially containing all of the elements in the
+     *         range defined by the two specified endpoints
+     */
+    public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
+        if (from.compareTo(to) > 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        EnumSet<E> result = noneOf(from.getDeclaringClass());
+        result.addRange(from, to);
+        return result;
+    }
+
+    /**
+     * Adds the specified range to this enum set, which is empty prior
+     * to the call.
+     */
+    abstract void addRange(E from, E to);
+
+    /**
+     * Returns a copy of this set.
+     *
+     * @return a copy of this set
+     */
+    @SuppressWarnings("unchecked")
+    public EnumSet<E> clone() {
+        try {
+            return (EnumSet<E>) super.clone();
+        } catch(CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Complements the contents of this enum set.
+     */
+    abstract void complement();
+
+    /**
+     * Throws an exception if e is not of the correct type for this enum set.
+     */
+    final void typeCheck(E e) {
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            throw new ClassCastException(eClass + " != " + elementType);
+    }
+
+    /**
+     * Returns all of the values comprising E.
+     * The result is uncloned, cached, and shared by all callers.
+     */
+    private static <E extends Enum<E>> E[] getUniverse(Class<E> elementType) {
+        // Android-changed: Use getEnumConstantsShared directly instead of going
+        // through SharedSecrets.
+        return elementType.getEnumConstantsShared();
+    }
+
+    /**
+     * This class is used to serialize all EnumSet instances, regardless of
+     * implementation type.  It captures their "logical contents" and they
+     * are reconstructed using public static factories.  This is necessary
+     * to ensure that the existence of a particular implementation type is
+     * an implementation detail.
+     *
+     * @serial include
+     */
+    private static class SerializationProxy <E extends Enum<E>>
+        implements java.io.Serializable
+    {
+        /**
+         * The element type of this enum set.
+         *
+         * @serial
+         */
+        private final Class<E> elementType;
+
+        /**
+         * The elements contained in this enum set.
+         *
+         * @serial
+         */
+        private final Enum<?>[] elements;
+
+        SerializationProxy(EnumSet<E> set) {
+            elementType = set.elementType;
+            elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
+        }
+
+        // instead of cast to E, we should perhaps use elementType.cast()
+        // to avoid injection of forged stream, but it will slow the implementation
+        @SuppressWarnings("unchecked")
+        private Object readResolve() {
+            EnumSet<E> result = EnumSet.noneOf(elementType);
+            for (Enum<?> e : elements)
+                result.add((E)e);
+            return result;
+        }
+
+        private static final long serialVersionUID = 362491234563181265L;
+    }
+
+    Object writeReplace() {
+        return new SerializationProxy<>(this);
+    }
+
+    // readObject method for the serialization proxy pattern
+    // See Effective Java, Second Ed., Item 78.
+    private void readObject(java.io.ObjectInputStream stream)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+}
diff --git a/java/util/Enumeration.java b/java/util/Enumeration.java
new file mode 100644
index 0000000..8aebb5c
--- /dev/null
+++ b/java/util/Enumeration.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1994, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * An object that implements the Enumeration interface generates a
+ * series of elements, one at a time. Successive calls to the
+ * <code>nextElement</code> method return successive elements of the
+ * series.
+ * <p>
+ * For example, to print all elements of a <tt>Vector&lt;E&gt;</tt> <i>v</i>:
+ * <pre>
+ *   for (Enumeration&lt;E&gt; e = v.elements(); e.hasMoreElements();)
+ *       System.out.println(e.nextElement());</pre>
+ * <p>
+ * Methods are provided to enumerate through the elements of a
+ * vector, the keys of a hashtable, and the values in a hashtable.
+ * Enumerations are also used to specify the input streams to a
+ * <code>SequenceInputStream</code>.
+ * <p>
+ * NOTE: The functionality of this interface is duplicated by the Iterator
+ * interface.  In addition, Iterator adds an optional remove operation, and
+ * has shorter method names.  New implementations should consider using
+ * Iterator in preference to Enumeration.
+ *
+ * @see     java.util.Iterator
+ * @see     java.io.SequenceInputStream
+ * @see     java.util.Enumeration#nextElement()
+ * @see     java.util.Hashtable
+ * @see     java.util.Hashtable#elements()
+ * @see     java.util.Hashtable#keys()
+ * @see     java.util.Vector
+ * @see     java.util.Vector#elements()
+ *
+ * @author  Lee Boynton
+ * @since   JDK1.0
+ */
+public interface Enumeration<E> {
+    /**
+     * Tests if this enumeration contains more elements.
+     *
+     * @return  <code>true</code> if and only if this enumeration object
+     *           contains at least one more element to provide;
+     *          <code>false</code> otherwise.
+     */
+    boolean hasMoreElements();
+
+    /**
+     * Returns the next element of this enumeration if this enumeration
+     * object has at least one more element to provide.
+     *
+     * @return     the next element of this enumeration.
+     * @exception  NoSuchElementException  if no more elements exist.
+     */
+    E nextElement();
+}
diff --git a/java/util/EventListener.java b/java/util/EventListener.java
new file mode 100644
index 0000000..1daf446
--- /dev/null
+++ b/java/util/EventListener.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A tagging interface that all event listener interfaces must extend.
+ * @since JDK1.1
+ */
+public interface EventListener {
+}
diff --git a/java/util/EventListenerProxy.java b/java/util/EventListenerProxy.java
new file mode 100644
index 0000000..c982367
--- /dev/null
+++ b/java/util/EventListenerProxy.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * An abstract wrapper class for an {@code EventListener} class
+ * which associates a set of additional parameters with the listener.
+ * Subclasses must provide the storage and accessor methods
+ * for the additional arguments or parameters.
+ * <p>
+ * For example, a bean which supports named properties
+ * would have a two argument method signature for adding
+ * a {@code PropertyChangeListener} for a property:
+ * <pre>
+ * public void addPropertyChangeListener(String propertyName,
+ *                                       PropertyChangeListener listener)
+ * </pre>
+ * If the bean also implemented the zero argument get listener method:
+ * <pre>
+ * public PropertyChangeListener[] getPropertyChangeListeners()
+ * </pre>
+ * then the array may contain inner {@code PropertyChangeListeners}
+ * which are also {@code PropertyChangeListenerProxy} objects.
+ * <p>
+ * If the calling method is interested in retrieving the named property
+ * then it would have to test the element to see if it is a proxy class.
+ *
+ * @since 1.4
+ */
+public abstract class EventListenerProxy<T extends EventListener>
+        implements EventListener {
+
+    private final T listener;
+
+    /**
+     * Creates a proxy for the specified listener.
+     *
+     * @param listener  the listener object
+     */
+    public EventListenerProxy(T listener) {
+        this.listener = listener;
+    }
+
+    /**
+     * Returns the listener associated with the proxy.
+     *
+     * @return  the listener associated with the proxy
+     */
+    public T getListener() {
+        return this.listener;
+    }
+}
diff --git a/java/util/EventObject.java b/java/util/EventObject.java
new file mode 100644
index 0000000..3bccae1
--- /dev/null
+++ b/java/util/EventObject.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * <p>
+ * The root class from which all event state objects shall be derived.
+ * <p>
+ * All Events are constructed with a reference to the object, the "source",
+ * that is logically deemed to be the object upon which the Event in question
+ * initially occurred upon.
+ *
+ * @since JDK1.1
+ */
+
+public class EventObject implements java.io.Serializable {
+
+    private static final long serialVersionUID = 5516075349620653480L;
+
+    /**
+     * The object on which the Event initially occurred.
+     */
+    protected transient Object  source;
+
+    /**
+     * Constructs a prototypical Event.
+     *
+     * @param    source    The object on which the Event initially occurred.
+     * @exception  IllegalArgumentException  if source is null.
+     */
+    public EventObject(Object source) {
+        if (source == null)
+            throw new IllegalArgumentException("null source");
+
+        this.source = source;
+    }
+
+    /**
+     * The object on which the Event initially occurred.
+     *
+     * @return   The object on which the Event initially occurred.
+     */
+    public Object getSource() {
+        return source;
+    }
+
+    /**
+     * Returns a String representation of this EventObject.
+     *
+     * @return  A a String representation of this EventObject.
+     */
+    public String toString() {
+        return getClass().getName() + "[source=" + source + "]";
+    }
+}
diff --git a/java/util/FormatFlagsConversionMismatchException.java b/java/util/FormatFlagsConversionMismatchException.java
new file mode 100644
index 0000000..58f593e
--- /dev/null
+++ b/java/util/FormatFlagsConversionMismatchException.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when a conversion and flag are incompatible.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class FormatFlagsConversionMismatchException
+    extends IllegalFormatException
+{
+    private static final long serialVersionUID = 19120414L;
+
+    private String f;
+
+    private char c;
+
+    /**
+     * Constructs an instance of this class with the specified flag
+     * and conversion.
+     *
+     * @param  f
+     *         The flag
+     *
+     * @param  c
+     *         The conversion
+     */
+    public FormatFlagsConversionMismatchException(String f, char c) {
+        if (f == null)
+            throw new NullPointerException();
+        this.f = f;
+        this.c = c;
+    }
+
+    /**
+     * Returns the incompatible flag.
+     *
+     * @return  The flag
+     */
+     public String getFlags() {
+        return f;
+    }
+
+    /**
+     * Returns the incompatible conversion.
+     *
+     * @return  The conversion
+     */
+    public char getConversion() {
+        return c;
+    }
+
+    public String getMessage() {
+        return "Conversion = " + c + ", Flags = " + f;
+    }
+}
diff --git a/java/util/Formattable.java b/java/util/Formattable.java
new file mode 100644
index 0000000..f7e1e50
--- /dev/null
+++ b/java/util/Formattable.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+
+/**
+ * The <tt>Formattable</tt> interface must be implemented by any class that
+ * needs to perform custom formatting using the <tt>'s'</tt> conversion
+ * specifier of {@link java.util.Formatter}.  This interface allows basic
+ * control for formatting arbitrary objects.
+ *
+ * For example, the following class prints out different representations of a
+ * stock's name depending on the flags and length constraints:
+ *
+ * {@code
+ *   import java.nio.CharBuffer;
+ *   import java.util.Formatter;
+ *   import java.util.Formattable;
+ *   import java.util.Locale;
+ *   import static java.util.FormattableFlags.*;
+ *
+ *  ...
+ *
+ *   public class StockName implements Formattable {
+ *       private String symbol, companyName, frenchCompanyName;
+ *       public StockName(String symbol, String companyName,
+ *                        String frenchCompanyName) {
+ *           ...
+ *       }
+ *
+ *       ...
+ *
+ *       public void formatTo(Formatter fmt, int f, int width, int precision) {
+ *           StringBuilder sb = new StringBuilder();
+ *
+ *           // decide form of name
+ *           String name = companyName;
+ *           if (fmt.locale().equals(Locale.FRANCE))
+ *               name = frenchCompanyName;
+ *           boolean alternate = (f & ALTERNATE) == ALTERNATE;
+ *           boolean usesymbol = alternate || (precision != -1 && precision < 10);
+ *           String out = (usesymbol ? symbol : name);
+ *
+ *           // apply precision
+ *           if (precision == -1 || out.length() < precision) {
+ *               // write it all
+ *               sb.append(out);
+ *           } else {
+ *               sb.append(out.substring(0, precision - 1)).append('*');
+ *           }
+ *
+ *           // apply width and justification
+ *           int len = sb.length();
+ *           if (len < width)
+ *               for (int i = 0; i < width - len; i++)
+ *                   if ((f & LEFT_JUSTIFY) == LEFT_JUSTIFY)
+ *                       sb.append(' ');
+ *                   else
+ *                       sb.insert(0, ' ');
+ *
+ *           fmt.format(sb.toString());
+ *       }
+ *
+ *       public String toString() {
+ *           return String.format("%s - %s", symbol, companyName);
+ *       }
+ *   }
+ * }
+ *
+ * <p> When used in conjunction with the {@link java.util.Formatter}, the above
+ * class produces the following output for various format strings.
+ *
+ * {@code
+ *   Formatter fmt = new Formatter();
+ *   StockName sn = new StockName("HUGE", "Huge Fruit, Inc.",
+ *                                "Fruit Titanesque, Inc.");
+ *   fmt.format("%s", sn);                   //   -> "Huge Fruit, Inc."
+ *   fmt.format("%s", sn.toString());        //   -> "HUGE - Huge Fruit, Inc."
+ *   fmt.format("%#s", sn);                  //   -> "HUGE"
+ *   fmt.format("%-10.8s", sn);              //   -> "HUGE      "
+ *   fmt.format("%.12s", sn);                //   -> "Huge Fruit,*"
+ *   fmt.format(Locale.FRANCE, "%25s", sn);  //   -> "   Fruit Titanesque, Inc."
+ * }
+ *
+ * <p> Formattables are not necessarily safe for multithreaded access.  Thread
+ * safety is optional and may be enforced by classes that extend and implement
+ * this interface.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to
+ * any method in this interface will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since  1.5
+ */
+public interface Formattable {
+
+    /**
+     * Formats the object using the provided {@link Formatter formatter}.
+     *
+     * @param  formatter
+     *         The {@link Formatter formatter}.  Implementing classes may call
+     *         {@link Formatter#out() formatter.out()} or {@link
+     *         Formatter#locale() formatter.locale()} to obtain the {@link
+     *         Appendable} or {@link Locale} used by this
+     *         <tt>formatter</tt> respectively.
+     *
+     * @param  flags
+     *         The flags modify the output format.  The value is interpreted as
+     *         a bitmask.  Any combination of the following flags may be set:
+     *         {@link FormattableFlags#LEFT_JUSTIFY}, {@link
+     *         FormattableFlags#UPPERCASE}, and {@link
+     *         FormattableFlags#ALTERNATE}.  If no flags are set, the default
+     *         formatting of the implementing class will apply.
+     *
+     * @param  width
+     *         The minimum number of characters to be written to the output.
+     *         If the length of the converted value is less than the
+     *         <tt>width</tt> then the output will be padded by
+     *         <tt>'&nbsp;&nbsp;'</tt> until the total number of characters
+     *         equals width.  The padding is at the beginning by default.  If
+     *         the {@link FormattableFlags#LEFT_JUSTIFY} flag is set then the
+     *         padding will be at the end.  If <tt>width</tt> is <tt>-1</tt>
+     *         then there is no minimum.
+     *
+     * @param  precision
+     *         The maximum number of characters to be written to the output.
+     *         The precision is applied before the width, thus the output will
+     *         be truncated to <tt>precision</tt> characters even if the
+     *         <tt>width</tt> is greater than the <tt>precision</tt>.  If
+     *         <tt>precision</tt> is <tt>-1</tt> then there is no explicit
+     *         limit on the number of characters.
+     *
+     * @throws  IllegalFormatException
+     *          If any of the parameters are invalid.  For specification of all
+     *          possible formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     */
+    void formatTo(Formatter formatter, int flags, int width, int precision);
+}
diff --git a/java/util/FormattableFlags.java b/java/util/FormattableFlags.java
new file mode 100644
index 0000000..11a10dd
--- /dev/null
+++ b/java/util/FormattableFlags.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * FomattableFlags are passed to the {@link Formattable#formatTo
+ * Formattable.formatTo()} method and modify the output format for {@linkplain
+ * Formattable Formattables}.  Implementations of {@link Formattable} are
+ * responsible for interpreting and validating any flags.
+ *
+ * @since  1.5
+ */
+public class FormattableFlags {
+
+    // Explicit instantiation of this class is prohibited.
+    private FormattableFlags() {}
+
+    /**
+     * Left-justifies the output.  Spaces (<tt>'&#92;u0020'</tt>) will be added
+     * at the end of the converted value as required to fill the minimum width
+     * of the field.  If this flag is not set then the output will be
+     * right-justified.
+     *
+     * <p> This flag corresponds to <tt>'-'</tt> (<tt>'&#92;u002d'</tt>) in
+     * the format specifier.
+     */
+    public static final int LEFT_JUSTIFY = 1<<0; // '-'
+
+    /**
+     * Converts the output to upper case according to the rules of the
+     * {@linkplain java.util.Locale locale} given during creation of the
+     * <tt>formatter</tt> argument of the {@link Formattable#formatTo
+     * formatTo()} method.  The output should be equivalent the following
+     * invocation of {@link String#toUpperCase(java.util.Locale)}
+     *
+     * <pre>
+     *     out.toUpperCase() </pre>
+     *
+     * <p> This flag corresponds to <tt>'S'</tt> (<tt>'&#92;u0053'</tt>) in
+     * the format specifier.
+     */
+    public static final int UPPERCASE = 1<<1;    // 'S'
+
+    /**
+     * Requires the output to use an alternate form.  The definition of the
+     * form is specified by the <tt>Formattable</tt>.
+     *
+     * <p> This flag corresponds to <tt>'#'</tt> (<tt>'&#92;u0023'</tt>) in
+     * the format specifier.
+     */
+    public static final int ALTERNATE = 1<<2;    // '#'
+}
diff --git a/java/util/Formatter.java b/java/util/Formatter.java
new file mode 100644
index 0000000..0b0c095
--- /dev/null
+++ b/java/util/Formatter.java
@@ -0,0 +1,4808 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.Flushable;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+import java.math.RoundingMode;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.text.DateFormatSymbols;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQueries;
+
+import libcore.icu.LocaleData;
+import sun.misc.FpUtils;
+import sun.misc.DoubleConsts;
+import sun.misc.FormattedFloatingDecimal;
+
+// Android-changed: Use localized exponent separator for %e.
+/**
+ * An interpreter for printf-style format strings.  This class provides support
+ * for layout justification and alignment, common formats for numeric, string,
+ * and date/time data, and locale-specific output.  Common Java types such as
+ * {@code byte}, {@link java.math.BigDecimal BigDecimal}, and {@link Calendar}
+ * are supported.  Limited formatting customization for arbitrary user types is
+ * provided through the {@link Formattable} interface.
+ *
+ * <p> Formatters are not necessarily safe for multithreaded access.  Thread
+ * safety is optional and is the responsibility of users of methods in this
+ * class.
+ *
+ * <p> Formatted printing for the Java language is heavily inspired by C's
+ * {@code printf}.  Although the format strings are similar to C, some
+ * customizations have been made to accommodate the Java language and exploit
+ * some of its features.  Also, Java formatting is more strict than C's; for
+ * example, if a conversion is incompatible with a flag, an exception will be
+ * thrown.  In C inapplicable flags are silently ignored.  The format strings
+ * are thus intended to be recognizable to C programmers but not necessarily
+ * completely compatible with those in C.
+ *
+ * <p> Examples of expected usage:
+ *
+ * <blockquote><pre>
+ *   StringBuilder sb = new StringBuilder();
+ *   // Send all output to the Appendable object sb
+ *   Formatter formatter = new Formatter(sb, Locale.US);
+ *
+ *   // Explicit argument indices may be used to re-order output.
+ *   formatter.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d")
+ *   // -&gt; " d  c  b  a"
+ *
+ *   // Optional locale as the first argument can be used to get
+ *   // locale-specific formatting of numbers.  The precision and width can be
+ *   // given to round and align the value.
+ *   formatter.format(Locale.FRANCE, "e = %+10.4f", Math.E);
+ *   // -&gt; "e =    +2,7183"
+ *
+ *   // The '(' numeric flag may be used to format negative numbers with
+ *   // parentheses rather than a minus sign.  Group separators are
+ *   // automatically inserted.
+ *   formatter.format("Amount gained or lost since last statement: $ %(,.2f",
+ *                    balanceDelta);
+ *   // -&gt; "Amount gained or lost since last statement: $ (6,217.58)"
+ * </pre></blockquote>
+ *
+ * <p> Convenience methods for common formatting requests exist as illustrated
+ * by the following invocations:
+ *
+ * <blockquote><pre>
+ *   // Writes a formatted string to System.out.
+ *   System.out.format("Local time: %tT", Calendar.getInstance());
+ *   // -&gt; "Local time: 13:34:18"
+ *
+ *   // Writes formatted output to System.err.
+ *   System.err.printf("Unable to open file '%1$s': %2$s",
+ *                     fileName, exception.getMessage());
+ *   // -&gt; "Unable to open file 'food': No such file or directory"
+ * </pre></blockquote>
+ *
+ * <p> Like C's {@code sprintf(3)}, Strings may be formatted using the static
+ * method {@link String#format(String,Object...) String.format}:
+ *
+ * <blockquote><pre>
+ *   // Format a string containing a date.
+ *   import java.util.Calendar;
+ *   import java.util.GregorianCalendar;
+ *   import static java.util.Calendar.*;
+ *
+ *   Calendar c = new GregorianCalendar(1995, MAY, 23);
+ *   String s = String.format("Duke's Birthday: %1$tb %1$te, %1$tY", c);
+ *   // -&gt; s == "Duke's Birthday: May 23, 1995"
+ * </pre></blockquote>
+ *
+ * <h3><a name="org">Organization</a></h3>
+ *
+ * <p> This specification is divided into two sections.  The first section, <a
+ * href="#summary">Summary</a>, covers the basic formatting concepts.  This
+ * section is intended for users who want to get started quickly and are
+ * familiar with formatted printing in other programming languages.  The second
+ * section, <a href="#detail">Details</a>, covers the specific implementation
+ * details.  It is intended for users who want more precise specification of
+ * formatting behavior.
+ *
+ * <h3><a name="summary">Summary</a></h3>
+ *
+ * <p> This section is intended to provide a brief overview of formatting
+ * concepts.  For precise behavioral details, refer to the <a
+ * href="#detail">Details</a> section.
+ *
+ * <h4><a name="syntax">Format String Syntax</a></h4>
+ *
+ * <p> Every method which produces formatted output requires a <i>format
+ * string</i> and an <i>argument list</i>.  The format string is a {@link
+ * String} which may contain fixed text and one or more embedded <i>format
+ * specifiers</i>.  Consider the following example:
+ *
+ * <blockquote><pre>
+ *   Calendar c = ...;
+ *   String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
+ * </pre></blockquote>
+ *
+ * This format string is the first argument to the {@code format} method.  It
+ * contains three format specifiers "{@code %1$tm}", "{@code %1$te}", and
+ * "{@code %1$tY}" which indicate how the arguments should be processed and
+ * where they should be inserted in the text.  The remaining portions of the
+ * format string are fixed text including {@code "Dukes Birthday: "} and any
+ * other spaces or punctuation.
+ *
+ * The argument list consists of all arguments passed to the method after the
+ * format string.  In the above example, the argument list is of size one and
+ * consists of the {@link java.util.Calendar Calendar} object {@code c}.
+ *
+ * <ul>
+ *
+ * <li> The format specifiers for general, character, and numeric types have
+ * the following syntax:
+ *
+ * <blockquote><pre>
+ *   %[argument_index$][flags][width][.precision]conversion
+ * </pre></blockquote>
+ *
+ * <p> The optional <i>argument_index</i> is a decimal integer indicating the
+ * position of the argument in the argument list.  The first argument is
+ * referenced by "{@code 1$}", the second by "{@code 2$}", etc.
+ *
+ * <p> The optional <i>flags</i> is a set of characters that modify the output
+ * format.  The set of valid flags depends on the conversion.
+ *
+ * <p> The optional <i>width</i> is a positive decimal integer indicating
+ * the minimum number of characters to be written to the output.
+ *
+ * <p> The optional <i>precision</i> is a non-negative decimal integer usually
+ * used to restrict the number of characters.  The specific behavior depends on
+ * the conversion.
+ *
+ * <p> The required <i>conversion</i> is a character indicating how the
+ * argument should be formatted.  The set of valid conversions for a given
+ * argument depends on the argument's data type.
+ *
+ * <li> The format specifiers for types which are used to represents dates and
+ * times have the following syntax:
+ *
+ * <blockquote><pre>
+ *   %[argument_index$][flags][width]conversion
+ * </pre></blockquote>
+ *
+ * <p> The optional <i>argument_index</i>, <i>flags</i> and <i>width</i> are
+ * defined as above.
+ *
+ * <p> The required <i>conversion</i> is a two character sequence.  The first
+ * character is {@code 't'} or {@code 'T'}.  The second character indicates
+ * the format to be used.  These characters are similar to but not completely
+ * identical to those defined by GNU {@code date} and POSIX
+ * {@code strftime(3c)}.
+ *
+ * <li> The format specifiers which do not correspond to arguments have the
+ * following syntax:
+ *
+ * <blockquote><pre>
+ *   %[flags][width]conversion
+ * </pre></blockquote>
+ *
+ * <p> The optional <i>flags</i> and <i>width</i> is defined as above.
+ *
+ * <p> The required <i>conversion</i> is a character indicating content to be
+ * inserted in the output.
+ *
+ * </ul>
+ *
+ * <h4> Conversions </h4>
+ *
+ * <p> Conversions are divided into the following categories:
+ *
+ * <ol>
+ *
+ * <li> <b>General</b> - may be applied to any argument
+ * type
+ *
+ * <li> <b>Character</b> - may be applied to basic types which represent
+ * Unicode characters: {@code char}, {@link Character}, {@code byte}, {@link
+ * Byte}, {@code short}, and {@link Short}. This conversion may also be
+ * applied to the types {@code int} and {@link Integer} when {@link
+ * Character#isValidCodePoint} returns {@code true}
+ *
+ * <li> <b>Numeric</b>
+ *
+ * <ol>
+ *
+ * <li> <b>Integral</b> - may be applied to Java integral types: {@code byte},
+ * {@link Byte}, {@code short}, {@link Short}, {@code int} and {@link
+ * Integer}, {@code long}, {@link Long}, and {@link java.math.BigInteger
+ * BigInteger} (but not {@code char} or {@link Character})
+ *
+ * <li><b>Floating Point</b> - may be applied to Java floating-point types:
+ * {@code float}, {@link Float}, {@code double}, {@link Double}, and {@link
+ * java.math.BigDecimal BigDecimal}
+ *
+ * </ol>
+ *
+ * <li> <b>Date/Time</b> - may be applied to Java types which are capable of
+ * encoding a date or time: {@code long}, {@link Long}, {@link Calendar},
+ * {@link Date} and {@link TemporalAccessor TemporalAccessor}
+ *
+ * <li> <b>Percent</b> - produces a literal {@code '%'}
+ * (<tt>'&#92;u0025'</tt>)
+ *
+ * <li> <b>Line Separator</b> - produces the platform-specific line separator
+ *
+ * </ol>
+ *
+ * <p> The following table summarizes the supported conversions.  Conversions
+ * denoted by an upper-case character (i.e. {@code 'B'}, {@code 'H'},
+ * {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'}, {@code 'G'},
+ * {@code 'A'}, and {@code 'T'}) are the same as those for the corresponding
+ * lower-case conversion characters except that the result is converted to
+ * upper case according to the rules of the prevailing {@link java.util.Locale
+ * Locale}.  The result is equivalent to the following invocation of {@link
+ * String#toUpperCase()}
+ *
+ * <pre>
+ *    out.toUpperCase() </pre>
+ *
+ * <table cellpadding=5 summary="genConv">
+ *
+ * <tr><th valign="bottom"> Conversion
+ *     <th valign="bottom"> Argument Category
+ *     <th valign="bottom"> Description
+ *
+ * <tr><td valign="top"> {@code 'b'}, {@code 'B'}
+ *     <td valign="top"> general
+ *     <td> If the argument <i>arg</i> is {@code null}, then the result is
+ *     "{@code false}".  If <i>arg</i> is a {@code boolean} or {@link
+ *     Boolean}, then the result is the string returned by {@link
+ *     String#valueOf(boolean) String.valueOf(arg)}.  Otherwise, the result is
+ *     "true".
+ *
+ * <tr><td valign="top"> {@code 'h'}, {@code 'H'}
+ *     <td valign="top"> general
+ *     <td> If the argument <i>arg</i> is {@code null}, then the result is
+ *     "{@code null}".  Otherwise, the result is obtained by invoking
+ *     {@code Integer.toHexString(arg.hashCode())}.
+ *
+ * <tr><td valign="top"> {@code 's'}, {@code 'S'}
+ *     <td valign="top"> general
+ *     <td> If the argument <i>arg</i> is {@code null}, then the result is
+ *     "{@code null}".  If <i>arg</i> implements {@link Formattable}, then
+ *     {@link Formattable#formatTo arg.formatTo} is invoked. Otherwise, the
+ *     result is obtained by invoking {@code arg.toString()}.
+ *
+ * <tr><td valign="top">{@code 'c'}, {@code 'C'}
+ *     <td valign="top"> character
+ *     <td> The result is a Unicode character
+ *
+ * <tr><td valign="top">{@code 'd'}
+ *     <td valign="top"> integral
+ *     <td> The result is formatted as a decimal integer
+ *
+ * <tr><td valign="top">{@code 'o'}
+ *     <td valign="top"> integral
+ *     <td> The result is formatted as an octal integer
+ *
+ * <tr><td valign="top">{@code 'x'}, {@code 'X'}
+ *     <td valign="top"> integral
+ *     <td> The result is formatted as a hexadecimal integer
+ *
+ * <tr><td valign="top">{@code 'e'}, {@code 'E'}
+ *     <td valign="top"> floating point
+ *     <td> The result is formatted as a decimal number in computerized
+ *     scientific notation
+ *
+ * <tr><td valign="top">{@code 'f'}
+ *     <td valign="top"> floating point
+ *     <td> The result is formatted as a decimal number
+ *
+ * <tr><td valign="top">{@code 'g'}, {@code 'G'}
+ *     <td valign="top"> floating point
+ *     <td> The result is formatted using computerized scientific notation or
+ *     decimal format, depending on the precision and the value after rounding.
+ *
+ * <tr><td valign="top">{@code 'a'}, {@code 'A'}
+ *     <td valign="top"> floating point
+ *     <td> The result is formatted as a hexadecimal floating-point number with
+ *     a significand and an exponent. This conversion is <b>not</b> supported
+ *     for the {@code BigDecimal} type despite the latter's being in the
+ *     <i>floating point</i> argument category.
+ *
+ * <tr><td valign="top">{@code 't'}, {@code 'T'}
+ *     <td valign="top"> date/time
+ *     <td> Prefix for date and time conversion characters.  See <a
+ *     href="#dt">Date/Time Conversions</a>.
+ *
+ * <tr><td valign="top">{@code '%'}
+ *     <td valign="top"> percent
+ *     <td> The result is a literal {@code '%'} (<tt>'&#92;u0025'</tt>)
+ *
+ * <tr><td valign="top">{@code 'n'}
+ *     <td valign="top"> line separator
+ *     <td> The result is the platform-specific line separator
+ *
+ * </table>
+ *
+ * <p> Any characters not explicitly defined as conversions are illegal and are
+ * reserved for future extensions.
+ *
+ * <h4><a name="dt">Date/Time Conversions</a></h4>
+ *
+ * <p> The following date and time conversion suffix characters are defined for
+ * the {@code 't'} and {@code 'T'} conversions.  The types are similar to but
+ * not completely identical to those defined by GNU {@code date} and POSIX
+ * {@code strftime(3c)}.  Additional conversion types are provided to access
+ * Java-specific functionality (e.g. {@code 'L'} for milliseconds within the
+ * second).
+ *
+ * <p> The following conversion characters are used for formatting times:
+ *
+ * <table cellpadding=5 summary="time">
+ *
+ * <tr><td valign="top"> {@code 'H'}
+ *     <td> Hour of the day for the 24-hour clock, formatted as two digits with
+ *     a leading zero as necessary i.e. {@code 00 - 23}.
+ *
+ * <tr><td valign="top">{@code 'I'}
+ *     <td> Hour for the 12-hour clock, formatted as two digits with a leading
+ *     zero as necessary, i.e.  {@code 01 - 12}.
+ *
+ * <tr><td valign="top">{@code 'k'}
+ *     <td> Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}.
+ *
+ * <tr><td valign="top">{@code 'l'}
+ *     <td> Hour for the 12-hour clock, i.e. {@code 1 - 12}.
+ *
+ * <tr><td valign="top">{@code 'M'}
+ *     <td> Minute within the hour formatted as two digits with a leading zero
+ *     as necessary, i.e.  {@code 00 - 59}.
+ *
+ * <tr><td valign="top">{@code 'S'}
+ *     <td> Seconds within the minute, formatted as two digits with a leading
+ *     zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special
+ *     value required to support leap seconds).
+ *
+ * <tr><td valign="top">{@code 'L'}
+ *     <td> Millisecond within the second formatted as three digits with
+ *     leading zeros as necessary, i.e. {@code 000 - 999}.
+ *
+ * <tr><td valign="top">{@code 'N'}
+ *     <td> Nanosecond within the second, formatted as nine digits with leading
+ *     zeros as necessary, i.e. {@code 000000000 - 999999999}.
+ *
+ * <tr><td valign="top">{@code 'p'}
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker
+ *     in lower case, e.g."{@code am}" or "{@code pm}". Use of the conversion
+ *     prefix {@code 'T'} forces this output to upper case.
+ *
+ * <tr><td valign="top">{@code 'z'}
+ *     <td> <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC&nbsp;822</a>
+ *     style numeric time zone offset from GMT, e.g. {@code -0800}.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.
+ *
+ * <tr><td valign="top">{@code 'Z'}
+ *     <td> A string representing the abbreviation for the time zone.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the  time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.  The Formatter's locale will
+ *     supersede the locale of the argument (if any).
+ *
+ * <tr><td valign="top">{@code 's'}
+ *     <td> Seconds since the beginning of the epoch starting at 1 January 1970
+ *     {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to
+ *     {@code Long.MAX_VALUE/1000}.
+ *
+ * <tr><td valign="top">{@code 'Q'}
+ *     <td> Milliseconds since the beginning of the epoch starting at 1 January
+ *     1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to
+ *     {@code Long.MAX_VALUE}.
+ *
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting dates:
+ *
+ * <table cellpadding=5 summary="date">
+ *
+ * <tr><td valign="top">{@code 'B'}
+ *     <td> Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths
+ *     full month name}, e.g. {@code "January"}, {@code "February"}.
+ *
+ * <tr><td valign="top">{@code 'b'}
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getShortMonths abbreviated month name},
+ *     e.g. {@code "Jan"}, {@code "Feb"}.
+ *
+ * <tr><td valign="top">{@code 'h'}
+ *     <td> Same as {@code 'b'}.
+ *
+ * <tr><td valign="top">{@code 'A'}
+ *     <td> Locale-specific full name of the {@linkplain
+ *     java.text.DateFormatSymbols#getWeekdays day of the week},
+ *     e.g. {@code "Sunday"}, {@code "Monday"}
+ *
+ * <tr><td valign="top">{@code 'a'}
+ *     <td> Locale-specific short name of the {@linkplain
+ *     java.text.DateFormatSymbols#getShortWeekdays day of the week},
+ *     e.g. {@code "Sun"}, {@code "Mon"}
+ *
+ * <tr><td valign="top">{@code 'C'}
+ *     <td> Four-digit year divided by {@code 100}, formatted as two digits
+ *     with leading zero as necessary, i.e. {@code 00 - 99}
+ *
+ * <tr><td valign="top">{@code 'Y'}
+ *     <td> Year, formatted as at least four digits with leading zeros as
+ *     necessary, e.g. {@code 0092} equals {@code 92} CE for the Gregorian
+ *     calendar.
+ *
+ * <tr><td valign="top">{@code 'y'}
+ *     <td> Last two digits of the year, formatted with leading zeros as
+ *     necessary, i.e. {@code 00 - 99}.
+ *
+ * <tr><td valign="top">{@code 'j'}
+ *     <td> Day of year, formatted as three digits with leading zeros as
+ *     necessary, e.g. {@code 001 - 366} for the Gregorian calendar.
+ *
+ * <tr><td valign="top">{@code 'm'}
+ *     <td> Month, formatted as two digits with leading zeros as necessary,
+ *     i.e. {@code 01 - 13}.
+ *
+ * <tr><td valign="top">{@code 'd'}
+ *     <td> Day of month, formatted as two digits with leading zeros as
+ *     necessary, i.e. {@code 01 - 31}
+ *
+ * <tr><td valign="top">{@code 'e'}
+ *     <td> Day of month, formatted as two digits, i.e. {@code 1 - 31}.
+ *
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting common
+ * date/time compositions.
+ *
+ * <table cellpadding=5 summary="composites">
+ *
+ * <tr><td valign="top">{@code 'R'}
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM"}
+ *
+ * <tr><td valign="top">{@code 'T'}
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}.
+ *
+ * <tr><td valign="top">{@code 'r'}
+ *     <td> Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS %Tp"}.
+ *     The location of the morning or afternoon marker ({@code '%Tp'}) may be
+ *     locale-dependent.
+ *
+ * <tr><td valign="top">{@code 'D'}
+ *     <td> Date formatted as {@code "%tm/%td/%ty"}.
+ *
+ * <tr><td valign="top">{@code 'F'}
+ *     <td> <a href="http://www.w3.org/TR/NOTE-datetime">ISO&nbsp;8601</a>
+ *     complete date formatted as {@code "%tY-%tm-%td"}.
+ *
+ * <tr><td valign="top">{@code 'c'}
+ *     <td> Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"},
+ *     e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}.
+ *
+ * </table>
+ *
+ * <p> Any characters not explicitly defined as date/time conversion suffixes
+ * are illegal and are reserved for future extensions.
+ *
+ * <h4> Flags </h4>
+ *
+ * <p> The following table summarizes the supported flags.  <i>y</i> means the
+ * flag is supported for the indicated argument types.
+ *
+ * <table cellpadding=5 summary="genConv">
+ *
+ * <tr><th valign="bottom"> Flag <th valign="bottom"> General
+ *     <th valign="bottom"> Character <th valign="bottom"> Integral
+ *     <th valign="bottom"> Floating Point
+ *     <th valign="bottom"> Date/Time
+ *     <th valign="bottom"> Description
+ *
+ * <tr><td> '-' <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> y
+ *     <td> The result will be left-justified.
+ *
+ * <tr><td> '#' <td align="center" valign="top"> y<sup>1</sup>
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y<sup>3</sup>
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> -
+ *     <td> The result should use a conversion-dependent alternate form
+ *
+ * <tr><td> '+' <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y<sup>4</sup>
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> -
+ *     <td> The result will always include a sign
+ *
+ * <tr><td> '&nbsp;&nbsp;' <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y<sup>4</sup>
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> -
+ *     <td> The result will include a leading space for positive values
+ *
+ * <tr><td> '0' <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> -
+ *     <td> The result will be zero-padded
+ *
+ * <tr><td> ',' <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y<sup>2</sup>
+ *     <td align="center" valign="top"> y<sup>5</sup>
+ *     <td align="center" valign="top"> -
+ *     <td> The result will include locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getGroupingSeparator grouping separators}
+ *
+ * <tr><td> '(' <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y<sup>4</sup>
+ *     <td align="center" valign="top"> y<sup>5</sup>
+ *     <td align="center"> -
+ *     <td> The result will enclose negative numbers in parentheses
+ *
+ * </table>
+ *
+ * <p> <sup>1</sup> Depends on the definition of {@link Formattable}.
+ *
+ * <p> <sup>2</sup> For {@code 'd'} conversion only.
+ *
+ * <p> <sup>3</sup> For {@code 'o'}, {@code 'x'}, and {@code 'X'}
+ * conversions only.
+ *
+ * <p> <sup>4</sup> For {@code 'd'}, {@code 'o'}, {@code 'x'}, and
+ * {@code 'X'} conversions applied to {@link java.math.BigInteger BigInteger}
+ * or {@code 'd'} applied to {@code byte}, {@link Byte}, {@code short}, {@link
+ * Short}, {@code int} and {@link Integer}, {@code long}, and {@link Long}.
+ *
+ * <p> <sup>5</sup> For {@code 'e'}, {@code 'E'}, {@code 'f'},
+ * {@code 'g'}, and {@code 'G'} conversions only.
+ *
+ * <p> Any characters not explicitly defined as flags are illegal and are
+ * reserved for future extensions.
+ *
+ * <h4> Width </h4>
+ *
+ * <p> The width is the minimum number of characters to be written to the
+ * output.  For the line separator conversion, width is not applicable; if it
+ * is provided, an exception will be thrown.
+ *
+ * <h4> Precision </h4>
+ *
+ * <p> For general argument types, the precision is the maximum number of
+ * characters to be written to the output.
+ *
+ * <p> For the floating-point conversions {@code 'a'}, {@code 'A'}, {@code 'e'},
+ * {@code 'E'}, and {@code 'f'} the precision is the number of digits after the
+ * radix point.  If the conversion is {@code 'g'} or {@code 'G'}, then the
+ * precision is the total number of digits in the resulting magnitude after
+ * rounding.
+ *
+ * <p> For character, integral, and date/time argument types and the percent
+ * and line separator conversions, the precision is not applicable; if a
+ * precision is provided, an exception will be thrown.
+ *
+ * <h4> Argument Index </h4>
+ *
+ * <p> The argument index is a decimal integer indicating the position of the
+ * argument in the argument list.  The first argument is referenced by
+ * "{@code 1$}", the second by "{@code 2$}", etc.
+ *
+ * <p> Another way to reference arguments by position is to use the
+ * {@code '<'} (<tt>'&#92;u003c'</tt>) flag, which causes the argument for
+ * the previous format specifier to be re-used.  For example, the following two
+ * statements would produce identical strings:
+ *
+ * <blockquote><pre>
+ *   Calendar c = ...;
+ *   String s1 = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
+ *
+ *   String s2 = String.format("Duke's Birthday: %1$tm %&lt;te,%&lt;tY", c);
+ * </pre></blockquote>
+ *
+ * <hr>
+ * <h3><a name="detail">Details</a></h3>
+ *
+ * <p> This section is intended to provide behavioral details for formatting,
+ * including conditions and exceptions, supported data types, localization, and
+ * interactions between flags, conversions, and data types.  For an overview of
+ * formatting concepts, refer to the <a href="#summary">Summary</a>
+ *
+ * <p> Any characters not explicitly defined as conversions, date/time
+ * conversion suffixes, or flags are illegal and are reserved for
+ * future extensions.  Use of such a character in a format string will
+ * cause an {@link UnknownFormatConversionException} or {@link
+ * UnknownFormatFlagsException} to be thrown.
+ *
+ * <p> If the format specifier contains a width or precision with an invalid
+ * value or which is otherwise unsupported, then a {@link
+ * IllegalFormatWidthException} or {@link IllegalFormatPrecisionException}
+ * respectively will be thrown.
+ *
+ * <p> If a format specifier contains a conversion character that is not
+ * applicable to the corresponding argument, then an {@link
+ * IllegalFormatConversionException} will be thrown.
+ *
+ * <p> All specified exceptions may be thrown by any of the {@code format}
+ * methods of {@code Formatter} as well as by any {@code format} convenience
+ * methods such as {@link String#format(String,Object...) String.format} and
+ * {@link java.io.PrintStream#printf(String,Object...) PrintStream.printf}.
+ *
+ * <p> Conversions denoted by an upper-case character (i.e. {@code 'B'},
+ * {@code 'H'}, {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'},
+ * {@code 'G'}, {@code 'A'}, and {@code 'T'}) are the same as those for the
+ * corresponding lower-case conversion characters except that the result is
+ * converted to upper case according to the rules of the prevailing {@link
+ * java.util.Locale Locale}.  The result is equivalent to the following
+ * invocation of {@link String#toUpperCase()}
+ *
+ * <pre>
+ *    out.toUpperCase() </pre>
+ *
+ * <h4><a name="dgen">General</a></h4>
+ *
+ * <p> The following general conversions may be applied to any argument type:
+ *
+ * <table cellpadding=5 summary="dgConv">
+ *
+ * <tr><td valign="top"> {@code 'b'}
+ *     <td valign="top"> <tt>'&#92;u0062'</tt>
+ *     <td> Produces either "{@code true}" or "{@code false}" as returned by
+ *     {@link Boolean#toString(boolean)}.
+ *
+ *     <p> If the argument is {@code null}, then the result is
+ *     "{@code false}".  If the argument is a {@code boolean} or {@link
+ *     Boolean}, then the result is the string returned by {@link
+ *     String#valueOf(boolean) String.valueOf()}.  Otherwise, the result is
+ *     "{@code true}".
+ *
+ *     <p> If the {@code '#'} flag is given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'B'}
+ *     <td valign="top"> <tt>'&#92;u0042'</tt>
+ *     <td> The upper-case variant of {@code 'b'}.
+ *
+ * <tr><td valign="top"> {@code 'h'}
+ *     <td valign="top"> <tt>'&#92;u0068'</tt>
+ *     <td> Produces a string representing the hash code value of the object.
+ *
+ *     <p> If the argument, <i>arg</i> is {@code null}, then the
+ *     result is "{@code null}".  Otherwise, the result is obtained
+ *     by invoking {@code Integer.toHexString(arg.hashCode())}.
+ *
+ *     <p> If the {@code '#'} flag is given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'H'}
+ *     <td valign="top"> <tt>'&#92;u0048'</tt>
+ *     <td> The upper-case variant of {@code 'h'}.
+ *
+ * <tr><td valign="top"> {@code 's'}
+ *     <td valign="top"> <tt>'&#92;u0073'</tt>
+ *     <td> Produces a string.
+ *
+ *     <p> If the argument is {@code null}, then the result is
+ *     "{@code null}".  If the argument implements {@link Formattable}, then
+ *     its {@link Formattable#formatTo formatTo} method is invoked.
+ *     Otherwise, the result is obtained by invoking the argument's
+ *     {@code toString()} method.
+ *
+ *     <p> If the {@code '#'} flag is given and the argument is not a {@link
+ *     Formattable} , then a {@link FormatFlagsConversionMismatchException}
+ *     will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'S'}
+ *     <td valign="top"> <tt>'&#92;u0053'</tt>
+ *     <td> The upper-case variant of {@code 's'}.
+ *
+ * </table>
+ *
+ * <p> The following <a name="dFlags">flags</a> apply to general conversions:
+ *
+ * <table cellpadding=5 summary="dFlags">
+ *
+ * <tr><td valign="top"> {@code '-'}
+ *     <td valign="top"> <tt>'&#92;u002d'</tt>
+ *     <td> Left justifies the output.  Spaces (<tt>'&#92;u0020'</tt>) will be
+ *     added at the end of the converted value as required to fill the minimum
+ *     width of the field.  If the width is not provided, then a {@link
+ *     MissingFormatWidthException} will be thrown.  If this flag is not given
+ *     then the output will be right-justified.
+ *
+ * <tr><td valign="top"> {@code '#'}
+ *     <td valign="top"> <tt>'&#92;u0023'</tt>
+ *     <td> Requires the output use an alternate form.  The definition of the
+ *     form is specified by the conversion.
+ *
+ * </table>
+ *
+ * <p> The <a name="genWidth">width</a> is the minimum number of characters to
+ * be written to the
+ * output.  If the length of the converted value is less than the width then
+ * the output will be padded by <tt>'&nbsp;&nbsp;'</tt> (<tt>'&#92;u0020'</tt>)
+ * until the total number of characters equals the width.  The padding is on
+ * the left by default.  If the {@code '-'} flag is given, then the padding
+ * will be on the right.  If the width is not specified then there is no
+ * minimum.
+ *
+ * <p> The precision is the maximum number of characters to be written to the
+ * output.  The precision is applied before the width, thus the output will be
+ * truncated to {@code precision} characters even if the width is greater than
+ * the precision.  If the precision is not specified then there is no explicit
+ * limit on the number of characters.
+ *
+ * <h4><a name="dchar">Character</a></h4>
+ *
+ * This conversion may be applied to {@code char} and {@link Character}.  It
+ * may also be applied to the types {@code byte}, {@link Byte},
+ * {@code short}, and {@link Short}, {@code int} and {@link Integer} when
+ * {@link Character#isValidCodePoint} returns {@code true}.  If it returns
+ * {@code false} then an {@link IllegalFormatCodePointException} will be
+ * thrown.
+ *
+ * <table cellpadding=5 summary="charConv">
+ *
+ * <tr><td valign="top"> {@code 'c'}
+ *     <td valign="top"> <tt>'&#92;u0063'</tt>
+ *     <td> Formats the argument as a Unicode character as described in <a
+ *     href="../lang/Character.html#unicode">Unicode Character
+ *     Representation</a>.  This may be more than one 16-bit {@code char} in
+ *     the case where the argument represents a supplementary character.
+ *
+ *     <p> If the {@code '#'} flag is given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'C'}
+ *     <td valign="top"> <tt>'&#92;u0043'</tt>
+ *     <td> The upper-case variant of {@code 'c'}.
+ *
+ * </table>
+ *
+ * <p> The {@code '-'} flag defined for <a href="#dFlags">General
+ * conversions</a> applies.  If the {@code '#'} flag is given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <p> The width is defined as for <a href="#genWidth">General conversions</a>.
+ *
+ * <p> The precision is not applicable.  If the precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <h4><a name="dnum">Numeric</a></h4>
+ *
+ * <p> Numeric conversions are divided into the following categories:
+ *
+ * <ol>
+ *
+ * <li> <a href="#dnint"><b>Byte, Short, Integer, and Long</b></a>
+ *
+ * <li> <a href="#dnbint"><b>BigInteger</b></a>
+ *
+ * <li> <a href="#dndec"><b>Float and Double</b></a>
+ *
+ * <li> <a href="#dnbdec"><b>BigDecimal</b></a>
+ *
+ * </ol>
+ *
+ * <p> Numeric types will be formatted according to the following algorithm:
+ *
+ * <p><b><a name="L10nAlgorithm"> Number Localization Algorithm</a></b>
+ *
+ * <p> After digits are obtained for the integer part, fractional part, and
+ * exponent (as appropriate for the data type), the following transformation
+ * is applied:
+ *
+ * <ol>
+ *
+ * <li> Each digit character <i>d</i> in the string is replaced by a
+ * locale-specific digit computed relative to the current locale's
+ * {@linkplain java.text.DecimalFormatSymbols#getZeroDigit() zero digit}
+ * <i>z</i>; that is <i>d&nbsp;-&nbsp;</i> {@code '0'}
+ * <i>&nbsp;+&nbsp;z</i>.
+ *
+ * <li> If a decimal separator is present, a locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getDecimalSeparator decimal separator} is
+ * substituted.
+ *
+ * <li> If the {@code ','} (<tt>'&#92;u002c'</tt>)
+ * <a name="L10nGroup">flag</a> is given, then the locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separator} is
+ * inserted by scanning the integer part of the string from least significant
+ * to most significant digits and inserting a separator at intervals defined by
+ * the locale's {@linkplain java.text.DecimalFormat#getGroupingSize() grouping
+ * size}.
+ *
+ * <li> If the {@code '0'} flag is given, then the locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getZeroDigit() zero digits} are inserted
+ * after the sign character, if any, and before the first non-zero digit, until
+ * the length of the string is equal to the requested field width.
+ *
+ * <li> If the value is negative and the {@code '('} flag is given, then a
+ * {@code '('} (<tt>'&#92;u0028'</tt>) is prepended and a {@code ')'}
+ * (<tt>'&#92;u0029'</tt>) is appended.
+ *
+ * <li> If the value is negative (or floating-point negative zero) and
+ * {@code '('} flag is not given, then a {@code '-'} (<tt>'&#92;u002d'</tt>)
+ * is prepended.
+ *
+ * <li> If the {@code '+'} flag is given and the value is positive or zero (or
+ * floating-point positive zero), then a {@code '+'} (<tt>'&#92;u002b'</tt>)
+ * will be prepended.
+ *
+ * </ol>
+ *
+ * <p> If the value is NaN or positive infinity the literal strings "NaN" or
+ * "Infinity" respectively, will be output.  If the value is negative infinity,
+ * then the output will be "(Infinity)" if the {@code '('} flag is given
+ * otherwise the output will be "-Infinity".  These values are not localized.
+ *
+ * <p><a name="dnint"><b> Byte, Short, Integer, and Long </b></a>
+ *
+ * <p> The following conversions may be applied to {@code byte}, {@link Byte},
+ * {@code short}, {@link Short}, {@code int} and {@link Integer},
+ * {@code long}, and {@link Long}.
+ *
+ * <table cellpadding=5 summary="IntConv">
+ *
+ * <tr><td valign="top"> {@code 'd'}
+ *     <td valign="top"> <tt>'&#92;u0064'</tt>
+ *     <td> Formats the argument as a decimal integer. The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> If the {@code '0'} flag is given and the value is negative, then
+ *     the zero padding will occur after the sign.
+ *
+ *     <p> If the {@code '#'} flag is given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'o'}
+ *     <td valign="top"> <tt>'&#92;u006f'</tt>
+ *     <td> Formats the argument as an integer in base eight.  No localization
+ *     is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be an unsigned value
+ *     generated by adding 2<sup>n</sup> to the value where {@code n} is the
+ *     number of bits in the type as returned by the static {@code SIZE} field
+ *     in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short},
+ *     {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long}
+ *     classes as appropriate.
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with the radix indicator {@code '0'}.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded
+ *     with leading zeros to the field width following any indication of sign.
+ *
+ *     <p> If {@code '('}, {@code '+'}, '&nbsp;&nbsp;', or {@code ','} flags
+ *     are given then a {@link FormatFlagsConversionMismatchException} will be
+ *     thrown.
+ *
+ * <tr><td valign="top"> {@code 'x'}
+ *     <td valign="top"> <tt>'&#92;u0078'</tt>
+ *     <td> Formats the argument as an integer in base sixteen. No
+ *     localization is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be an unsigned value
+ *     generated by adding 2<sup>n</sup> to the value where {@code n} is the
+ *     number of bits in the type as returned by the static {@code SIZE} field
+ *     in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short},
+ *     {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long}
+ *     classes as appropriate.
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with the radix indicator {@code "0x"}.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded to
+ *     the field width with leading zeros after the radix indicator or sign (if
+ *     present).
+ *
+ *     <p> If {@code '('}, <tt>'&nbsp;&nbsp;'</tt>, {@code '+'}, or
+ *     {@code ','} flags are given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'X'}
+ *     <td valign="top"> <tt>'&#92;u0058'</tt>
+ *     <td> The upper-case variant of {@code 'x'}.  The entire string
+ *     representing the number will be converted to {@linkplain
+ *     String#toUpperCase upper case} including the {@code 'x'} (if any) and
+ *     all hexadecimal digits {@code 'a'} - {@code 'f'}
+ *     (<tt>'&#92;u0061'</tt> -  <tt>'&#92;u0066'</tt>).
+ *
+ * </table>
+ *
+ * <p> If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and
+ * both the {@code '#'} and the {@code '0'} flags are given, then result will
+ * contain the radix indicator ({@code '0'} for octal and {@code "0x"} or
+ * {@code "0X"} for hexadecimal), some number of zeros (based on the width),
+ * and the value.
+ *
+ * <p> If the {@code '-'} flag is not given, then the space padding will occur
+ * before the sign.
+ *
+ * <p> The following <a name="intFlags">flags</a> apply to numeric integral
+ * conversions:
+ *
+ * <table cellpadding=5 summary="intFlags">
+ *
+ * <tr><td valign="top"> {@code '+'}
+ *     <td valign="top"> <tt>'&#92;u002b'</tt>
+ *     <td> Requires the output to include a positive sign for all positive
+ *     numbers.  If this flag is not given then only negative values will
+ *     include a sign.
+ *
+ *     <p> If both the {@code '+'} and <tt>'&nbsp;&nbsp;'</tt> flags are given
+ *     then an {@link IllegalFormatFlagsException} will be thrown.
+ *
+ * <tr><td valign="top"> <tt>'&nbsp;&nbsp;'</tt>
+ *     <td valign="top"> <tt>'&#92;u0020'</tt>
+ *     <td> Requires the output to include a single extra space
+ *     (<tt>'&#92;u0020'</tt>) for non-negative values.
+ *
+ *     <p> If both the {@code '+'} and <tt>'&nbsp;&nbsp;'</tt> flags are given
+ *     then an {@link IllegalFormatFlagsException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code '0'}
+ *     <td valign="top"> <tt>'&#92;u0030'</tt>
+ *     <td> Requires the output to be padded with leading {@linkplain
+ *     java.text.DecimalFormatSymbols#getZeroDigit zeros} to the minimum field
+ *     width following any sign or radix indicator except when converting NaN
+ *     or infinity.  If the width is not provided, then a {@link
+ *     MissingFormatWidthException} will be thrown.
+ *
+ *     <p> If both the {@code '-'} and {@code '0'} flags are given then an
+ *     {@link IllegalFormatFlagsException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code ','}
+ *     <td valign="top"> <tt>'&#92;u002c'</tt>
+ *     <td> Requires the output to include the locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getGroupingSeparator group separators} as
+ *     described in the <a href="#L10nGroup">"group" section</a> of the
+ *     localization algorithm.
+ *
+ * <tr><td valign="top"> {@code '('}
+ *     <td valign="top"> <tt>'&#92;u0028'</tt>
+ *     <td> Requires the output to prepend a {@code '('}
+ *     (<tt>'&#92;u0028'</tt>) and append a {@code ')'}
+ *     (<tt>'&#92;u0029'</tt>) to negative values.
+ *
+ * </table>
+ *
+ * <p> If no <a name="intdFlags">flags</a> are given the default formatting is
+ * as follows:
+ *
+ * <ul>
+ *
+ * <li> The output is right-justified within the {@code width}
+ *
+ * <li> Negative numbers begin with a {@code '-'} (<tt>'&#92;u002d'</tt>)
+ *
+ * <li> Positive numbers and zero do not include a sign or extra leading
+ * space
+ *
+ * <li> No grouping separators are included
+ *
+ * </ul>
+ *
+ * <p> The <a name="intWidth">width</a> is the minimum number of characters to
+ * be written to the output.  This includes any signs, digits, grouping
+ * separators, radix indicator, and parentheses.  If the length of the
+ * converted value is less than the width then the output will be padded by
+ * spaces (<tt>'&#92;u0020'</tt>) until the total number of characters equals
+ * width.  The padding is on the left by default.  If {@code '-'} flag is
+ * given then the padding will be on the right.  If width is not specified then
+ * there is no minimum.
+ *
+ * <p> The precision is not applicable.  If precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <p><a name="dnbint"><b> BigInteger </b></a>
+ *
+ * <p> The following conversions may be applied to {@link
+ * java.math.BigInteger}.
+ *
+ * <table cellpadding=5 summary="BIntConv">
+ *
+ * <tr><td valign="top"> {@code 'd'}
+ *     <td valign="top"> <tt>'&#92;u0064'</tt>
+ *     <td> Requires the output to be formatted as a decimal integer. The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> If the {@code '#'} flag is given {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'o'}
+ *     <td valign="top"> <tt>'&#92;u006f'</tt>
+ *     <td> Requires the output to be formatted as an integer in base eight.
+ *     No localization is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be a signed value
+ *     beginning with {@code '-'} (<tt>'&#92;u002d'</tt>).  Signed output is
+ *     allowed for this type because unlike the primitive types it is not
+ *     possible to create an unsigned equivalent without assuming an explicit
+ *     data-type size.
+ *
+ *     <p> If <i>x</i> is positive or zero and the {@code '+'} flag is given
+ *     then the result will begin with {@code '+'} (<tt>'&#92;u002b'</tt>).
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with {@code '0'} prefix.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded
+ *     with leading zeros to the field width following any indication of sign.
+ *
+ *     <p> If the {@code ','} flag is given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'x'}
+ *     <td valign="top"> <tt>'&#92;u0078'</tt>
+ *     <td> Requires the output to be formatted as an integer in base
+ *     sixteen.  No localization is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be a signed value
+ *     beginning with {@code '-'} (<tt>'&#92;u002d'</tt>).  Signed output is
+ *     allowed for this type because unlike the primitive types it is not
+ *     possible to create an unsigned equivalent without assuming an explicit
+ *     data-type size.
+ *
+ *     <p> If <i>x</i> is positive or zero and the {@code '+'} flag is given
+ *     then the result will begin with {@code '+'} (<tt>'&#92;u002b'</tt>).
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with the radix indicator {@code "0x"}.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded to
+ *     the field width with leading zeros after the radix indicator or sign (if
+ *     present).
+ *
+ *     <p> If the {@code ','} flag is given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'X'}
+ *     <td valign="top"> <tt>'&#92;u0058'</tt>
+ *     <td> The upper-case variant of {@code 'x'}.  The entire string
+ *     representing the number will be converted to {@linkplain
+ *     String#toUpperCase upper case} including the {@code 'x'} (if any) and
+ *     all hexadecimal digits {@code 'a'} - {@code 'f'}
+ *     (<tt>'&#92;u0061'</tt> - <tt>'&#92;u0066'</tt>).
+ *
+ * </table>
+ *
+ * <p> If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and
+ * both the {@code '#'} and the {@code '0'} flags are given, then result will
+ * contain the base indicator ({@code '0'} for octal and {@code "0x"} or
+ * {@code "0X"} for hexadecimal), some number of zeros (based on the width),
+ * and the value.
+ *
+ * <p> If the {@code '0'} flag is given and the value is negative, then the
+ * zero padding will occur after the sign.
+ *
+ * <p> If the {@code '-'} flag is not given, then the space padding will occur
+ * before the sign.
+ *
+ * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
+ * Long apply.  The <a href="#intdFlags">default behavior</a> when no flags are
+ * given is the same as for Byte, Short, Integer, and Long.
+ *
+ * <p> The specification of <a href="#intWidth">width</a> is the same as
+ * defined for Byte, Short, Integer, and Long.
+ *
+ * <p> The precision is not applicable.  If precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <p><a name="dndec"><b> Float and Double</b></a>
+ *
+ * <p> The following conversions may be applied to {@code float}, {@link
+ * Float}, {@code double} and {@link Double}.
+ *
+ * <table cellpadding=5 summary="floatConv">
+ *
+ * <tr><td valign="top"> {@code 'e'}
+ *     <td valign="top"> <tt>'&#92;u0065'</tt>
+ *     <td> Requires the output to be formatted using <a
+ *     name="scientific">computerized scientific notation</a>.  The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> The formatting of the magnitude <i>m</i> depends upon its value.
+ *
+ *     <p> If <i>m</i> is NaN or infinite, the literal strings "NaN" or
+ *     "Infinity", respectively, will be output.  These values are not
+ *     localized.
+ *
+ *     <p> If <i>m</i> is positive-zero or negative-zero, then the exponent
+ *     will be {@code "+00"}.
+ *
+ *     <p> Otherwise, the result is a string that represents the sign and
+ *     magnitude (absolute value) of the argument.  The formatting of the sign
+ *     is described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup>
+ *     &lt;= <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the
+ *     mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so
+ *     that 1 &lt;= <i>a</i> &lt; 10. The magnitude is then represented as the
+ *     integer part of <i>a</i>, as a single decimal digit, followed by the
+ *     decimal separator followed by decimal digits representing the fractional
+ *     part of <i>a</i>, followed by the lower-case locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getExponentSeparator exponent separator}
+ *     (e.g. {@code 'e'}), followed by the sign of the exponent, followed
+ *     by a representation of <i>n</i> as a decimal integer, as produced by the
+ *     method {@link Long#toString(long, int)}, and zero-padded to include at
+ *     least two digits.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision.  If the precision is not
+ *     specified then the default value is {@code 6}. If the precision is less
+ *     than the number of digits which would appear after the decimal point in
+ *     the string returned by {@link Float#toString(float)} or {@link
+ *     Double#toString(double)} respectively, then the value will be rounded
+ *     using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     Float#toString(float)} or {@link Double#toString(double)} as
+ *     appropriate.
+ *
+ *     <p>If the {@code ','} flag is given, then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'E'}
+ *     <td valign="top"> <tt>'&#92;u0045'</tt>
+ *     <td> The upper-case variant of {@code 'e'}.  The exponent symbol
+ *     will be the upper-case locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getExponentSeparator exponent separator}
+ *     (e.g. {@code 'E'}).
+ *
+ * <tr><td valign="top"> {@code 'g'}
+ *     <td valign="top"> <tt>'&#92;u0067'</tt>
+ *     <td> Requires the output to be formatted in general scientific notation
+ *     as described below. The <a href="#L10nAlgorithm">localization
+ *     algorithm</a> is applied.
+ *
+ *     <p> After rounding for the precision, the formatting of the resulting
+ *     magnitude <i>m</i> depends on its value.
+ *
+ *     <p> If <i>m</i> is greater than or equal to 10<sup>-4</sup> but less
+ *     than 10<sup>precision</sup> then it is represented in <i><a
+ *     href="#decimal">decimal format</a></i>.
+ *
+ *     <p> If <i>m</i> is less than 10<sup>-4</sup> or greater than or equal to
+ *     10<sup>precision</sup>, then it is represented in <i><a
+ *     href="#scientific">computerized scientific notation</a></i>.
+ *
+ *     <p> The total number of significant digits in <i>m</i> is equal to the
+ *     precision.  If the precision is not specified, then the default value is
+ *     {@code 6}.  If the precision is {@code 0}, then it is taken to be
+ *     {@code 1}.
+ *
+ *     <p> If the {@code '#'} flag is given then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'G'}
+ *     <td valign="top"> <tt>'&#92;u0047'</tt>
+ *     <td> The upper-case variant of {@code 'g'}.
+ *
+ * <tr><td valign="top"> {@code 'f'}
+ *     <td valign="top"> <tt>'&#92;u0066'</tt>
+ *     <td> Requires the output to be formatted using <a name="decimal">decimal
+ *     format</a>.  The <a href="#L10nAlgorithm">localization algorithm</a> is
+ *     applied.
+ *
+ *     <p> The result is a string that represents the sign and magnitude
+ *     (absolute value) of the argument.  The formatting of the sign is
+ *     described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> If <i>m</i> NaN or infinite, the literal strings "NaN" or
+ *     "Infinity", respectively, will be output.  These values are not
+ *     localized.
+ *
+ *     <p> The magnitude is formatted as the integer part of <i>m</i>, with no
+ *     leading zeroes, followed by the decimal separator followed by one or
+ *     more decimal digits representing the fractional part of <i>m</i>.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision.  If the precision is not
+ *     specified then the default value is {@code 6}. If the precision is less
+ *     than the number of digits which would appear after the decimal point in
+ *     the string returned by {@link Float#toString(float)} or {@link
+ *     Double#toString(double)} respectively, then the value will be rounded
+ *     using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     Float#toString(float)} or {@link Double#toString(double)} as
+ *     appropriate.
+ *
+ * <tr><td valign="top"> {@code 'a'}
+ *     <td valign="top"> <tt>'&#92;u0061'</tt>
+ *     <td> Requires the output to be formatted in hexadecimal exponential
+ *     form.  No localization is applied.
+ *
+ *     <p> The result is a string that represents the sign and magnitude
+ *     (absolute value) of the argument <i>x</i>.
+ *
+ *     <p> If <i>x</i> is negative or a negative-zero value then the result
+ *     will begin with {@code '-'} (<tt>'&#92;u002d'</tt>).
+ *
+ *     <p> If <i>x</i> is positive or a positive-zero value and the
+ *     {@code '+'} flag is given then the result will begin with {@code '+'}
+ *     (<tt>'&#92;u002b'</tt>).
+ *
+ *     <p> The formatting of the magnitude <i>m</i> depends upon its value.
+ *
+ *     <ul>
+ *
+ *     <li> If the value is NaN or infinite, the literal strings "NaN" or
+ *     "Infinity", respectively, will be output.
+ *
+ *     <li> If <i>m</i> is zero then it is represented by the string
+ *     {@code "0x0.0p0"}.
+ *
+ *     <li> If <i>m</i> is a {@code double} value with a normalized
+ *     representation then substrings are used to represent the significand and
+ *     exponent fields.  The significand is represented by the characters
+ *     {@code "0x1."} followed by the hexadecimal representation of the rest
+ *     of the significand as a fraction.  The exponent is represented by
+ *     {@code 'p'} (<tt>'&#92;u0070'</tt>) followed by a decimal string of the
+ *     unbiased exponent as if produced by invoking {@link
+ *     Integer#toString(int) Integer.toString} on the exponent value.  If the
+ *     precision is specified, the value is rounded to the given number of
+ *     hexadecimal digits.
+ *
+ *     <li> If <i>m</i> is a {@code double} value with a subnormal
+ *     representation then, unless the precision is specified to be in the range
+ *     1 through 12, inclusive, the significand is represented by the characters
+ *     {@code '0x0.'} followed by the hexadecimal representation of the rest of
+ *     the significand as a fraction, and the exponent represented by
+ *     {@code 'p-1022'}.  If the precision is in the interval
+ *     [1,&nbsp;12], the subnormal value is normalized such that it
+ *     begins with the characters {@code '0x1.'}, rounded to the number of
+ *     hexadecimal digits of precision, and the exponent adjusted
+ *     accordingly.  Note that there must be at least one nonzero digit in a
+ *     subnormal significand.
+ *
+ *     </ul>
+ *
+ *     <p> If the {@code '('} or {@code ','} flags are given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'A'}
+ *     <td valign="top"> <tt>'&#92;u0041'</tt>
+ *     <td> The upper-case variant of {@code 'a'}.  The entire string
+ *     representing the number will be converted to upper case including the
+ *     {@code 'x'} (<tt>'&#92;u0078'</tt>) and {@code 'p'}
+ *     (<tt>'&#92;u0070'</tt> and all hexadecimal digits {@code 'a'} -
+ *     {@code 'f'} (<tt>'&#92;u0061'</tt> - <tt>'&#92;u0066'</tt>).
+ *
+ * </table>
+ *
+ * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
+ * Long apply.
+ *
+ * <p> If the {@code '#'} flag is given, then the decimal separator will
+ * always be present.
+ *
+ * <p> If no <a name="floatdFlags">flags</a> are given the default formatting
+ * is as follows:
+ *
+ * <ul>
+ *
+ * <li> The output is right-justified within the {@code width}
+ *
+ * <li> Negative numbers begin with a {@code '-'}
+ *
+ * <li> Positive numbers and positive zero do not include a sign or extra
+ * leading space
+ *
+ * <li> No grouping separators are included
+ *
+ * <li> The decimal separator will only appear if a digit follows it
+ *
+ * </ul>
+ *
+ * <p> The <a name="floatDWidth">width</a> is the minimum number of characters
+ * to be written to the output.  This includes any signs, digits, grouping
+ * separators, decimal separators, exponential symbol, radix indicator,
+ * parentheses, and strings representing infinity and NaN as applicable.  If
+ * the length of the converted value is less than the width then the output
+ * will be padded by spaces (<tt>'&#92;u0020'</tt>) until the total number of
+ * characters equals width.  The padding is on the left by default.  If the
+ * {@code '-'} flag is given then the padding will be on the right.  If width
+ * is not specified then there is no minimum.
+ *
+ * <p> If the <a name="floatDPrec">conversion</a> is {@code 'e'},
+ * {@code 'E'} or {@code 'f'}, then the precision is the number of digits
+ * after the decimal separator.  If the precision is not specified, then it is
+ * assumed to be {@code 6}.
+ *
+ * <p> If the conversion is {@code 'g'} or {@code 'G'}, then the precision is
+ * the total number of significant digits in the resulting magnitude after
+ * rounding.  If the precision is not specified, then the default value is
+ * {@code 6}.  If the precision is {@code 0}, then it is taken to be
+ * {@code 1}.
+ *
+ * <p> If the conversion is {@code 'a'} or {@code 'A'}, then the precision
+ * is the number of hexadecimal digits after the radix point.  If the
+ * precision is not provided, then all of the digits as returned by {@link
+ * Double#toHexString(double)} will be output.
+ *
+ * <p><a name="dnbdec"><b> BigDecimal </b></a>
+ *
+ * <p> The following conversions may be applied {@link java.math.BigDecimal
+ * BigDecimal}.
+ *
+ * <table cellpadding=5 summary="floatConv">
+ *
+ * <tr><td valign="top"> {@code 'e'}
+ *     <td valign="top"> <tt>'&#92;u0065'</tt>
+ *     <td> Requires the output to be formatted using <a
+ *     name="bscientific">computerized scientific notation</a>.  The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> The formatting of the magnitude <i>m</i> depends upon its value.
+ *
+ *     <p> If <i>m</i> is positive-zero or negative-zero, then the exponent
+ *     will be {@code "+00"}.
+ *
+ *     <p> Otherwise, the result is a string that represents the sign and
+ *     magnitude (absolute value) of the argument.  The formatting of the sign
+ *     is described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup>
+ *     &lt;= <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the
+ *     mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so
+ *     that 1 &lt;= <i>a</i> &lt; 10. The magnitude is then represented as the
+ *     integer part of <i>a</i>, as a single decimal digit, followed by the
+ *     decimal separator followed by decimal digits representing the fractional
+ *     part of <i>a</i>, followed by the exponent symbol {@code 'e'}
+ *     (<tt>'&#92;u0065'</tt>), followed by the sign of the exponent, followed
+ *     by a representation of <i>n</i> as a decimal integer, as produced by the
+ *     method {@link Long#toString(long, int)}, and zero-padded to include at
+ *     least two digits.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision.  If the precision is not
+ *     specified then the default value is {@code 6}.  If the precision is
+ *     less than the number of digits to the right of the decimal point then
+ *     the value will be rounded using the
+ *     {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     BigDecimal#toString()}.
+ *
+ *     <p> If the {@code ','} flag is given, then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'E'}
+ *     <td valign="top"> <tt>'&#92;u0045'</tt>
+ *     <td> The upper-case variant of {@code 'e'}.  The exponent symbol
+ *     will be {@code 'E'} (<tt>'&#92;u0045'</tt>).
+ *
+ * <tr><td valign="top"> {@code 'g'}
+ *     <td valign="top"> <tt>'&#92;u0067'</tt>
+ *     <td> Requires the output to be formatted in general scientific notation
+ *     as described below. The <a href="#L10nAlgorithm">localization
+ *     algorithm</a> is applied.
+ *
+ *     <p> After rounding for the precision, the formatting of the resulting
+ *     magnitude <i>m</i> depends on its value.
+ *
+ *     <p> If <i>m</i> is greater than or equal to 10<sup>-4</sup> but less
+ *     than 10<sup>precision</sup> then it is represented in <i><a
+ *     href="#bdecimal">decimal format</a></i>.
+ *
+ *     <p> If <i>m</i> is less than 10<sup>-4</sup> or greater than or equal to
+ *     10<sup>precision</sup>, then it is represented in <i><a
+ *     href="#bscientific">computerized scientific notation</a></i>.
+ *
+ *     <p> The total number of significant digits in <i>m</i> is equal to the
+ *     precision.  If the precision is not specified, then the default value is
+ *     {@code 6}.  If the precision is {@code 0}, then it is taken to be
+ *     {@code 1}.
+ *
+ *     <p> If the {@code '#'} flag is given then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'G'}
+ *     <td valign="top"> <tt>'&#92;u0047'</tt>
+ *     <td> The upper-case variant of {@code 'g'}.
+ *
+ * <tr><td valign="top"> {@code 'f'}
+ *     <td valign="top"> <tt>'&#92;u0066'</tt>
+ *     <td> Requires the output to be formatted using <a name="bdecimal">decimal
+ *     format</a>.  The <a href="#L10nAlgorithm">localization algorithm</a> is
+ *     applied.
+ *
+ *     <p> The result is a string that represents the sign and magnitude
+ *     (absolute value) of the argument.  The formatting of the sign is
+ *     described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> The magnitude is formatted as the integer part of <i>m</i>, with no
+ *     leading zeroes, followed by the decimal separator followed by one or
+ *     more decimal digits representing the fractional part of <i>m</i>.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision. If the precision is not
+ *     specified then the default value is {@code 6}.  If the precision is
+ *     less than the number of digits to the right of the decimal point
+ *     then the value will be rounded using the
+ *     {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     BigDecimal#toString()}.
+ *
+ * </table>
+ *
+ * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
+ * Long apply.
+ *
+ * <p> If the {@code '#'} flag is given, then the decimal separator will
+ * always be present.
+ *
+ * <p> The <a href="#floatdFlags">default behavior</a> when no flags are
+ * given is the same as for Float and Double.
+ *
+ * <p> The specification of <a href="#floatDWidth">width</a> and <a
+ * href="#floatDPrec">precision</a> is the same as defined for Float and
+ * Double.
+ *
+ * <h4><a name="ddt">Date/Time</a></h4>
+ *
+ * <p> This conversion may be applied to {@code long}, {@link Long}, {@link
+ * Calendar}, {@link Date} and {@link TemporalAccessor TemporalAccessor}
+ *
+ * <table cellpadding=5 summary="DTConv">
+ *
+ * <tr><td valign="top"> {@code 't'}
+ *     <td valign="top"> <tt>'&#92;u0074'</tt>
+ *     <td> Prefix for date and time conversion characters.
+ * <tr><td valign="top"> {@code 'T'}
+ *     <td valign="top"> <tt>'&#92;u0054'</tt>
+ *     <td> The upper-case variant of {@code 't'}.
+ *
+ * </table>
+ *
+ * <p> The following date and time conversion character suffixes are defined
+ * for the {@code 't'} and {@code 'T'} conversions.  The types are similar to
+ * but not completely identical to those defined by GNU {@code date} and
+ * POSIX {@code strftime(3c)}.  Additional conversion types are provided to
+ * access Java-specific functionality (e.g. {@code 'L'} for milliseconds
+ * within the second).
+ *
+ * <p> The following conversion characters are used for formatting times:
+ *
+ * <table cellpadding=5 summary="time">
+ *
+ * <tr><td valign="top"> {@code 'H'}
+ *     <td valign="top"> <tt>'&#92;u0048'</tt>
+ *     <td> Hour of the day for the 24-hour clock, formatted as two digits with
+ *     a leading zero as necessary i.e. {@code 00 - 23}. {@code 00}
+ *     corresponds to midnight.
+ *
+ * <tr><td valign="top">{@code 'I'}
+ *     <td valign="top"> <tt>'&#92;u0049'</tt>
+ *     <td> Hour for the 12-hour clock, formatted as two digits with a leading
+ *     zero as necessary, i.e.  {@code 01 - 12}.  {@code 01} corresponds to
+ *     one o'clock (either morning or afternoon).
+ *
+ * <tr><td valign="top">{@code 'k'}
+ *     <td valign="top"> <tt>'&#92;u006b'</tt>
+ *     <td> Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}.
+ *     {@code 0} corresponds to midnight.
+ *
+ * <tr><td valign="top">{@code 'l'}
+ *     <td valign="top"> <tt>'&#92;u006c'</tt>
+ *     <td> Hour for the 12-hour clock, i.e. {@code 1 - 12}.  {@code 1}
+ *     corresponds to one o'clock (either morning or afternoon).
+ *
+ * <tr><td valign="top">{@code 'M'}
+ *     <td valign="top"> <tt>'&#92;u004d'</tt>
+ *     <td> Minute within the hour formatted as two digits with a leading zero
+ *     as necessary, i.e.  {@code 00 - 59}.
+ *
+ * <tr><td valign="top">{@code 'S'}
+ *     <td valign="top"> <tt>'&#92;u0053'</tt>
+ *     <td> Seconds within the minute, formatted as two digits with a leading
+ *     zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special
+ *     value required to support leap seconds).
+ *
+ * <tr><td valign="top">{@code 'L'}
+ *     <td valign="top"> <tt>'&#92;u004c'</tt>
+ *     <td> Millisecond within the second formatted as three digits with
+ *     leading zeros as necessary, i.e. {@code 000 - 999}.
+ *
+ * <tr><td valign="top">{@code 'N'}
+ *     <td valign="top"> <tt>'&#92;u004e'</tt>
+ *     <td> Nanosecond within the second, formatted as nine digits with leading
+ *     zeros as necessary, i.e. {@code 000000000 - 999999999}.  The precision
+ *     of this value is limited by the resolution of the underlying operating
+ *     system or hardware.
+ *
+ * <tr><td valign="top">{@code 'p'}
+ *     <td valign="top"> <tt>'&#92;u0070'</tt>
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker
+ *     in lower case, e.g."{@code am}" or "{@code pm}".  Use of the
+ *     conversion prefix {@code 'T'} forces this output to upper case.  (Note
+ *     that {@code 'p'} produces lower-case output.  This is different from
+ *     GNU {@code date} and POSIX {@code strftime(3c)} which produce
+ *     upper-case output.)
+ *
+ * <tr><td valign="top">{@code 'z'}
+ *     <td valign="top"> <tt>'&#92;u007a'</tt>
+ *     <td> <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC&nbsp;822</a>
+ *     style numeric time zone offset from GMT, e.g. {@code -0800}.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.
+ *
+ * <tr><td valign="top">{@code 'Z'}
+ *     <td valign="top"> <tt>'&#92;u005a'</tt>
+ *     <td> A string representing the abbreviation for the time zone.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.  The Formatter's locale will
+ *     supersede the locale of the argument (if any).
+ *
+ * <tr><td valign="top">{@code 's'}
+ *     <td valign="top"> <tt>'&#92;u0073'</tt>
+ *     <td> Seconds since the beginning of the epoch starting at 1 January 1970
+ *     {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to
+ *     {@code Long.MAX_VALUE/1000}.
+ *
+ * <tr><td valign="top">{@code 'Q'}
+ *     <td valign="top"> <tt>'&#92;u004f'</tt>
+ *     <td> Milliseconds since the beginning of the epoch starting at 1 January
+ *     1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to
+ *     {@code Long.MAX_VALUE}. The precision of this value is limited by
+ *     the resolution of the underlying operating system or hardware.
+ *
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting dates:
+ *
+ * <table cellpadding=5 summary="date">
+ *
+ * <tr><td valign="top">{@code 'B'}
+ *     <td valign="top"> <tt>'&#92;u0042'</tt>
+ *     <td> Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths
+ *     full month name}, e.g. {@code "January"}, {@code "February"}.
+ *
+ * <tr><td valign="top">{@code 'b'}
+ *     <td valign="top"> <tt>'&#92;u0062'</tt>
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getShortMonths abbreviated month name},
+ *     e.g. {@code "Jan"}, {@code "Feb"}.
+ *
+ * <tr><td valign="top">{@code 'h'}
+ *     <td valign="top"> <tt>'&#92;u0068'</tt>
+ *     <td> Same as {@code 'b'}.
+ *
+ * <tr><td valign="top">{@code 'A'}
+ *     <td valign="top"> <tt>'&#92;u0041'</tt>
+ *     <td> Locale-specific full name of the {@linkplain
+ *     java.text.DateFormatSymbols#getWeekdays day of the week},
+ *     e.g. {@code "Sunday"}, {@code "Monday"}
+ *
+ * <tr><td valign="top">{@code 'a'}
+ *     <td valign="top"> <tt>'&#92;u0061'</tt>
+ *     <td> Locale-specific short name of the {@linkplain
+ *     java.text.DateFormatSymbols#getShortWeekdays day of the week},
+ *     e.g. {@code "Sun"}, {@code "Mon"}
+ *
+ * <tr><td valign="top">{@code 'C'}
+ *     <td valign="top"> <tt>'&#92;u0043'</tt>
+ *     <td> Four-digit year divided by {@code 100}, formatted as two digits
+ *     with leading zero as necessary, i.e. {@code 00 - 99}
+ *
+ * <tr><td valign="top">{@code 'Y'}
+ *     <td valign="top"> <tt>'&#92;u0059'</tt> <td> Year, formatted to at least
+ *     four digits with leading zeros as necessary, e.g. {@code 0092} equals
+ *     {@code 92} CE for the Gregorian calendar.
+ *
+ * <tr><td valign="top">{@code 'y'}
+ *     <td valign="top"> <tt>'&#92;u0079'</tt>
+ *     <td> Last two digits of the year, formatted with leading zeros as
+ *     necessary, i.e. {@code 00 - 99}.
+ *
+ * <tr><td valign="top">{@code 'j'}
+ *     <td valign="top"> <tt>'&#92;u006a'</tt>
+ *     <td> Day of year, formatted as three digits with leading zeros as
+ *     necessary, e.g. {@code 001 - 366} for the Gregorian calendar.
+ *     {@code 001} corresponds to the first day of the year.
+ *
+ * <tr><td valign="top">{@code 'm'}
+ *     <td valign="top"> <tt>'&#92;u006d'</tt>
+ *     <td> Month, formatted as two digits with leading zeros as necessary,
+ *     i.e. {@code 01 - 13}, where "{@code 01}" is the first month of the
+ *     year and ("{@code 13}" is a special value required to support lunar
+ *     calendars).
+ *
+ * <tr><td valign="top">{@code 'd'}
+ *     <td valign="top"> <tt>'&#92;u0064'</tt>
+ *     <td> Day of month, formatted as two digits with leading zeros as
+ *     necessary, i.e. {@code 01 - 31}, where "{@code 01}" is the first day
+ *     of the month.
+ *
+ * <tr><td valign="top">{@code 'e'}
+ *     <td valign="top"> <tt>'&#92;u0065'</tt>
+ *     <td> Day of month, formatted as two digits, i.e. {@code 1 - 31} where
+ *     "{@code 1}" is the first day of the month.
+ *
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting common
+ * date/time compositions.
+ *
+ * <table cellpadding=5 summary="composites">
+ *
+ * <tr><td valign="top">{@code 'R'}
+ *     <td valign="top"> <tt>'&#92;u0052'</tt>
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM"}
+ *
+ * <tr><td valign="top">{@code 'T'}
+ *     <td valign="top"> <tt>'&#92;u0054'</tt>
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}.
+ *
+ * <tr><td valign="top">{@code 'r'}
+ *     <td valign="top"> <tt>'&#92;u0072'</tt>
+ *     <td> Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS
+ *     %Tp"}.  The location of the morning or afternoon marker
+ *     ({@code '%Tp'}) may be locale-dependent.
+ *
+ * <tr><td valign="top">{@code 'D'}
+ *     <td valign="top"> <tt>'&#92;u0044'</tt>
+ *     <td> Date formatted as {@code "%tm/%td/%ty"}.
+ *
+ * <tr><td valign="top">{@code 'F'}
+ *     <td valign="top"> <tt>'&#92;u0046'</tt>
+ *     <td> <a href="http://www.w3.org/TR/NOTE-datetime">ISO&nbsp;8601</a>
+ *     complete date formatted as {@code "%tY-%tm-%td"}.
+ *
+ * <tr><td valign="top">{@code 'c'}
+ *     <td valign="top"> <tt>'&#92;u0063'</tt>
+ *     <td> Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"},
+ *     e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}.
+ *
+ * </table>
+ *
+ * <p> The {@code '-'} flag defined for <a href="#dFlags">General
+ * conversions</a> applies.  If the {@code '#'} flag is given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <p> The width is the minimum number of characters to
+ * be written to the output.  If the length of the converted value is less than
+ * the {@code width} then the output will be padded by spaces
+ * (<tt>'&#92;u0020'</tt>) until the total number of characters equals width.
+ * The padding is on the left by default.  If the {@code '-'} flag is given
+ * then the padding will be on the right.  If width is not specified then there
+ * is no minimum.
+ *
+ * <p> The precision is not applicable.  If the precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <h4><a name="dper">Percent</a></h4>
+ *
+ * <p> The conversion does not correspond to any argument.
+ *
+ * <table cellpadding=5 summary="DTConv">
+ *
+ * <tr><td valign="top">{@code '%'}
+ *     <td> The result is a literal {@code '%'} (<tt>'&#92;u0025'</tt>)
+ *
+ * <p> The width is the minimum number of characters to
+ * be written to the output including the {@code '%'}.  If the length of the
+ * converted value is less than the {@code width} then the output will be
+ * padded by spaces (<tt>'&#92;u0020'</tt>) until the total number of
+ * characters equals width.  The padding is on the left.  If width is not
+ * specified then just the {@code '%'} is output.
+ *
+ * <p> The {@code '-'} flag defined for <a href="#dFlags">General
+ * conversions</a> applies.  If any other flags are provided, then a
+ * {@link FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <p> The precision is not applicable.  If the precision is specified an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * </table>
+ *
+ * <h4><a name="dls">Line Separator</a></h4>
+ *
+ * <p> The conversion does not correspond to any argument.
+ *
+ * <table cellpadding=5 summary="DTConv">
+ *
+ * <tr><td valign="top">{@code 'n'}
+ *     <td> the platform-specific line separator as returned by {@link
+ *     System#getProperty System.getProperty("line.separator")}.
+ *
+ * </table>
+ *
+ * <p> Flags, width, and precision are not applicable.  If any are provided an
+ * {@link IllegalFormatFlagsException}, {@link IllegalFormatWidthException},
+ * and {@link IllegalFormatPrecisionException}, respectively will be thrown.
+ *
+ * <h4><a name="dpos">Argument Index</a></h4>
+ *
+ * <p> Format specifiers can reference arguments in three ways:
+ *
+ * <ul>
+ *
+ * <li> <i>Explicit indexing</i> is used when the format specifier contains an
+ * argument index.  The argument index is a decimal integer indicating the
+ * position of the argument in the argument list.  The first argument is
+ * referenced by "{@code 1$}", the second by "{@code 2$}", etc.  An argument
+ * may be referenced more than once.
+ *
+ * <p> For example:
+ *
+ * <blockquote><pre>
+ *   formatter.format("%4$s %3$s %2$s %1$s %4$s %3$s %2$s %1$s",
+ *                    "a", "b", "c", "d")
+ *   // -&gt; "d c b a d c b a"
+ * </pre></blockquote>
+ *
+ * <li> <i>Relative indexing</i> is used when the format specifier contains a
+ * {@code '<'} (<tt>'&#92;u003c'</tt>) flag which causes the argument for
+ * the previous format specifier to be re-used.  If there is no previous
+ * argument, then a {@link MissingFormatArgumentException} is thrown.
+ *
+ * <blockquote><pre>
+ *    formatter.format("%s %s %&lt;s %&lt;s", "a", "b", "c", "d")
+ *    // -&gt; "a b b b"
+ *    // "c" and "d" are ignored because they are not referenced
+ * </pre></blockquote>
+ *
+ * <li> <i>Ordinary indexing</i> is used when the format specifier contains
+ * neither an argument index nor a {@code '<'} flag.  Each format specifier
+ * which uses ordinary indexing is assigned a sequential implicit index into
+ * argument list which is independent of the indices used by explicit or
+ * relative indexing.
+ *
+ * <blockquote><pre>
+ *   formatter.format("%s %s %s %s", "a", "b", "c", "d")
+ *   // -&gt; "a b c d"
+ * </pre></blockquote>
+ *
+ * </ul>
+ *
+ * <p> It is possible to have a format string which uses all forms of indexing,
+ * for example:
+ *
+ * <blockquote><pre>
+ *   formatter.format("%2$s %s %&lt;s %s", "a", "b", "c", "d")
+ *   // -&gt; "b a a b"
+ *   // "c" and "d" are ignored because they are not referenced
+ * </pre></blockquote>
+ *
+ * <p> The maximum number of arguments is limited by the maximum dimension of a
+ * Java array as defined by
+ * <cite>The Java&trade; Virtual Machine Specification</cite>.
+ * If the argument index is does not correspond to an
+ * available argument, then a {@link MissingFormatArgumentException} is thrown.
+ *
+ * <p> If there are more arguments than format specifiers, the extra arguments
+ * are ignored.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @author  Iris Clark
+ * @since 1.5
+ */
+public final class Formatter implements Closeable, Flushable {
+    private Appendable a;
+    private final Locale l;
+
+    private IOException lastException;
+
+    private final char zero;
+    private static double scaleUp;
+
+    // 1 (sign) + 19 (max # sig digits) + 1 ('.') + 1 ('e') + 1 (sign)
+    // + 3 (max # exp digits) + 4 (error) = 30
+    private static final int MAX_FD_CHARS = 30;
+
+    /**
+     * Returns a charset object for the given charset name.
+     * @throws NullPointerException          is csn is null
+     * @throws UnsupportedEncodingException  if the charset is not supported
+     */
+    private static Charset toCharset(String csn)
+        throws UnsupportedEncodingException
+    {
+        Objects.requireNonNull(csn, "charsetName");
+        try {
+            return Charset.forName(csn);
+        } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
+            // UnsupportedEncodingException should be thrown
+            throw new UnsupportedEncodingException(csn);
+        }
+    }
+
+    private static final Appendable nonNullAppendable(Appendable a) {
+        if (a == null)
+            return new StringBuilder();
+
+        return a;
+    }
+
+    /* Private constructors */
+    private Formatter(Locale l, Appendable a) {
+        this.a = a;
+        this.l = l;
+        this.zero = getZero(l);
+    }
+
+    private Formatter(Charset charset, Locale l, File file)
+        throws FileNotFoundException
+    {
+        this(l,
+             new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)));
+    }
+
+    /**
+     * Constructs a new formatter.
+     *
+     * <p> The destination of the formatted output is a {@link StringBuilder}
+     * which may be retrieved by invoking {@link #out out()} and whose
+     * current content may be converted into a string by invoking {@link
+     * #toString toString()}.  The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     */
+    public Formatter() {
+        this(Locale.getDefault(Locale.Category.FORMAT), new StringBuilder());
+    }
+
+    /**
+     * Constructs a new formatter with the specified destination.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  a
+     *         Destination for the formatted output.  If {@code a} is
+     *         {@code null} then a {@link StringBuilder} will be created.
+     */
+    public Formatter(Appendable a) {
+        this(Locale.getDefault(Locale.Category.FORMAT), nonNullAppendable(a));
+    }
+
+    /**
+     * Constructs a new formatter with the specified locale.
+     *
+     * <p> The destination of the formatted output is a {@link StringBuilder}
+     * which may be retrieved by invoking {@link #out out()} and whose current
+     * content may be converted into a string by invoking {@link #toString
+     * toString()}.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     */
+    public Formatter(Locale l) {
+        this(l, new StringBuilder());
+    }
+
+    /**
+     * Constructs a new formatter with the specified destination and locale.
+     *
+     * @param  a
+     *         Destination for the formatted output.  If {@code a} is
+     *         {@code null} then a {@link StringBuilder} will be created.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     */
+    public Formatter(Appendable a, Locale l) {
+        this(l, nonNullAppendable(a));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file name.
+     *
+     * <p> The charset used is the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this
+     *         formatter.  If the file exists then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws  FileNotFoundException
+     *          If the given file name does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     */
+    public Formatter(String fileName) throws FileNotFoundException {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file name and charset.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this
+     *         formatter.  If the file exists then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  FileNotFoundException
+     *          If the given file name does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(String fileName, String csn)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(fileName, csn, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file name, charset, and
+     * locale.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this
+     *         formatter.  If the file exists then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws  FileNotFoundException
+     *          If the given file name does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(String fileName, String csn, Locale l)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(toCharset(csn), l, new File(fileName));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file.
+     *
+     * <p> The charset used is the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  file
+     *         The file to use as the destination of this formatter.  If the
+     *         file exists then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())} denies
+     *          write access to the file
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     */
+    public Formatter(File file) throws FileNotFoundException {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file and charset.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  file
+     *         The file to use as the destination of this formatter.  If the
+     *         file exists then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())} denies
+     *          write access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(File file, String csn)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(file, csn, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file, charset, and
+     * locale.
+     *
+     * @param  file
+     *         The file to use as the destination of this formatter.  If the
+     *         file exists then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())} denies
+     *          write access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(File file, String csn, Locale l)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(toCharset(csn), l, file);
+    }
+
+    /**
+     * Constructs a new formatter with the specified print stream.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * <p> Characters are written to the given {@link java.io.PrintStream
+     * PrintStream} object and are therefore encoded using that object's
+     * charset.
+     *
+     * @param  ps
+     *         The stream to use as the destination of this formatter.
+     */
+    public Formatter(PrintStream ps) {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             (Appendable)Objects.requireNonNull(ps));
+    }
+
+    /**
+     * Constructs a new formatter with the specified output stream.
+     *
+     * <p> The charset used is the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  os
+     *         The output stream to use as the destination of this formatter.
+     *         The output will be buffered.
+     */
+    public Formatter(OutputStream os) {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             new BufferedWriter(new OutputStreamWriter(os)));
+    }
+
+    /**
+     * Constructs a new formatter with the specified output stream and
+     * charset.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  os
+     *         The output stream to use as the destination of this formatter.
+     *         The output will be buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(OutputStream os, String csn)
+        throws UnsupportedEncodingException
+    {
+        this(os, csn, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new formatter with the specified output stream, charset,
+     * and locale.
+     *
+     * @param  os
+     *         The output stream to use as the destination of this formatter.
+     *         The output will be buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(OutputStream os, String csn, Locale l)
+        throws UnsupportedEncodingException
+    {
+        this(l, new BufferedWriter(new OutputStreamWriter(os, csn)));
+    }
+
+    private static char getZero(Locale l) {
+        if ((l != null) && !l.equals(Locale.US)) {
+            DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+            return dfs.getZeroDigit();
+        } else {
+            return '0';
+        }
+    }
+
+    /**
+     * Returns the locale set by the construction of this formatter.
+     *
+     * <p> The {@link #format(java.util.Locale,String,Object...) format} method
+     * for this object which has a locale argument does not change this value.
+     *
+     * @return  {@code null} if no localization is applied, otherwise a
+     *          locale
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public Locale locale() {
+        ensureOpen();
+        return l;
+    }
+
+    /**
+     * Returns the destination for the output.
+     *
+     * @return  The destination for the output
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public Appendable out() {
+        ensureOpen();
+        return a;
+    }
+
+    /**
+     * Returns the result of invoking {@code toString()} on the destination
+     * for the output.  For example, the following code formats text into a
+     * {@link StringBuilder} then retrieves the resultant string:
+     *
+     * <blockquote><pre>
+     *   Formatter f = new Formatter();
+     *   f.format("Last reboot at %tc", lastRebootDate);
+     *   String s = f.toString();
+     *   // -&gt; s == "Last reboot at Sat Jan 01 00:00:00 PST 2000"
+     * </pre></blockquote>
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     *
+     * <pre>
+     *     out().toString() </pre>
+     *
+     * <p> Depending on the specification of {@code toString} for the {@link
+     * Appendable}, the returned string may or may not contain the characters
+     * written to the destination.  For instance, buffers typically return
+     * their contents in {@code toString()}, but streams cannot since the
+     * data is discarded.
+     *
+     * @return  The result of invoking {@code toString()} on the destination
+     *          for the output
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public String toString() {
+        ensureOpen();
+        return a.toString();
+    }
+
+    /**
+     * Flushes this formatter.  If the destination implements the {@link
+     * java.io.Flushable} interface, its {@code flush} method will be invoked.
+     *
+     * <p> Flushing a formatter writes any buffered output in the destination
+     * to the underlying stream.
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public void flush() {
+        ensureOpen();
+        if (a instanceof Flushable) {
+            try {
+                ((Flushable)a).flush();
+            } catch (IOException ioe) {
+                lastException = ioe;
+            }
+        }
+    }
+
+    /**
+     * Closes this formatter.  If the destination implements the {@link
+     * java.io.Closeable} interface, its {@code close} method will be invoked.
+     *
+     * <p> Closing a formatter allows it to release resources it may be holding
+     * (such as open files).  If the formatter is already closed, then invoking
+     * this method has no effect.
+     *
+     * <p> Attempting to invoke any methods except {@link #ioException()} in
+     * this formatter after it has been closed will result in a {@link
+     * FormatterClosedException}.
+     */
+    public void close() {
+        if (a == null)
+            return;
+        try {
+            if (a instanceof Closeable)
+                ((Closeable)a).close();
+        } catch (IOException ioe) {
+            lastException = ioe;
+        } finally {
+            a = null;
+        }
+    }
+
+    private void ensureOpen() {
+        if (a == null)
+            throw new FormatterClosedException();
+    }
+
+    /**
+     * Returns the {@code IOException} last thrown by this formatter's {@link
+     * Appendable}.
+     *
+     * <p> If the destination's {@code append()} method never throws
+     * {@code IOException}, then this method will always return {@code null}.
+     *
+     * @return  The last exception thrown by the Appendable or {@code null} if
+     *          no such exception exists.
+     */
+    public IOException ioException() {
+        return lastException;
+    }
+
+    /**
+     * Writes a formatted string to this object's destination using the
+     * specified format string and arguments.  The locale used is the one
+     * defined during the construction of this formatter.
+     *
+     * @param  format
+     *         A format string as described in <a href="#syntax">Format string
+     *         syntax</a>.
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *
+     * @throws  IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a href="#detail">Details</a>
+     *          section of the formatter class specification.
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     *
+     * @return  This formatter
+     */
+    public Formatter format(String format, Object ... args) {
+        return format(l, format, args);
+    }
+
+    /**
+     * Writes a formatted string to this object's destination using the
+     * specified locale, format string, and arguments.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.  This does not change this object's locale that was
+     *         set during construction.
+     *
+     * @param  format
+     *         A format string as described in <a href="#syntax">Format string
+     *         syntax</a>
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *
+     * @throws  IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a href="#detail">Details</a>
+     *          section of the formatter class specification.
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     *
+     * @return  This formatter
+     */
+    public Formatter format(Locale l, String format, Object ... args) {
+        ensureOpen();
+
+        // index of last argument referenced
+        int last = -1;
+        // last ordinary index
+        int lasto = -1;
+
+        FormatString[] fsa = parse(format);
+        for (int i = 0; i < fsa.length; i++) {
+            FormatString fs = fsa[i];
+            int index = fs.index();
+            try {
+                switch (index) {
+                case -2:  // fixed string, "%n", or "%%"
+                    fs.print(null, l);
+                    break;
+                case -1:  // relative index
+                    if (last < 0 || (args != null && last > args.length - 1))
+                        throw new MissingFormatArgumentException(fs.toString());
+                    fs.print((args == null ? null : args[last]), l);
+                    break;
+                case 0:  // ordinary index
+                    lasto++;
+                    last = lasto;
+                    if (args != null && lasto > args.length - 1)
+                        throw new MissingFormatArgumentException(fs.toString());
+                    fs.print((args == null ? null : args[lasto]), l);
+                    break;
+                default:  // explicit index
+                    last = index - 1;
+                    if (args != null && last > args.length - 1)
+                        throw new MissingFormatArgumentException(fs.toString());
+                    fs.print((args == null ? null : args[last]), l);
+                    break;
+                }
+            } catch (IOException x) {
+                lastException = x;
+            }
+        }
+        return this;
+    }
+
+    // BEGIN Android-changed: changed parse() to manual parsing instead of regex.
+    /**
+     * Finds format specifiers in the format string.
+     */
+    private FormatString[] parse(String s) {
+        ArrayList<FormatString> al = new ArrayList<>();
+        for (int i = 0, len = s.length(); i < len; ) {
+            int nextPercent = s.indexOf('%', i);
+            if (s.charAt(i) != '%') {
+                // This is plain-text part, find the maximal plain-text
+                // sequence and store it.
+                int plainTextStart = i;
+                int plainTextEnd = (nextPercent == -1) ? len: nextPercent;
+                al.add(new FixedString(s.substring(plainTextStart,
+                                                   plainTextEnd)));
+                i = plainTextEnd;
+            } else {
+                // We have a format specifier
+                FormatSpecifierParser fsp = new FormatSpecifierParser(s, i + 1);
+                al.add(fsp.getFormatSpecifier());
+                i = fsp.getEndIdx();
+            }
+        }
+        return al.toArray(new FormatString[al.size()]);
+    }
+
+    /**
+     * Parses the format specifier.
+     * %[argument_index$][flags][width][.precision][t]conversion
+     */
+    private class FormatSpecifierParser {
+        private final String format;
+        private int cursor;
+        private FormatSpecifier fs;
+
+        private String index;
+        private String flags;
+        private String width;
+        private String precision;
+        private String tT;
+        private String conv;
+
+        private static final String FLAGS = ",-(+# 0<";
+
+        public FormatSpecifierParser(String format, int startIdx) {
+            this.format = format;
+            cursor = startIdx;
+            // Index
+            if (nextIsInt()) {
+                String nint = nextInt();
+                if (peek() == '$') {
+                    index = nint;
+                    advance();
+                } else if (nint.charAt(0) == '0') {
+                    // This is a flag, skip to parsing flags.
+                    back(nint.length());
+                } else {
+                    // This is the width, skip to parsing precision.
+                    width = nint;
+                }
+            }
+            // Flags
+            flags = "";
+            while (width == null && FLAGS.indexOf(peek()) >= 0) {
+                flags += advance();
+            }
+            // Width
+            if (width == null && nextIsInt()) {
+                width = nextInt();
+            }
+            // Precision
+            if (peek() == '.') {
+                advance();
+                if (!nextIsInt()) {
+                    throw new IllegalFormatPrecisionException(peek());
+                }
+                precision = nextInt();
+            }
+            // tT
+            if (peek() == 't' || peek() == 'T') {
+                tT = String.valueOf(advance());
+            }
+            // Conversion
+            conv = String.valueOf(advance());
+
+            fs = new FormatSpecifier(index, flags, width, precision, tT, conv);
+        }
+
+        private String nextInt() {
+            int strBegin = cursor;
+            while (nextIsInt()) {
+                advance();
+            }
+            return format.substring(strBegin, cursor);
+        }
+
+        private boolean nextIsInt() {
+            return !isEnd() && Character.isDigit(peek());
+        }
+
+        private char peek() {
+            if (isEnd()) {
+                throw new UnknownFormatConversionException("End of String");
+            }
+            return format.charAt(cursor);
+        }
+
+        private char advance() {
+            if (isEnd()) {
+                throw new UnknownFormatConversionException("End of String");
+            }
+            return format.charAt(cursor++);
+        }
+
+        private void back(int len) {
+            cursor -= len;
+        }
+
+        private boolean isEnd() {
+            return cursor == format.length();
+        }
+
+        public FormatSpecifier getFormatSpecifier() {
+            return fs;
+        }
+
+        public int getEndIdx() {
+            return cursor;
+        }
+    }
+    // END Android-changed: changed parse() to manual parsing instead of regex.
+
+    private interface FormatString {
+        int index();
+        void print(Object arg, Locale l) throws IOException;
+        String toString();
+    }
+
+    private class FixedString implements FormatString {
+        private String s;
+        FixedString(String s) { this.s = s; }
+        public int index() { return -2; }
+        public void print(Object arg, Locale l)
+            throws IOException { a.append(s); }
+        public String toString() { return s; }
+    }
+
+    /**
+     * Enum for {@code BigDecimal} formatting.
+     */
+    public enum BigDecimalLayoutForm {
+        /**
+         * Format the {@code BigDecimal} in computerized scientific notation.
+         */
+        SCIENTIFIC,
+
+        /**
+         * Format the {@code BigDecimal} as a decimal number.
+         */
+        DECIMAL_FLOAT
+    };
+
+    private class FormatSpecifier implements FormatString {
+        private int index = -1;
+        private Flags f = Flags.NONE;
+        private int width;
+        private int precision;
+        private boolean dt = false;
+        private char c;
+
+        private int index(String s) {
+            if (s != null) {
+                try {
+                    // Android-changed: FormatSpecifierParser passes in correct String.
+                    // index = Integer.parseInt(s.substring(0, s.length() - 1));
+                    index = Integer.parseInt(s);
+                } catch (NumberFormatException x) {
+                    assert(false);
+                }
+            } else {
+                index = 0;
+            }
+            return index;
+        }
+
+        public int index() {
+            return index;
+        }
+
+        private Flags flags(String s) {
+            f = Flags.parse(s);
+            if (f.contains(Flags.PREVIOUS))
+                index = -1;
+            return f;
+        }
+
+        Flags flags() {
+            return f;
+        }
+
+        private int width(String s) {
+            width = -1;
+            if (s != null) {
+                try {
+                    width  = Integer.parseInt(s);
+                    if (width < 0)
+                        throw new IllegalFormatWidthException(width);
+                } catch (NumberFormatException x) {
+                    assert(false);
+                }
+            }
+            return width;
+        }
+
+        int width() {
+            return width;
+        }
+
+        private int precision(String s) {
+            precision = -1;
+            if (s != null) {
+                try {
+                    // Android-changed: FormatSpecifierParser passes in correct String.
+                    // precision = Integer.parseInt(s.substring(1));
+                    precision = Integer.parseInt(s);
+                    if (precision < 0)
+                        throw new IllegalFormatPrecisionException(precision);
+                } catch (NumberFormatException x) {
+                    assert(false);
+                }
+            }
+            return precision;
+        }
+
+        int precision() {
+            return precision;
+        }
+
+        private char conversion(String s) {
+            c = s.charAt(0);
+            if (!dt) {
+                if (!Conversion.isValid(c))
+                    throw new UnknownFormatConversionException(String.valueOf(c));
+                if (Character.isUpperCase(c))
+                    f.add(Flags.UPPERCASE);
+                c = Character.toLowerCase(c);
+                if (Conversion.isText(c))
+                    index = -2;
+            }
+            return c;
+        }
+
+        private char conversion() {
+            return c;
+        }
+
+        // BEGIN Android-changed: FormatSpecifierParser passes in the values instead of a Matcher.
+        FormatSpecifier(String indexStr, String flagsStr, String widthStr,
+                        String precisionStr, String tTStr, String convStr) {
+            int idx = 1;
+
+            index(indexStr);
+            flags(flagsStr);
+            width(widthStr);
+            precision(precisionStr);
+
+            if (tTStr != null) {
+                dt = true;
+                if (tTStr.equals("T"))
+                    f.add(Flags.UPPERCASE);
+            }
+
+            conversion(convStr);
+        // END Android-changed: FormatSpecifierParser passes in the values instead of a Matcher.
+            if (dt)
+                checkDateTime();
+            else if (Conversion.isGeneral(c))
+                checkGeneral();
+            else if (Conversion.isCharacter(c))
+                checkCharacter();
+            else if (Conversion.isInteger(c))
+                checkInteger();
+            else if (Conversion.isFloat(c))
+                checkFloat();
+            else if (Conversion.isText(c))
+                checkText();
+            else
+                throw new UnknownFormatConversionException(String.valueOf(c));
+        }
+
+        public void print(Object arg, Locale l) throws IOException {
+            if (dt) {
+                printDateTime(arg, l);
+                return;
+            }
+            switch(c) {
+            case Conversion.DECIMAL_INTEGER:
+            case Conversion.OCTAL_INTEGER:
+            case Conversion.HEXADECIMAL_INTEGER:
+                printInteger(arg, l);
+                break;
+            case Conversion.SCIENTIFIC:
+            case Conversion.GENERAL:
+            case Conversion.DECIMAL_FLOAT:
+            case Conversion.HEXADECIMAL_FLOAT:
+                printFloat(arg, l);
+                break;
+            case Conversion.CHARACTER:
+            case Conversion.CHARACTER_UPPER:
+                printCharacter(arg);
+                break;
+            case Conversion.BOOLEAN:
+                printBoolean(arg);
+                break;
+            case Conversion.STRING:
+                printString(arg, l);
+                break;
+            case Conversion.HASHCODE:
+                printHashCode(arg);
+                break;
+            case Conversion.LINE_SEPARATOR:
+                a.append(System.lineSeparator());
+                break;
+            case Conversion.PERCENT_SIGN:
+                a.append('%');
+                break;
+            default:
+                assert false;
+            }
+        }
+
+        private void printInteger(Object arg, Locale l) throws IOException {
+            if (arg == null)
+                print("null");
+            else if (arg instanceof Byte)
+                print(((Byte)arg).byteValue(), l);
+            else if (arg instanceof Short)
+                print(((Short)arg).shortValue(), l);
+            else if (arg instanceof Integer)
+                print(((Integer)arg).intValue(), l);
+            else if (arg instanceof Long)
+                print(((Long)arg).longValue(), l);
+            else if (arg instanceof BigInteger)
+                print(((BigInteger)arg), l);
+            else
+                failConversion(c, arg);
+        }
+
+        private void printFloat(Object arg, Locale l) throws IOException {
+            if (arg == null)
+                print("null");
+            else if (arg instanceof Float)
+                print(((Float)arg).floatValue(), l);
+            else if (arg instanceof Double)
+                print(((Double)arg).doubleValue(), l);
+            else if (arg instanceof BigDecimal)
+                print(((BigDecimal)arg), l);
+            else
+                failConversion(c, arg);
+        }
+
+        private void printDateTime(Object arg, Locale l) throws IOException {
+            if (arg == null) {
+                print("null");
+                return;
+            }
+            Calendar cal = null;
+
+            // Instead of Calendar.setLenient(true), perhaps we should
+            // wrap the IllegalArgumentException that might be thrown?
+            if (arg instanceof Long) {
+                // Note that the following method uses an instance of the
+                // default time zone (TimeZone.getDefaultRef().
+                cal = Calendar.getInstance(l == null ? Locale.US : l);
+                cal.setTimeInMillis((Long)arg);
+            } else if (arg instanceof Date) {
+                // Note that the following method uses an instance of the
+                // default time zone (TimeZone.getDefaultRef().
+                cal = Calendar.getInstance(l == null ? Locale.US : l);
+                cal.setTime((Date)arg);
+            } else if (arg instanceof Calendar) {
+                cal = (Calendar) ((Calendar) arg).clone();
+                cal.setLenient(true);
+            } else if (arg instanceof TemporalAccessor) {
+                print((TemporalAccessor) arg, c, l);
+                return;
+            } else {
+                failConversion(c, arg);
+            }
+            // Use the provided locale so that invocations of
+            // localizedMagnitude() use optimizations for null.
+            print(cal, c, l);
+        }
+
+        private void printCharacter(Object arg) throws IOException {
+            if (arg == null) {
+                print("null");
+                return;
+            }
+            String s = null;
+            if (arg instanceof Character) {
+                s = ((Character)arg).toString();
+            } else if (arg instanceof Byte) {
+                byte i = ((Byte)arg).byteValue();
+                if (Character.isValidCodePoint(i))
+                    s = new String(Character.toChars(i));
+                else
+                    throw new IllegalFormatCodePointException(i);
+            } else if (arg instanceof Short) {
+                short i = ((Short)arg).shortValue();
+                if (Character.isValidCodePoint(i))
+                    s = new String(Character.toChars(i));
+                else
+                    throw new IllegalFormatCodePointException(i);
+            } else if (arg instanceof Integer) {
+                int i = ((Integer)arg).intValue();
+                if (Character.isValidCodePoint(i))
+                    s = new String(Character.toChars(i));
+                else
+                    throw new IllegalFormatCodePointException(i);
+            } else {
+                failConversion(c, arg);
+            }
+            print(s);
+        }
+
+        private void printString(Object arg, Locale l) throws IOException {
+            if (arg instanceof Formattable) {
+                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))
+                    failMismatch(Flags.ALTERNATE, 's');
+                if (arg == null)
+                    print("null");
+                else
+                    print(arg.toString());
+            }
+        }
+
+        private void printBoolean(Object arg) throws IOException {
+            String s;
+            if (arg != null)
+                s = ((arg instanceof Boolean)
+                     ? ((Boolean)arg).toString()
+                     : Boolean.toString(true));
+            else
+                s = Boolean.toString(false);
+            print(s);
+        }
+
+        private void printHashCode(Object arg) throws IOException {
+            String s = (arg == null
+                        ? "null"
+                        : Integer.toHexString(arg.hashCode()));
+            print(s);
+        }
+
+        private void print(String s) throws IOException {
+            if (precision != -1 && precision < s.length())
+                s = s.substring(0, precision);
+            if (f.contains(Flags.UPPERCASE)) {
+                // Android-changed: Use provided locale instead of default, if it is non-null.
+                // s = s.toUpperCase();
+                s = s.toUpperCase(l != null ? l : Locale.getDefault());
+            }
+            a.append(justify(s));
+        }
+
+        private String justify(String s) {
+            if (width == -1)
+                return s;
+            StringBuilder sb = new StringBuilder();
+            boolean pad = f.contains(Flags.LEFT_JUSTIFY);
+            int sp = width - s.length();
+            if (!pad)
+                for (int i = 0; i < sp; i++) sb.append(' ');
+            sb.append(s);
+            if (pad)
+                for (int i = 0; i < sp; i++) sb.append(' ');
+            return sb.toString();
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder("%");
+            // Flags.UPPERCASE is set internally for legal conversions.
+            Flags dupf = f.dup().remove(Flags.UPPERCASE);
+            sb.append(dupf.toString());
+            if (index > 0)
+                sb.append(index).append('$');
+            if (width != -1)
+                sb.append(width);
+            if (precision != -1)
+                sb.append('.').append(precision);
+            if (dt)
+                sb.append(f.contains(Flags.UPPERCASE) ? 'T' : 't');
+            sb.append(f.contains(Flags.UPPERCASE)
+                      ? Character.toUpperCase(c) : c);
+            return sb.toString();
+        }
+
+        private void checkGeneral() {
+            if ((c == Conversion.BOOLEAN || c == Conversion.HASHCODE)
+                && f.contains(Flags.ALTERNATE))
+                failMismatch(Flags.ALTERNATE, c);
+            // '-' requires a width
+            if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                throw new MissingFormatWidthException(toString());
+            checkBadFlags(Flags.PLUS, Flags.LEADING_SPACE, Flags.ZERO_PAD,
+                          Flags.GROUP, Flags.PARENTHESES);
+        }
+
+        private void checkDateTime() {
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+            if (!DateTime.isValid(c))
+                throw new UnknownFormatConversionException("t" + c);
+            checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE,
+                          Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES);
+            // '-' requires a width
+            if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                throw new MissingFormatWidthException(toString());
+        }
+
+        private void checkCharacter() {
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+            checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE,
+                          Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES);
+            // '-' requires a width
+            if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                throw new MissingFormatWidthException(toString());
+        }
+
+        private void checkInteger() {
+            checkNumeric();
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+
+            if (c == Conversion.DECIMAL_INTEGER)
+                checkBadFlags(Flags.ALTERNATE);
+            else if (c == Conversion.OCTAL_INTEGER)
+                checkBadFlags(Flags.GROUP);
+            else
+                checkBadFlags(Flags.GROUP);
+        }
+
+        private void checkBadFlags(Flags ... badFlags) {
+            for (int i = 0; i < badFlags.length; i++)
+                if (f.contains(badFlags[i]))
+                    failMismatch(badFlags[i], c);
+        }
+
+        private void checkFloat() {
+            checkNumeric();
+            if (c == Conversion.DECIMAL_FLOAT) {
+            } else if (c == Conversion.HEXADECIMAL_FLOAT) {
+                checkBadFlags(Flags.PARENTHESES, Flags.GROUP);
+            } else if (c == Conversion.SCIENTIFIC) {
+                checkBadFlags(Flags.GROUP);
+            } else if (c == Conversion.GENERAL) {
+                checkBadFlags(Flags.ALTERNATE);
+            }
+        }
+
+        private void checkNumeric() {
+            if (width != -1 && width < 0)
+                throw new IllegalFormatWidthException(width);
+
+            if (precision != -1 && precision < 0)
+                throw new IllegalFormatPrecisionException(precision);
+
+            // '-' and '0' require a width
+            if (width == -1
+                && (f.contains(Flags.LEFT_JUSTIFY) || f.contains(Flags.ZERO_PAD)))
+                throw new MissingFormatWidthException(toString());
+
+            // bad combination
+            if ((f.contains(Flags.PLUS) && f.contains(Flags.LEADING_SPACE))
+                || (f.contains(Flags.LEFT_JUSTIFY) && f.contains(Flags.ZERO_PAD)))
+                throw new IllegalFormatFlagsException(f.toString());
+        }
+
+        private void checkText() {
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+            switch (c) {
+            case Conversion.PERCENT_SIGN:
+                if (f.valueOf() != Flags.LEFT_JUSTIFY.valueOf()
+                    && f.valueOf() != Flags.NONE.valueOf())
+                    throw new IllegalFormatFlagsException(f.toString());
+                // '-' requires a width
+                if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                    throw new MissingFormatWidthException(toString());
+                break;
+            case Conversion.LINE_SEPARATOR:
+                if (width != -1)
+                    throw new IllegalFormatWidthException(width);
+                if (f.valueOf() != Flags.NONE.valueOf())
+                    throw new IllegalFormatFlagsException(f.toString());
+                break;
+            default:
+                assert false;
+            }
+        }
+
+        private void print(byte value, Locale l) throws IOException {
+            long v = value;
+            if (value < 0
+                && (c == Conversion.OCTAL_INTEGER
+                    || c == Conversion.HEXADECIMAL_INTEGER)) {
+                v += (1L << 8);
+                assert v >= 0 : v;
+            }
+            print(v, l);
+        }
+
+        private void print(short value, Locale l) throws IOException {
+            long v = value;
+            if (value < 0
+                && (c == Conversion.OCTAL_INTEGER
+                    || c == Conversion.HEXADECIMAL_INTEGER)) {
+                v += (1L << 16);
+                assert v >= 0 : v;
+            }
+            print(v, l);
+        }
+
+        private void print(int value, Locale l) throws IOException {
+            long v = value;
+            if (value < 0
+                && (c == Conversion.OCTAL_INTEGER
+                    || c == Conversion.HEXADECIMAL_INTEGER)) {
+                v += (1L << 32);
+                assert v >= 0 : v;
+            }
+            print(v, l);
+        }
+
+        private void print(long value, Locale l) throws IOException {
+
+            StringBuilder sb = new StringBuilder();
+
+            if (c == Conversion.DECIMAL_INTEGER) {
+                boolean neg = value < 0;
+                char[] va;
+                if (value < 0)
+                    va = Long.toString(value, 10).substring(1).toCharArray();
+                else
+                    va = Long.toString(value, 10).toCharArray();
+
+                // leading sign indicator
+                leadingSign(sb, neg);
+
+                // the value
+                localizedMagnitude(sb, va, f, adjustWidth(width, f, neg), l);
+
+                // trailing sign indicator
+                trailingSign(sb, neg);
+            } else if (c == Conversion.OCTAL_INTEGER) {
+                checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE,
+                              Flags.PLUS);
+                String s = Long.toOctalString(value);
+                int len = (f.contains(Flags.ALTERNATE)
+                           ? s.length() + 1
+                           : s.length());
+
+                // apply ALTERNATE (radix indicator for octal) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE))
+                    sb.append('0');
+                if (f.contains(Flags.ZERO_PAD))
+                    for (int i = 0; i < width - len; i++) sb.append('0');
+                sb.append(s);
+            } else if (c == Conversion.HEXADECIMAL_INTEGER) {
+                checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE,
+                              Flags.PLUS);
+                String s = Long.toHexString(value);
+                int len = (f.contains(Flags.ALTERNATE)
+                           ? s.length() + 2
+                           : s.length());
+
+                // apply ALTERNATE (radix indicator for hex) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE))
+                    sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x");
+                if (f.contains(Flags.ZERO_PAD))
+                    for (int i = 0; i < width - len; i++) sb.append('0');
+                if (f.contains(Flags.UPPERCASE))
+                    s = s.toUpperCase();
+                sb.append(s);
+            }
+
+            // justify based on width
+            a.append(justify(sb.toString()));
+        }
+
+        // neg := val < 0
+        private StringBuilder leadingSign(StringBuilder sb, boolean neg) {
+            if (!neg) {
+                if (f.contains(Flags.PLUS)) {
+                    sb.append('+');
+                } else if (f.contains(Flags.LEADING_SPACE)) {
+                    sb.append(' ');
+                }
+            } else {
+                if (f.contains(Flags.PARENTHESES))
+                    sb.append('(');
+                else
+                    sb.append('-');
+            }
+            return sb;
+        }
+
+        // neg := val < 0
+        private StringBuilder trailingSign(StringBuilder sb, boolean neg) {
+            if (neg && f.contains(Flags.PARENTHESES))
+                sb.append(')');
+            return sb;
+        }
+
+        private void print(BigInteger value, Locale l) throws IOException {
+            StringBuilder sb = new StringBuilder();
+            boolean neg = value.signum() == -1;
+            BigInteger v = value.abs();
+
+            // leading sign indicator
+            leadingSign(sb, neg);
+
+            // the value
+            if (c == Conversion.DECIMAL_INTEGER) {
+                char[] va = v.toString().toCharArray();
+                localizedMagnitude(sb, va, f, adjustWidth(width, f, neg), l);
+            } else if (c == Conversion.OCTAL_INTEGER) {
+                String s = v.toString(8);
+
+                int len = s.length() + sb.length();
+                if (neg && f.contains(Flags.PARENTHESES))
+                    len++;
+
+                // apply ALTERNATE (radix indicator for octal) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE)) {
+                    len++;
+                    sb.append('0');
+                }
+                if (f.contains(Flags.ZERO_PAD)) {
+                    for (int i = 0; i < width - len; i++)
+                        sb.append('0');
+                }
+                sb.append(s);
+            } else if (c == Conversion.HEXADECIMAL_INTEGER) {
+                String s = v.toString(16);
+
+                int len = s.length() + sb.length();
+                if (neg && f.contains(Flags.PARENTHESES))
+                    len++;
+
+                // apply ALTERNATE (radix indicator for hex) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE)) {
+                    len += 2;
+                    sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x");
+                }
+                if (f.contains(Flags.ZERO_PAD))
+                    for (int i = 0; i < width - len; i++)
+                        sb.append('0');
+                if (f.contains(Flags.UPPERCASE))
+                    s = s.toUpperCase();
+                sb.append(s);
+            }
+
+            // trailing sign indicator
+            trailingSign(sb, (value.signum() == -1));
+
+            // justify based on width
+            a.append(justify(sb.toString()));
+        }
+
+        private void print(float value, Locale l) throws IOException {
+            print((double) value, l);
+        }
+
+        private void print(double value, Locale l) throws IOException {
+            StringBuilder sb = new StringBuilder();
+            boolean neg = Double.compare(value, 0.0) == -1;
+
+            if (!Double.isNaN(value)) {
+                double v = Math.abs(value);
+
+                // leading sign indicator
+                leadingSign(sb, neg);
+
+                // the value
+                if (!Double.isInfinite(v))
+                    print(sb, v, l, f, c, precision, neg);
+                else
+                    sb.append(f.contains(Flags.UPPERCASE)
+                              ? "INFINITY" : "Infinity");
+
+                // trailing sign indicator
+                trailingSign(sb, neg);
+            } else {
+                sb.append(f.contains(Flags.UPPERCASE) ? "NAN" : "NaN");
+            }
+
+            // justify based on width
+            a.append(justify(sb.toString()));
+        }
+
+        // !Double.isInfinite(value) && !Double.isNaN(value)
+        private void print(StringBuilder sb, double value, Locale l,
+                           Flags f, char c, int precision, boolean neg)
+            throws IOException
+        {
+            if (c == Conversion.SCIENTIFIC) {
+                // Create a new FormattedFloatingDecimal with the desired
+                // precision.
+                int prec = (precision == -1 ? 6 : precision);
+
+                FormattedFloatingDecimal fd
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.SCIENTIFIC);
+
+                char[] mant = addZeros(fd.getMantissa(), prec);
+
+                // If the precision is zero and the '#' flag is set, add the
+                // requested decimal point.
+                if (f.contains(Flags.ALTERNATE) && (prec == 0))
+                    mant = addDot(mant);
+
+                char[] exp = (value == 0.0)
+                    ? new char[] {'+','0','0'} : fd.getExponent();
+
+                int newW = width;
+                if (width != -1)
+                    newW = adjustWidth(width - exp.length - 1, f, neg);
+                localizedMagnitude(sb, mant, f, newW, l);
+
+                // BEGIN Android-changed: Use localized exponent separator for %e.
+                Locale separatorLocale = (l != null) ? l : Locale.getDefault();
+                LocaleData localeData = LocaleData.get(separatorLocale);
+                sb.append(f.contains(Flags.UPPERCASE) ?
+                        localeData.exponentSeparator.toUpperCase(separatorLocale) :
+                        localeData.exponentSeparator.toLowerCase(separatorLocale));
+                // END Android-changed: Use localized exponent separator for %e.
+
+                Flags flags = f.dup().remove(Flags.GROUP);
+                char sign = exp[0];
+                assert(sign == '+' || sign == '-');
+                sb.append(sign);
+
+                char[] tmp = new char[exp.length - 1];
+                System.arraycopy(exp, 1, tmp, 0, exp.length - 1);
+                sb.append(localizedMagnitude(null, tmp, flags, -1, l));
+            } else if (c == Conversion.DECIMAL_FLOAT) {
+                // Create a new FormattedFloatingDecimal with the desired
+                // precision.
+                int prec = (precision == -1 ? 6 : precision);
+
+                FormattedFloatingDecimal fd
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
+
+                char[] mant = addZeros(fd.getMantissa(), prec);
+
+                // If the precision is zero and the '#' flag is set, add the
+                // requested decimal point.
+                if (f.contains(Flags.ALTERNATE) && (prec == 0))
+                    mant = addDot(mant);
+
+                int newW = width;
+                if (width != -1)
+                    newW = adjustWidth(width, f, neg);
+                localizedMagnitude(sb, mant, f, newW, l);
+            } else if (c == Conversion.GENERAL) {
+                int prec = precision;
+                if (precision == -1)
+                    prec = 6;
+                else if (precision == 0)
+                    prec = 1;
+
+                char[] exp;
+                char[] mant;
+                int expRounded;
+                if (value == 0.0) {
+                    exp = null;
+                    mant = new char[] {'0'};
+                    expRounded = 0;
+                } else {
+                    FormattedFloatingDecimal fd
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.GENERAL);
+                    exp = fd.getExponent();
+                    mant = fd.getMantissa();
+                    expRounded = fd.getExponentRounded();
+                }
+
+                if (exp != null) {
+                    prec -= 1;
+                } else {
+                    prec -= expRounded + 1;
+                }
+
+                mant = addZeros(mant, prec);
+                // If the precision is zero and the '#' flag is set, add the
+                // requested decimal point.
+                if (f.contains(Flags.ALTERNATE) && (prec == 0))
+                    mant = addDot(mant);
+
+                int newW = width;
+                if (width != -1) {
+                    if (exp != null)
+                        newW = adjustWidth(width - exp.length - 1, f, neg);
+                    else
+                        newW = adjustWidth(width, f, neg);
+                }
+                localizedMagnitude(sb, mant, f, newW, l);
+
+                if (exp != null) {
+                    sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
+
+                    Flags flags = f.dup().remove(Flags.GROUP);
+                    char sign = exp[0];
+                    assert(sign == '+' || sign == '-');
+                    sb.append(sign);
+
+                    char[] tmp = new char[exp.length - 1];
+                    System.arraycopy(exp, 1, tmp, 0, exp.length - 1);
+                    sb.append(localizedMagnitude(null, tmp, flags, -1, l));
+                }
+            } else if (c == Conversion.HEXADECIMAL_FLOAT) {
+                int prec = precision;
+                if (precision == -1)
+                    // assume that we want all of the digits
+                    prec = 0;
+                else if (precision == 0)
+                    prec = 1;
+
+                String s = hexDouble(value, prec);
+
+                char[] va;
+                boolean upper = f.contains(Flags.UPPERCASE);
+                sb.append(upper ? "0X" : "0x");
+
+                if (f.contains(Flags.ZERO_PAD))
+                    for (int i = 0; i < width - s.length() - 2; i++)
+                        sb.append('0');
+
+                int idx = s.indexOf('p');
+                va = s.substring(0, idx).toCharArray();
+                if (upper) {
+                    String tmp = new String(va);
+                    // don't localize hex
+                    tmp = tmp.toUpperCase(Locale.US);
+                    va = tmp.toCharArray();
+                }
+                sb.append(prec != 0 ? addZeros(va, prec) : va);
+                sb.append(upper ? 'P' : 'p');
+                sb.append(s.substring(idx+1));
+            }
+        }
+
+        // Add zeros to the requested precision.
+        private char[] addZeros(char[] v, int prec) {
+            // Look for the dot.  If we don't find one, the we'll need to add
+            // it before we add the zeros.
+            int i;
+            for (i = 0; i < v.length; i++) {
+                if (v[i] == '.')
+                    break;
+            }
+            boolean needDot = false;
+            if (i == v.length) {
+                needDot = true;
+            }
+
+            // Determine existing precision.
+            int outPrec = v.length - i - (needDot ? 0 : 1);
+            assert (outPrec <= prec);
+            if (outPrec == prec)
+                return v;
+
+            // Create new array with existing contents.
+            char[] tmp
+                = new char[v.length + prec - outPrec + (needDot ? 1 : 0)];
+            System.arraycopy(v, 0, tmp, 0, v.length);
+
+            // Add dot if previously determined to be necessary.
+            int start = v.length;
+            if (needDot) {
+                tmp[v.length] = '.';
+                start++;
+            }
+
+            // Add zeros.
+            for (int j = start; j < tmp.length; j++)
+                tmp[j] = '0';
+
+            return tmp;
+        }
+
+        // Method assumes that d > 0.
+        private String hexDouble(double d, int prec) {
+            // Let Double.toHexString handle simple cases
+            if(!Double.isFinite(d) || d == 0.0 || prec == 0 || prec >= 13)
+                // remove "0x"
+                return Double.toHexString(d).substring(2);
+            else {
+                assert(prec >= 1 && prec <= 12);
+
+                int exponent  = Math.getExponent(d);
+                boolean subnormal
+                    = (exponent == DoubleConsts.MIN_EXPONENT - 1);
+
+                // If this is subnormal input so normalize (could be faster to
+                // do as integer operation).
+                if (subnormal) {
+                    scaleUp = Math.scalb(1.0, 54);
+                    d *= scaleUp;
+                    // Calculate the exponent.  This is not just exponent + 54
+                    // since the former is not the normalized exponent.
+                    exponent = Math.getExponent(d);
+                    assert exponent >= DoubleConsts.MIN_EXPONENT &&
+                        exponent <= DoubleConsts.MAX_EXPONENT: exponent;
+                }
+
+                int precision = 1 + prec*4;
+                int shiftDistance
+                    =  DoubleConsts.SIGNIFICAND_WIDTH - precision;
+                assert(shiftDistance >= 1 && shiftDistance < DoubleConsts.SIGNIFICAND_WIDTH);
+
+                long doppel = Double.doubleToLongBits(d);
+                // Deterime the number of bits to keep.
+                long newSignif
+                    = (doppel & (DoubleConsts.EXP_BIT_MASK
+                                 | DoubleConsts.SIGNIF_BIT_MASK))
+                                     >> shiftDistance;
+                // Bits to round away.
+                long roundingBits = doppel & ~(~0L << shiftDistance);
+
+                // To decide how to round, look at the low-order bit of the
+                // working significand, the highest order discarded bit (the
+                // round bit) and whether any of the lower order discarded bits
+                // are nonzero (the sticky bit).
+
+                boolean leastZero = (newSignif & 0x1L) == 0L;
+                boolean round
+                    = ((1L << (shiftDistance - 1) ) & roundingBits) != 0L;
+                boolean sticky  = shiftDistance > 1 &&
+                    (~(1L<< (shiftDistance - 1)) & roundingBits) != 0;
+                if((leastZero && round && sticky) || (!leastZero && round)) {
+                    newSignif++;
+                }
+
+                long signBit = doppel & DoubleConsts.SIGN_BIT_MASK;
+                newSignif = signBit | (newSignif << shiftDistance);
+                double result = Double.longBitsToDouble(newSignif);
+
+                if (Double.isInfinite(result) ) {
+                    // Infinite result generated by rounding
+                    return "1.0p1024";
+                } else {
+                    String res = Double.toHexString(result).substring(2);
+                    if (!subnormal)
+                        return res;
+                    else {
+                        // Create a normalized subnormal string.
+                        int idx = res.indexOf('p');
+                        if (idx == -1) {
+                            // No 'p' character in hex string.
+                            assert false;
+                            return null;
+                        } else {
+                            // Get exponent and append at the end.
+                            String exp = res.substring(idx + 1);
+                            int iexp = Integer.parseInt(exp) -54;
+                            return res.substring(0, idx) + "p"
+                                + Integer.toString(iexp);
+                        }
+                    }
+                }
+            }
+        }
+
+        private void print(BigDecimal value, Locale l) throws IOException {
+            if (c == Conversion.HEXADECIMAL_FLOAT)
+                failConversion(c, value);
+            StringBuilder sb = new StringBuilder();
+            boolean neg = value.signum() == -1;
+            BigDecimal v = value.abs();
+            // leading sign indicator
+            leadingSign(sb, neg);
+
+            // the value
+            print(sb, v, l, f, c, precision, neg);
+
+            // trailing sign indicator
+            trailingSign(sb, neg);
+
+            // justify based on width
+            a.append(justify(sb.toString()));
+        }
+
+        // value > 0
+        private void print(StringBuilder sb, BigDecimal value, Locale l,
+                           Flags f, char c, int precision, boolean neg)
+            throws IOException
+        {
+            if (c == Conversion.SCIENTIFIC) {
+                // Create a new BigDecimal with the desired precision.
+                int prec = (precision == -1 ? 6 : precision);
+                int scale = value.scale();
+                int origPrec = value.precision();
+                int nzeros = 0;
+                int compPrec;
+
+                if (prec > origPrec - 1) {
+                    compPrec = origPrec;
+                    nzeros = prec - (origPrec - 1);
+                } else {
+                    compPrec = prec + 1;
+                }
+
+                MathContext mc = new MathContext(compPrec);
+                BigDecimal v
+                    = new BigDecimal(value.unscaledValue(), scale, mc);
+
+                BigDecimalLayout bdl
+                    = new BigDecimalLayout(v.unscaledValue(), v.scale(),
+                                           BigDecimalLayoutForm.SCIENTIFIC);
+
+                char[] mant = bdl.mantissa();
+
+                // Add a decimal point if necessary.  The mantissa may not
+                // contain a decimal point if the scale is zero (the internal
+                // representation has no fractional part) or the original
+                // precision is one. Append a decimal point if '#' is set or if
+                // we require zero padding to get to the requested precision.
+                if ((origPrec == 1 || !bdl.hasDot())
+                    && (nzeros > 0 || (f.contains(Flags.ALTERNATE))))
+                    mant = addDot(mant);
+
+                // Add trailing zeros in the case precision is greater than
+                // the number of available digits after the decimal separator.
+                mant = trailingZeros(mant, nzeros);
+
+                char[] exp = bdl.exponent();
+                int newW = width;
+                if (width != -1)
+                    newW = adjustWidth(width - exp.length - 1, f, neg);
+                localizedMagnitude(sb, mant, f, newW, l);
+
+                sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
+
+                Flags flags = f.dup().remove(Flags.GROUP);
+                char sign = exp[0];
+                assert(sign == '+' || sign == '-');
+                sb.append(exp[0]);
+
+                char[] tmp = new char[exp.length - 1];
+                System.arraycopy(exp, 1, tmp, 0, exp.length - 1);
+                sb.append(localizedMagnitude(null, tmp, flags, -1, l));
+            } else if (c == Conversion.DECIMAL_FLOAT) {
+                // Create a new BigDecimal with the desired precision.
+                int prec = (precision == -1 ? 6 : precision);
+                int scale = value.scale();
+
+                if (scale > prec) {
+                    // more "scale" digits than the requested "precision"
+                    int compPrec = value.precision();
+                    if (compPrec <= scale) {
+                        // case of 0.xxxxxx
+                        value = value.setScale(prec, RoundingMode.HALF_UP);
+                    } else {
+                        compPrec -= (scale - prec);
+                        value = new BigDecimal(value.unscaledValue(),
+                                               scale,
+                                               new MathContext(compPrec));
+                    }
+                }
+                BigDecimalLayout bdl = new BigDecimalLayout(
+                                           value.unscaledValue(),
+                                           value.scale(),
+                                           BigDecimalLayoutForm.DECIMAL_FLOAT);
+
+                char mant[] = bdl.mantissa();
+                int nzeros = (bdl.scale() < prec ? prec - bdl.scale() : 0);
+
+                // Add a decimal point if necessary.  The mantissa may not
+                // contain a decimal point if the scale is zero (the internal
+                // representation has no fractional part).  Append a decimal
+                // point if '#' is set or we require zero padding to get to the
+                // requested precision.
+                if (bdl.scale() == 0 && (f.contains(Flags.ALTERNATE) || nzeros > 0))
+                    mant = addDot(bdl.mantissa());
+
+                // Add trailing zeros if the precision is greater than the
+                // number of available digits after the decimal separator.
+                mant = trailingZeros(mant, nzeros);
+
+                localizedMagnitude(sb, mant, f, adjustWidth(width, f, neg), l);
+            } else if (c == Conversion.GENERAL) {
+                int prec = precision;
+                if (precision == -1)
+                    prec = 6;
+                else if (precision == 0)
+                    prec = 1;
+
+                BigDecimal tenToTheNegFour = BigDecimal.valueOf(1, 4);
+                BigDecimal tenToThePrec = BigDecimal.valueOf(1, -prec);
+                if ((value.equals(BigDecimal.ZERO))
+                    || ((value.compareTo(tenToTheNegFour) != -1)
+                        && (value.compareTo(tenToThePrec) == -1))) {
+
+                    int e = - value.scale()
+                        + (value.unscaledValue().toString().length() - 1);
+
+                    // xxx.yyy
+                    //   g precision (# sig digits) = #x + #y
+                    //   f precision = #y
+                    //   exponent = #x - 1
+                    // => f precision = g precision - exponent - 1
+                    // 0.000zzz
+                    //   g precision (# sig digits) = #z
+                    //   f precision = #0 (after '.') + #z
+                    //   exponent = - #0 (after '.') - 1
+                    // => f precision = g precision - exponent - 1
+                    prec = prec - e - 1;
+
+                    print(sb, value, l, f, Conversion.DECIMAL_FLOAT, prec,
+                          neg);
+                } else {
+                    print(sb, value, l, f, Conversion.SCIENTIFIC, prec - 1, neg);
+                }
+            } else if (c == Conversion.HEXADECIMAL_FLOAT) {
+                // This conversion isn't supported.  The error should be
+                // reported earlier.
+                assert false;
+            }
+        }
+
+        private class BigDecimalLayout {
+            private StringBuilder mant;
+            private StringBuilder exp;
+            private boolean dot = false;
+            private int scale;
+
+            public BigDecimalLayout(BigInteger intVal, int scale, BigDecimalLayoutForm form) {
+                layout(intVal, scale, form);
+            }
+
+            public boolean hasDot() {
+                return dot;
+            }
+
+            public int scale() {
+                return scale;
+            }
+
+            // char[] with canonical string representation
+            public char[] layoutChars() {
+                StringBuilder sb = new StringBuilder(mant);
+                if (exp != null) {
+                    sb.append('E');
+                    sb.append(exp);
+                }
+                return toCharArray(sb);
+            }
+
+            public char[] mantissa() {
+                return toCharArray(mant);
+            }
+
+            // The exponent will be formatted as a sign ('+' or '-') followed
+            // by the exponent zero-padded to include at least two digits.
+            public char[] exponent() {
+                return toCharArray(exp);
+            }
+
+            private char[] toCharArray(StringBuilder sb) {
+                if (sb == null)
+                    return null;
+                char[] result = new char[sb.length()];
+                sb.getChars(0, result.length, result, 0);
+                return result;
+            }
+
+            private void layout(BigInteger intVal, int scale, BigDecimalLayoutForm form) {
+                char coeff[] = intVal.toString().toCharArray();
+                this.scale = scale;
+
+                // Construct a buffer, with sufficient capacity for all cases.
+                // If E-notation is needed, length will be: +1 if negative, +1
+                // if '.' needed, +2 for "E+", + up to 10 for adjusted
+                // exponent.  Otherwise it could have +1 if negative, plus
+                // leading "0.00000"
+                mant = new StringBuilder(coeff.length + 14);
+
+                if (scale == 0) {
+                    int len = coeff.length;
+                    if (len > 1) {
+                        mant.append(coeff[0]);
+                        if (form == BigDecimalLayoutForm.SCIENTIFIC) {
+                            mant.append('.');
+                            dot = true;
+                            mant.append(coeff, 1, len - 1);
+                            exp = new StringBuilder("+");
+                            if (len < 10)
+                                exp.append("0").append(len - 1);
+                            else
+                                exp.append(len - 1);
+                        } else {
+                            mant.append(coeff, 1, len - 1);
+                        }
+                    } else {
+                        mant.append(coeff);
+                        if (form == BigDecimalLayoutForm.SCIENTIFIC)
+                            exp = new StringBuilder("+00");
+                    }
+                    return;
+                }
+                long adjusted = -(long) scale + (coeff.length - 1);
+                if (form == BigDecimalLayoutForm.DECIMAL_FLOAT) {
+                    // count of padding zeros
+                    int pad = scale - coeff.length;
+                    if (pad >= 0) {
+                        // 0.xxx form
+                        mant.append("0.");
+                        dot = true;
+                        for (; pad > 0 ; pad--) mant.append('0');
+                        mant.append(coeff);
+                    } else {
+                        if (-pad < coeff.length) {
+                            // xx.xx form
+                            mant.append(coeff, 0, -pad);
+                            mant.append('.');
+                            dot = true;
+                            mant.append(coeff, -pad, scale);
+                        } else {
+                            // xx form
+                            mant.append(coeff, 0, coeff.length);
+                            for (int i = 0; i < -scale; i++)
+                                mant.append('0');
+                            this.scale = 0;
+                        }
+                    }
+                } else {
+                    // x.xxx form
+                    mant.append(coeff[0]);
+                    if (coeff.length > 1) {
+                        mant.append('.');
+                        dot = true;
+                        mant.append(coeff, 1, coeff.length-1);
+                    }
+                    exp = new StringBuilder();
+                    if (adjusted != 0) {
+                        long abs = Math.abs(adjusted);
+                        // require sign
+                        exp.append(adjusted < 0 ? '-' : '+');
+                        if (abs < 10)
+                            exp.append('0');
+                        exp.append(abs);
+                    } else {
+                        exp.append("+00");
+                    }
+                }
+            }
+        }
+
+        private int adjustWidth(int width, Flags f, boolean neg) {
+            int newW = width;
+            if (newW != -1 && neg && f.contains(Flags.PARENTHESES))
+                newW--;
+            return newW;
+        }
+
+        // Add a '.' to th mantissa if required
+        private char[] addDot(char[] mant) {
+            char[] tmp = mant;
+            tmp = new char[mant.length + 1];
+            System.arraycopy(mant, 0, tmp, 0, mant.length);
+            tmp[tmp.length - 1] = '.';
+            return tmp;
+        }
+
+        // Add trailing zeros in the case precision is greater than the number
+        // of available digits after the decimal separator.
+        private char[] trailingZeros(char[] mant, int nzeros) {
+            char[] tmp = mant;
+            if (nzeros > 0) {
+                tmp = new char[mant.length + nzeros];
+                System.arraycopy(mant, 0, tmp, 0, mant.length);
+                for (int i = mant.length; i < tmp.length; i++)
+                    tmp[i] = '0';
+            }
+            return tmp;
+        }
+
+        private void print(Calendar t, char c, Locale l)  throws IOException
+        {
+            StringBuilder sb = new StringBuilder();
+            print(sb, t, c, l);
+
+            // justify based on width
+            String s = justify(sb.toString());
+            if (f.contains(Flags.UPPERCASE))
+                s = s.toUpperCase();
+
+            a.append(s);
+        }
+
+        private Appendable print(StringBuilder sb, Calendar t, char c,
+                                 Locale l)
+            throws IOException
+        {
+            if (sb == null)
+                sb = new StringBuilder();
+            switch (c) {
+            case DateTime.HOUR_OF_DAY_0: // 'H' (00 - 23)
+            case DateTime.HOUR_0:        // 'I' (01 - 12)
+            case DateTime.HOUR_OF_DAY:   // 'k' (0 - 23) -- like H
+            case DateTime.HOUR:        { // 'l' (1 - 12) -- like I
+                int i = t.get(Calendar.HOUR_OF_DAY);
+                if (c == DateTime.HOUR_0 || c == DateTime.HOUR)
+                    i = (i == 0 || i == 12 ? 12 : i % 12);
+                Flags flags = (c == DateTime.HOUR_OF_DAY_0
+                               || c == DateTime.HOUR_0
+                               ? Flags.ZERO_PAD
+                               : Flags.NONE);
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.MINUTE:      { // 'M' (00 - 59)
+                int i = t.get(Calendar.MINUTE);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.NANOSECOND:  { // 'N' (000000000 - 999999999)
+                int i = t.get(Calendar.MILLISECOND) * 1000000;
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 9, l));
+                break;
+            }
+            case DateTime.MILLISECOND: { // 'L' (000 - 999)
+                int i = t.get(Calendar.MILLISECOND);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 3, l));
+                break;
+            }
+            case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
+                long i = t.getTimeInMillis();
+                Flags flags = Flags.NONE;
+                sb.append(localizedMagnitude(null, i, flags, width, l));
+                break;
+            }
+            case DateTime.AM_PM:       { // 'p' (am or pm)
+                // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper
+                String[] ampm = { "AM", "PM" };
+                if (l != null && l != Locale.US) {
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(l);
+                    ampm = dfs.getAmPmStrings();
+                }
+                String s = ampm[t.get(Calendar.AM_PM)];
+                sb.append(s.toLowerCase(l != null ? l : Locale.US));
+                break;
+            }
+            case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
+                long i = t.getTimeInMillis() / 1000;
+                Flags flags = Flags.NONE;
+                sb.append(localizedMagnitude(null, i, flags, width, l));
+                break;
+            }
+            case DateTime.SECOND:      { // 'S' (00 - 60 - leap second)
+                int i = t.get(Calendar.SECOND);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
+                int i = t.get(Calendar.ZONE_OFFSET) + t.get(Calendar.DST_OFFSET);
+                boolean neg = i < 0;
+                sb.append(neg ? '-' : '+');
+                if (neg)
+                    i = -i;
+                int min = i / 60000;
+                // combine minute and hour into a single integer
+                int offset = (min / 60) * 100 + (min % 60);
+                Flags flags = Flags.ZERO_PAD;
+
+                sb.append(localizedMagnitude(null, offset, flags, 4, l));
+                break;
+            }
+            case DateTime.ZONE:        { // 'Z' (symbol)
+                TimeZone tz = t.getTimeZone();
+                sb.append(tz.getDisplayName((t.get(Calendar.DST_OFFSET) != 0),
+                                           TimeZone.SHORT,
+                                            (l == null) ? Locale.US : l));
+                break;
+            }
+
+            // Date
+            case DateTime.NAME_OF_DAY_ABBREV:     // 'a'
+            case DateTime.NAME_OF_DAY:          { // 'A'
+                int i = t.get(Calendar.DAY_OF_WEEK);
+                Locale lt = ((l == null) ? Locale.US : l);
+                DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                if (c == DateTime.NAME_OF_DAY)
+                    sb.append(dfs.getWeekdays()[i]);
+                else
+                    sb.append(dfs.getShortWeekdays()[i]);
+                break;
+            }
+            case DateTime.NAME_OF_MONTH_ABBREV:   // 'b'
+            case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
+            case DateTime.NAME_OF_MONTH:        { // 'B'
+                int i = t.get(Calendar.MONTH);
+                Locale lt = ((l == null) ? Locale.US : l);
+                DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                if (c == DateTime.NAME_OF_MONTH)
+                    sb.append(dfs.getMonths()[i]);
+                else
+                    sb.append(dfs.getShortMonths()[i]);
+                break;
+            }
+            case DateTime.CENTURY:                // 'C' (00 - 99)
+            case DateTime.YEAR_2:                 // 'y' (00 - 99)
+            case DateTime.YEAR_4:               { // 'Y' (0000 - 9999)
+                int i = t.get(Calendar.YEAR);
+                int size = 2;
+                switch (c) {
+                case DateTime.CENTURY:
+                    i /= 100;
+                    break;
+                case DateTime.YEAR_2:
+                    i %= 100;
+                    break;
+                case DateTime.YEAR_4:
+                    size = 4;
+                    break;
+                }
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, size, l));
+                break;
+            }
+            case DateTime.DAY_OF_MONTH_0:         // 'd' (01 - 31)
+            case DateTime.DAY_OF_MONTH:         { // 'e' (1 - 31) -- like d
+                int i = t.get(Calendar.DATE);
+                Flags flags = (c == DateTime.DAY_OF_MONTH_0
+                               ? Flags.ZERO_PAD
+                               : Flags.NONE);
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.DAY_OF_YEAR:          { // 'j' (001 - 366)
+                int i = t.get(Calendar.DAY_OF_YEAR);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 3, l));
+                break;
+            }
+            case DateTime.MONTH:                { // 'm' (01 - 12)
+                int i = t.get(Calendar.MONTH) + 1;
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+
+            // Composites
+            case DateTime.TIME:         // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
+            case DateTime.TIME_24_HOUR:    { // 'R' (hh:mm same as %H:%M)
+                char sep = ':';
+                print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
+                print(sb, t, DateTime.MINUTE, l);
+                if (c == DateTime.TIME) {
+                    sb.append(sep);
+                    print(sb, t, DateTime.SECOND, l);
+                }
+                break;
+            }
+            case DateTime.TIME_12_HOUR:    { // 'r' (hh:mm:ss [AP]M)
+                char sep = ':';
+                print(sb, t, DateTime.HOUR_0, l).append(sep);
+                print(sb, t, DateTime.MINUTE, l).append(sep);
+                print(sb, t, DateTime.SECOND, l).append(' ');
+                // this may be in wrong place for some locales
+                StringBuilder tsb = new StringBuilder();
+                print(tsb, t, DateTime.AM_PM, l);
+                sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US));
+                break;
+            }
+            case DateTime.DATE_TIME:    { // 'c' (Sat Nov 04 12:02:33 EST 1999)
+                char sep = ' ';
+                print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
+                print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
+                print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                print(sb, t, DateTime.TIME, l).append(sep);
+                print(sb, t, DateTime.ZONE, l).append(sep);
+                print(sb, t, DateTime.YEAR_4, l);
+                break;
+            }
+            case DateTime.DATE:            { // 'D' (mm/dd/yy)
+                char sep = '/';
+                print(sb, t, DateTime.MONTH, l).append(sep);
+                print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                print(sb, t, DateTime.YEAR_2, l);
+                break;
+            }
+            case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
+                char sep = '-';
+                print(sb, t, DateTime.YEAR_4, l).append(sep);
+                print(sb, t, DateTime.MONTH, l).append(sep);
+                print(sb, t, DateTime.DAY_OF_MONTH_0, l);
+                break;
+            }
+            default:
+                assert false;
+            }
+            return sb;
+        }
+
+        private void print(TemporalAccessor t, char c, Locale l)  throws IOException {
+            StringBuilder sb = new StringBuilder();
+            print(sb, t, c, l);
+            // justify based on width
+            String s = justify(sb.toString());
+            if (f.contains(Flags.UPPERCASE))
+                s = s.toUpperCase();
+            a.append(s);
+        }
+
+        private Appendable print(StringBuilder sb, TemporalAccessor t, char c,
+                                 Locale l) throws IOException {
+            if (sb == null)
+                sb = new StringBuilder();
+            try {
+                switch (c) {
+                case DateTime.HOUR_OF_DAY_0: {  // 'H' (00 - 23)
+                    int i = t.get(ChronoField.HOUR_OF_DAY);
+                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    break;
+                }
+                case DateTime.HOUR_OF_DAY: {   // 'k' (0 - 23) -- like H
+                    int i = t.get(ChronoField.HOUR_OF_DAY);
+                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    break;
+                }
+                case DateTime.HOUR_0:      {  // 'I' (01 - 12)
+                    int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
+                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    break;
+                }
+                case DateTime.HOUR:        { // 'l' (1 - 12) -- like I
+                    int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
+                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    break;
+                }
+                case DateTime.MINUTE:      { // 'M' (00 - 59)
+                    int i = t.get(ChronoField.MINUTE_OF_HOUR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.NANOSECOND:  { // 'N' (000000000 - 999999999)
+                    int i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000;
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 9, l));
+                    break;
+                }
+                case DateTime.MILLISECOND: { // 'L' (000 - 999)
+                    int i = t.get(ChronoField.MILLI_OF_SECOND);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    break;
+                }
+                case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
+                    long i = t.getLong(ChronoField.INSTANT_SECONDS) * 1000L +
+                             t.getLong(ChronoField.MILLI_OF_SECOND);
+                    Flags flags = Flags.NONE;
+                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    break;
+                }
+                case DateTime.AM_PM:       { // 'p' (am or pm)
+                    // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper
+                    String[] ampm = { "AM", "PM" };
+                    if (l != null && l != Locale.US) {
+                        DateFormatSymbols dfs = DateFormatSymbols.getInstance(l);
+                        ampm = dfs.getAmPmStrings();
+                    }
+                    String s = ampm[t.get(ChronoField.AMPM_OF_DAY)];
+                    sb.append(s.toLowerCase(l != null ? l : Locale.US));
+                    break;
+                }
+                case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
+                    long i = t.getLong(ChronoField.INSTANT_SECONDS);
+                    Flags flags = Flags.NONE;
+                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    break;
+                }
+                case DateTime.SECOND:      { // 'S' (00 - 60 - leap second)
+                    int i = t.get(ChronoField.SECOND_OF_MINUTE);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
+                    int i = t.get(ChronoField.OFFSET_SECONDS);
+                    boolean neg = i < 0;
+                    sb.append(neg ? '-' : '+');
+                    if (neg)
+                        i = -i;
+                    int min = i / 60;
+                    // combine minute and hour into a single integer
+                    int offset = (min / 60) * 100 + (min % 60);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, offset, flags, 4, l));
+                    break;
+                }
+                case DateTime.ZONE:        { // 'Z' (symbol)
+                    ZoneId zid = t.query(TemporalQueries.zone());
+                    if (zid == null) {
+                        throw new IllegalFormatConversionException(c, t.getClass());
+                    }
+                    if (!(zid instanceof ZoneOffset) &&
+                        t.isSupported(ChronoField.INSTANT_SECONDS)) {
+                        Instant instant = Instant.from(t);
+                        sb.append(TimeZone.getTimeZone(zid.getId())
+                                          .getDisplayName(zid.getRules().isDaylightSavings(instant),
+                                                          TimeZone.SHORT,
+                                                          (l == null) ? Locale.US : l));
+                        break;
+                    }
+                    sb.append(zid.getId());
+                    break;
+                }
+                // Date
+                case DateTime.NAME_OF_DAY_ABBREV:     // 'a'
+                case DateTime.NAME_OF_DAY:          { // 'A'
+                    int i = t.get(ChronoField.DAY_OF_WEEK) % 7 + 1;
+                    Locale lt = ((l == null) ? Locale.US : l);
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                    if (c == DateTime.NAME_OF_DAY)
+                        sb.append(dfs.getWeekdays()[i]);
+                    else
+                        sb.append(dfs.getShortWeekdays()[i]);
+                    break;
+                }
+                case DateTime.NAME_OF_MONTH_ABBREV:   // 'b'
+                case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
+                case DateTime.NAME_OF_MONTH:        { // 'B'
+                    int i = t.get(ChronoField.MONTH_OF_YEAR) - 1;
+                    Locale lt = ((l == null) ? Locale.US : l);
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                    if (c == DateTime.NAME_OF_MONTH)
+                        sb.append(dfs.getMonths()[i]);
+                    else
+                        sb.append(dfs.getShortMonths()[i]);
+                    break;
+                }
+                case DateTime.CENTURY:                // 'C' (00 - 99)
+                case DateTime.YEAR_2:                 // 'y' (00 - 99)
+                case DateTime.YEAR_4:               { // 'Y' (0000 - 9999)
+                    int i = t.get(ChronoField.YEAR_OF_ERA);
+                    int size = 2;
+                    switch (c) {
+                    case DateTime.CENTURY:
+                        i /= 100;
+                        break;
+                    case DateTime.YEAR_2:
+                        i %= 100;
+                        break;
+                    case DateTime.YEAR_4:
+                        size = 4;
+                        break;
+                    }
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, size, l));
+                    break;
+                }
+                case DateTime.DAY_OF_MONTH_0:         // 'd' (01 - 31)
+                case DateTime.DAY_OF_MONTH:         { // 'e' (1 - 31) -- like d
+                    int i = t.get(ChronoField.DAY_OF_MONTH);
+                    Flags flags = (c == DateTime.DAY_OF_MONTH_0
+                                   ? Flags.ZERO_PAD
+                                   : Flags.NONE);
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.DAY_OF_YEAR:          { // 'j' (001 - 366)
+                    int i = t.get(ChronoField.DAY_OF_YEAR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    break;
+                }
+                case DateTime.MONTH:                { // 'm' (01 - 12)
+                    int i = t.get(ChronoField.MONTH_OF_YEAR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+
+                // Composites
+                case DateTime.TIME:         // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
+                case DateTime.TIME_24_HOUR:    { // 'R' (hh:mm same as %H:%M)
+                    char sep = ':';
+                    print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
+                    print(sb, t, DateTime.MINUTE, l);
+                    if (c == DateTime.TIME) {
+                        sb.append(sep);
+                        print(sb, t, DateTime.SECOND, l);
+                    }
+                    break;
+                }
+                case DateTime.TIME_12_HOUR:    { // 'r' (hh:mm:ss [AP]M)
+                    char sep = ':';
+                    print(sb, t, DateTime.HOUR_0, l).append(sep);
+                    print(sb, t, DateTime.MINUTE, l).append(sep);
+                    print(sb, t, DateTime.SECOND, l).append(' ');
+                    // this may be in wrong place for some locales
+                    StringBuilder tsb = new StringBuilder();
+                    print(tsb, t, DateTime.AM_PM, l);
+                    sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US));
+                    break;
+                }
+                case DateTime.DATE_TIME:    { // 'c' (Sat Nov 04 12:02:33 EST 1999)
+                    char sep = ' ';
+                    print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
+                    print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(sb, t, DateTime.TIME, l).append(sep);
+                    print(sb, t, DateTime.ZONE, l).append(sep);
+                    print(sb, t, DateTime.YEAR_4, l);
+                    break;
+                }
+                case DateTime.DATE:            { // 'D' (mm/dd/yy)
+                    char sep = '/';
+                    print(sb, t, DateTime.MONTH, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(sb, t, DateTime.YEAR_2, l);
+                    break;
+                }
+                case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
+                    char sep = '-';
+                    print(sb, t, DateTime.YEAR_4, l).append(sep);
+                    print(sb, t, DateTime.MONTH, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l);
+                    break;
+                }
+                default:
+                    assert false;
+                }
+            } catch (DateTimeException x) {
+                throw new IllegalFormatConversionException(c, t.getClass());
+            }
+            return sb;
+        }
+
+        // -- Methods to support throwing exceptions --
+
+        private void failMismatch(Flags f, char c) {
+            String fs = f.toString();
+            throw new FormatFlagsConversionMismatchException(fs, c);
+        }
+
+        private void failConversion(char c, Object arg) {
+            throw new IllegalFormatConversionException(c, arg.getClass());
+        }
+
+        private char getZero(Locale l) {
+            if ((l != null) &&  !l.equals(locale())) {
+                DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+                return dfs.getZeroDigit();
+            }
+            return zero;
+        }
+
+        private StringBuilder
+            localizedMagnitude(StringBuilder sb, long value, Flags f,
+                               int width, Locale l)
+        {
+            char[] va = Long.toString(value, 10).toCharArray();
+            return localizedMagnitude(sb, va, f, width, l);
+        }
+
+        private StringBuilder
+            localizedMagnitude(StringBuilder sb, char[] value, Flags f,
+                               int width, Locale l)
+        {
+            if (sb == null)
+                sb = new StringBuilder();
+            int begin = sb.length();
+
+            char zero = getZero(l);
+
+            // determine localized grouping separator and size
+            char grpSep = '\0';
+            int  grpSize = -1;
+            char decSep = '\0';
+
+            int len = value.length;
+            int dot = len;
+            for (int j = 0; j < len; j++) {
+                if (value[j] == '.') {
+                    dot = j;
+                    break;
+                }
+            }
+
+            if (dot < len) {
+                if (l == null || l.equals(Locale.US)) {
+                    decSep  = '.';
+                } else {
+                    DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+                    decSep  = dfs.getDecimalSeparator();
+                }
+            }
+
+            if (f.contains(Flags.GROUP)) {
+                if (l == null || l.equals(Locale.US)) {
+                    grpSep = ',';
+                    grpSize = 3;
+                } else {
+                    DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+                    grpSep = dfs.getGroupingSeparator();
+                    DecimalFormat df = (DecimalFormat) NumberFormat.getIntegerInstance(l);
+                    grpSize = df.getGroupingSize();
+                    // BEGIN Android-changed: Fix division by zero if group separator is not clear.
+                    // http://b/33245708
+                    // Some locales have a group separator but also patterns without groups.
+                    // If we do not clear the group separator in these cases a divide by zero
+                    // is thrown when determining where to place the separators.
+                    if (!df.isGroupingUsed() || df.getGroupingSize() == 0) {
+                        grpSep = '\0';
+                    }
+                    // END Android-changed: Fix division by zero if group separator is not clear.
+                }
+            }
+
+            // localize the digits inserting group separators as necessary
+            for (int j = 0; j < len; j++) {
+                if (j == dot) {
+                    sb.append(decSep);
+                    // no more group separators after the decimal separator
+                    grpSep = '\0';
+                    continue;
+                }
+
+                char c = value[j];
+                sb.append((char) ((c - '0') + zero));
+                if (grpSep != '\0' && j != dot - 1 && ((dot - j) % grpSize == 1))
+                    sb.append(grpSep);
+            }
+
+            // apply zero padding
+            len = sb.length();
+            if (width != -1 && f.contains(Flags.ZERO_PAD))
+                for (int k = 0; k < width - len; k++)
+                    sb.insert(begin, zero);
+
+            return sb;
+        }
+    }
+
+    private static class Flags {
+        private int flags;
+
+        static final Flags NONE          = new Flags(0);      // ''
+
+        // duplicate declarations from Formattable.java
+        static final Flags LEFT_JUSTIFY  = new Flags(1<<0);   // '-'
+        static final Flags UPPERCASE     = new Flags(1<<1);   // '^'
+        static final Flags ALTERNATE     = new Flags(1<<2);   // '#'
+
+        // numerics
+        static final Flags PLUS          = new Flags(1<<3);   // '+'
+        static final Flags LEADING_SPACE = new Flags(1<<4);   // ' '
+        static final Flags ZERO_PAD      = new Flags(1<<5);   // '0'
+        static final Flags GROUP         = new Flags(1<<6);   // ','
+        static final Flags PARENTHESES   = new Flags(1<<7);   // '('
+
+        // indexing
+        static final Flags PREVIOUS      = new Flags(1<<8);   // '<'
+
+        private Flags(int f) {
+            flags = f;
+        }
+
+        public int valueOf() {
+            return flags;
+        }
+
+        public boolean contains(Flags f) {
+            return (flags & f.valueOf()) == f.valueOf();
+        }
+
+        public Flags dup() {
+            return new Flags(flags);
+        }
+
+        private Flags add(Flags f) {
+            flags |= f.valueOf();
+            return this;
+        }
+
+        public Flags remove(Flags f) {
+            flags &= ~f.valueOf();
+            return this;
+        }
+
+        public static Flags parse(String s) {
+            char[] ca = s.toCharArray();
+            Flags f = new Flags(0);
+            for (int i = 0; i < ca.length; i++) {
+                Flags v = parse(ca[i]);
+                if (f.contains(v))
+                    throw new DuplicateFormatFlagsException(v.toString());
+                f.add(v);
+            }
+            return f;
+        }
+
+        // parse those flags which may be provided by users
+        private static Flags parse(char c) {
+            switch (c) {
+            case '-': return LEFT_JUSTIFY;
+            case '#': return ALTERNATE;
+            case '+': return PLUS;
+            case ' ': return LEADING_SPACE;
+            case '0': return ZERO_PAD;
+            case ',': return GROUP;
+            case '(': return PARENTHESES;
+            case '<': return PREVIOUS;
+            default:
+                throw new UnknownFormatFlagsException(String.valueOf(c));
+            }
+        }
+
+        // Returns a string representation of the current {@code Flags}.
+        public static String toString(Flags f) {
+            return f.toString();
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            if (contains(LEFT_JUSTIFY))  sb.append('-');
+            if (contains(UPPERCASE))     sb.append('^');
+            if (contains(ALTERNATE))     sb.append('#');
+            if (contains(PLUS))          sb.append('+');
+            if (contains(LEADING_SPACE)) sb.append(' ');
+            if (contains(ZERO_PAD))      sb.append('0');
+            if (contains(GROUP))         sb.append(',');
+            if (contains(PARENTHESES))   sb.append('(');
+            if (contains(PREVIOUS))      sb.append('<');
+            return sb.toString();
+        }
+    }
+
+    private static class Conversion {
+        // Byte, Short, Integer, Long, BigInteger
+        // (and associated primitives due to autoboxing)
+        static final char DECIMAL_INTEGER     = 'd';
+        static final char OCTAL_INTEGER       = 'o';
+        static final char HEXADECIMAL_INTEGER = 'x';
+        static final char HEXADECIMAL_INTEGER_UPPER = 'X';
+
+        // Float, Double, BigDecimal
+        // (and associated primitives due to autoboxing)
+        static final char SCIENTIFIC          = 'e';
+        static final char SCIENTIFIC_UPPER    = 'E';
+        static final char GENERAL             = 'g';
+        static final char GENERAL_UPPER       = 'G';
+        static final char DECIMAL_FLOAT       = 'f';
+        static final char HEXADECIMAL_FLOAT   = 'a';
+        static final char HEXADECIMAL_FLOAT_UPPER = 'A';
+
+        // Character, Byte, Short, Integer
+        // (and associated primitives due to autoboxing)
+        static final char CHARACTER           = 'c';
+        static final char CHARACTER_UPPER     = 'C';
+
+        // java.util.Date, java.util.Calendar, long
+        static final char DATE_TIME           = 't';
+        static final char DATE_TIME_UPPER     = 'T';
+
+        // if (arg.TYPE != boolean) return boolean
+        // if (arg != null) return true; else return false;
+        static final char BOOLEAN             = 'b';
+        static final char BOOLEAN_UPPER       = 'B';
+        // if (arg instanceof Formattable) arg.formatTo()
+        // else arg.toString();
+        static final char STRING              = 's';
+        static final char STRING_UPPER        = 'S';
+        // arg.hashCode()
+        static final char HASHCODE            = 'h';
+        static final char HASHCODE_UPPER      = 'H';
+
+        static final char LINE_SEPARATOR      = 'n';
+        static final char PERCENT_SIGN        = '%';
+
+        static boolean isValid(char c) {
+            return (isGeneral(c) || isInteger(c) || isFloat(c) || isText(c)
+                    || c == 't' || isCharacter(c));
+        }
+
+        // Returns true iff the Conversion is applicable to all objects.
+        static boolean isGeneral(char c) {
+            switch (c) {
+            case BOOLEAN:
+            case BOOLEAN_UPPER:
+            case STRING:
+            case STRING_UPPER:
+            case HASHCODE:
+            case HASHCODE_UPPER:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        // Returns true iff the Conversion is applicable to character.
+        static boolean isCharacter(char c) {
+            switch (c) {
+            case CHARACTER:
+            case CHARACTER_UPPER:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        // Returns true iff the Conversion is an integer type.
+        static boolean isInteger(char c) {
+            switch (c) {
+            case DECIMAL_INTEGER:
+            case OCTAL_INTEGER:
+            case HEXADECIMAL_INTEGER:
+            case HEXADECIMAL_INTEGER_UPPER:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        // Returns true iff the Conversion is a floating-point type.
+        static boolean isFloat(char c) {
+            switch (c) {
+            case SCIENTIFIC:
+            case SCIENTIFIC_UPPER:
+            case GENERAL:
+            case GENERAL_UPPER:
+            case DECIMAL_FLOAT:
+            case HEXADECIMAL_FLOAT:
+            case HEXADECIMAL_FLOAT_UPPER:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        // Returns true iff the Conversion does not require an argument
+        static boolean isText(char c) {
+            switch (c) {
+            case LINE_SEPARATOR:
+            case PERCENT_SIGN:
+                return true;
+            default:
+                return false;
+            }
+        }
+    }
+
+    private static class DateTime {
+        static final char HOUR_OF_DAY_0 = 'H'; // (00 - 23)
+        static final char HOUR_0        = 'I'; // (01 - 12)
+        static final char HOUR_OF_DAY   = 'k'; // (0 - 23) -- like H
+        static final char HOUR          = 'l'; // (1 - 12) -- like I
+        static final char MINUTE        = 'M'; // (00 - 59)
+        static final char NANOSECOND    = 'N'; // (000000000 - 999999999)
+        static final char MILLISECOND   = 'L'; // jdk, not in gnu (000 - 999)
+        static final char MILLISECOND_SINCE_EPOCH = 'Q'; // (0 - 99...?)
+        static final char AM_PM         = 'p'; // (am or pm)
+        static final char SECONDS_SINCE_EPOCH = 's'; // (0 - 99...?)
+        static final char SECOND        = 'S'; // (00 - 60 - leap second)
+        static final char TIME          = 'T'; // (24 hour hh:mm:ss)
+        static final char ZONE_NUMERIC  = 'z'; // (-1200 - +1200) - ls minus?
+        static final char ZONE          = 'Z'; // (symbol)
+
+        // Date
+        static final char NAME_OF_DAY_ABBREV    = 'a'; // 'a'
+        static final char NAME_OF_DAY           = 'A'; // 'A'
+        static final char NAME_OF_MONTH_ABBREV  = 'b'; // 'b'
+        static final char NAME_OF_MONTH         = 'B'; // 'B'
+        static final char CENTURY               = 'C'; // (00 - 99)
+        static final char DAY_OF_MONTH_0        = 'd'; // (01 - 31)
+        static final char DAY_OF_MONTH          = 'e'; // (1 - 31) -- like d
+// *    static final char ISO_WEEK_OF_YEAR_2    = 'g'; // cross %y %V
+// *    static final char ISO_WEEK_OF_YEAR_4    = 'G'; // cross %Y %V
+        static final char NAME_OF_MONTH_ABBREV_X  = 'h'; // -- same b
+        static final char DAY_OF_YEAR           = 'j'; // (001 - 366)
+        static final char MONTH                 = 'm'; // (01 - 12)
+// *    static final char DAY_OF_WEEK_1         = 'u'; // (1 - 7) Monday
+// *    static final char WEEK_OF_YEAR_SUNDAY   = 'U'; // (0 - 53) Sunday+
+// *    static final char WEEK_OF_YEAR_MONDAY_01 = 'V'; // (01 - 53) Monday+
+// *    static final char DAY_OF_WEEK_0         = 'w'; // (0 - 6) Sunday
+// *    static final char WEEK_OF_YEAR_MONDAY   = 'W'; // (00 - 53) Monday
+        static final char YEAR_2                = 'y'; // (00 - 99)
+        static final char YEAR_4                = 'Y'; // (0000 - 9999)
+
+        // Composites
+        static final char TIME_12_HOUR  = 'r'; // (hh:mm:ss [AP]M)
+        static final char TIME_24_HOUR  = 'R'; // (hh:mm same as %H:%M)
+// *    static final char LOCALE_TIME   = 'X'; // (%H:%M:%S) - parse format?
+        static final char DATE_TIME             = 'c';
+                                            // (Sat Nov 04 12:02:33 EST 1999)
+        static final char DATE                  = 'D'; // (mm/dd/yy)
+        static final char ISO_STANDARD_DATE     = 'F'; // (%Y-%m-%d)
+// *    static final char LOCALE_DATE           = 'x'; // (mm/dd/yy)
+
+        static boolean isValid(char c) {
+            switch (c) {
+            case HOUR_OF_DAY_0:
+            case HOUR_0:
+            case HOUR_OF_DAY:
+            case HOUR:
+            case MINUTE:
+            case NANOSECOND:
+            case MILLISECOND:
+            case MILLISECOND_SINCE_EPOCH:
+            case AM_PM:
+            case SECONDS_SINCE_EPOCH:
+            case SECOND:
+            case TIME:
+            case ZONE_NUMERIC:
+            case ZONE:
+
+            // Date
+            case NAME_OF_DAY_ABBREV:
+            case NAME_OF_DAY:
+            case NAME_OF_MONTH_ABBREV:
+            case NAME_OF_MONTH:
+            case CENTURY:
+            case DAY_OF_MONTH_0:
+            case DAY_OF_MONTH:
+// *        case ISO_WEEK_OF_YEAR_2:
+// *        case ISO_WEEK_OF_YEAR_4:
+            case NAME_OF_MONTH_ABBREV_X:
+            case DAY_OF_YEAR:
+            case MONTH:
+// *        case DAY_OF_WEEK_1:
+// *        case WEEK_OF_YEAR_SUNDAY:
+// *        case WEEK_OF_YEAR_MONDAY_01:
+// *        case DAY_OF_WEEK_0:
+// *        case WEEK_OF_YEAR_MONDAY:
+            case YEAR_2:
+            case YEAR_4:
+
+            // Composites
+            case TIME_12_HOUR:
+            case TIME_24_HOUR:
+// *        case LOCALE_TIME:
+            case DATE_TIME:
+            case DATE:
+            case ISO_STANDARD_DATE:
+// *        case LOCALE_DATE:
+                return true;
+            default:
+                return false;
+            }
+        }
+    }
+}
diff --git a/java/util/FormatterClosedException.java b/java/util/FormatterClosedException.java
new file mode 100644
index 0000000..b0aa872
--- /dev/null
+++ b/java/util/FormatterClosedException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the formatter has been closed.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class FormatterClosedException extends IllegalStateException {
+
+    private static final long serialVersionUID = 18111216L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public FormatterClosedException() { }
+}
diff --git a/java/util/GregorianCalendar.java b/java/util/GregorianCalendar.java
new file mode 100644
index 0000000..1d8c87b
--- /dev/null
+++ b/java/util/GregorianCalendar.java
@@ -0,0 +1,3468 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.time.Instant;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoField;
+import libcore.util.ZoneInfo;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.CalendarDate;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.Era;
+import sun.util.calendar.Gregorian;
+import sun.util.calendar.JulianCalendar;
+
+/**
+ * <code>GregorianCalendar</code> is a concrete subclass of
+ * <code>Calendar</code> and provides the standard calendar system
+ * used by most of the world.
+ *
+ * <p> <code>GregorianCalendar</code> is a hybrid calendar that
+ * supports both the Julian and Gregorian calendar systems with the
+ * support of a single discontinuity, which corresponds by default to
+ * the Gregorian date when the Gregorian calendar was instituted
+ * (October 15, 1582 in some countries, later in others).  The cutover
+ * date may be changed by the caller by calling {@link
+ * #setGregorianChange(Date) setGregorianChange()}.
+ *
+ * <p>
+ * Historically, in those countries which adopted the Gregorian calendar first,
+ * October 4, 1582 (Julian) was thus followed by October 15, 1582 (Gregorian). This calendar models
+ * this correctly.  Before the Gregorian cutover, <code>GregorianCalendar</code>
+ * implements the Julian calendar.  The only difference between the Gregorian
+ * and the Julian calendar is the leap year rule. The Julian calendar specifies
+ * leap years every four years, whereas the Gregorian calendar omits century
+ * years which are not divisible by 400.
+ *
+ * <p>
+ * <code>GregorianCalendar</code> implements <em>proleptic</em> Gregorian and
+ * Julian calendars. That is, dates are computed by extrapolating the current
+ * rules indefinitely far backward and forward in time. As a result,
+ * <code>GregorianCalendar</code> may be used for all years to generate
+ * meaningful and consistent results. However, dates obtained using
+ * <code>GregorianCalendar</code> are historically accurate only from March 1, 4
+ * AD onward, when modern Julian calendar rules were adopted.  Before this date,
+ * leap year rules were applied irregularly, and before 45 BC the Julian
+ * calendar did not even exist.
+ *
+ * <p>
+ * Prior to the institution of the Gregorian calendar, New Year's Day was
+ * March 25. To avoid confusion, this calendar always uses January 1. A manual
+ * adjustment may be made if desired for dates that are prior to the Gregorian
+ * changeover and which fall between January 1 and March 24.
+ *
+ * <h3><a name="week_and_year">Week Of Year and Week Year</a></h3>
+ *
+ * <p>Values calculated for the {@link Calendar#WEEK_OF_YEAR
+ * WEEK_OF_YEAR} field range from 1 to 53. The first week of a
+ * calendar year is the earliest seven day period starting on {@link
+ * Calendar#getFirstDayOfWeek() getFirstDayOfWeek()} that contains at
+ * least {@link Calendar#getMinimalDaysInFirstWeek()
+ * getMinimalDaysInFirstWeek()} days from that year. It thus depends
+ * on the values of {@code getMinimalDaysInFirstWeek()}, {@code
+ * getFirstDayOfWeek()}, and the day of the week of January 1. Weeks
+ * between week 1 of one year and week 1 of the following year
+ * (exclusive) are numbered sequentially from 2 to 52 or 53 (except
+ * for year(s) involved in the Julian-Gregorian transition).
+ *
+ * <p>The {@code getFirstDayOfWeek()} and {@code
+ * getMinimalDaysInFirstWeek()} values are initialized using
+ * locale-dependent resources when constructing a {@code
+ * GregorianCalendar}. <a name="iso8601_compatible_setting">The week
+ * determination is compatible</a> with the ISO 8601 standard when {@code
+ * getFirstDayOfWeek()} is {@code MONDAY} and {@code
+ * getMinimalDaysInFirstWeek()} is 4, which values are used in locales
+ * where the standard is preferred. These values can explicitly be set by
+ * calling {@link Calendar#setFirstDayOfWeek(int) setFirstDayOfWeek()} and
+ * {@link Calendar#setMinimalDaysInFirstWeek(int)
+ * setMinimalDaysInFirstWeek()}.
+ *
+ * <p>A <a name="week_year"><em>week year</em></a> is in sync with a
+ * {@code WEEK_OF_YEAR} cycle. All weeks between the first and last
+ * weeks (inclusive) have the same <em>week year</em> value.
+ * Therefore, the first and last days of a week year may have
+ * different calendar year values.
+ *
+ * <p>For example, January 1, 1998 is a Thursday. If {@code
+ * getFirstDayOfWeek()} is {@code MONDAY} and {@code
+ * getMinimalDaysInFirstWeek()} is 4 (ISO 8601 standard compatible
+ * setting), then week 1 of 1998 starts on December 29, 1997, and ends
+ * on January 4, 1998. The week year is 1998 for the last three days
+ * of calendar year 1997. If, however, {@code getFirstDayOfWeek()} is
+ * {@code SUNDAY}, then week 1 of 1998 starts on January 4, 1998, and
+ * ends on January 10, 1998; the first three days of 1998 then are
+ * part of week 53 of 1997 and their week year is 1997.
+ *
+ * <h4>Week Of Month</h4>
+ *
+ * <p>Values calculated for the <code>WEEK_OF_MONTH</code> field range from 0
+ * to 6.  Week 1 of a month (the days with <code>WEEK_OF_MONTH =
+ * 1</code>) is the earliest set of at least
+ * <code>getMinimalDaysInFirstWeek()</code> contiguous days in that month,
+ * ending on the day before <code>getFirstDayOfWeek()</code>.  Unlike
+ * week 1 of a year, week 1 of a month may be shorter than 7 days, need
+ * not start on <code>getFirstDayOfWeek()</code>, and will not include days of
+ * the previous month.  Days of a month before week 1 have a
+ * <code>WEEK_OF_MONTH</code> of 0.
+ *
+ * <p>For example, if <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>
+ * and <code>getMinimalDaysInFirstWeek()</code> is 4, then the first week of
+ * January 1998 is Sunday, January 4 through Saturday, January 10.  These days
+ * have a <code>WEEK_OF_MONTH</code> of 1.  Thursday, January 1 through
+ * Saturday, January 3 have a <code>WEEK_OF_MONTH</code> of 0.  If
+ * <code>getMinimalDaysInFirstWeek()</code> is changed to 3, then January 1
+ * through January 3 have a <code>WEEK_OF_MONTH</code> of 1.
+ *
+ * <h4>Default Fields Values</h4>
+ *
+ * <p>The <code>clear</code> method sets calendar field(s)
+ * undefined. <code>GregorianCalendar</code> uses the following
+ * default value for each calendar field if its value is undefined.
+ *
+ * <table cellpadding="0" cellspacing="3" border="0"
+ *        summary="GregorianCalendar default field values"
+ *        style="text-align: left; width: 66%;">
+ *   <tbody>
+ *     <tr>
+ *       <th style="vertical-align: top; background-color: rgb(204, 204, 255);
+ *           text-align: center;">Field<br>
+ *       </th>
+ *       <th style="vertical-align: top; background-color: rgb(204, 204, 255);
+ *           text-align: center;">Default Value<br>
+ *       </th>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle;">
+ *              <code>ERA<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle;">
+ *              <code>AD<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
+ *              <code>YEAR<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
+ *              <code>1970<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle;">
+ *              <code>MONTH<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle;">
+ *              <code>JANUARY<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *              <code>DAY_OF_MONTH<br></code>
+ *       </td>
+ *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *              <code>1<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle;">
+ *              <code>DAY_OF_WEEK<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle;">
+ *              <code>the first day of week<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *              <code>WEEK_OF_MONTH<br></code>
+ *       </td>
+ *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *              <code>0<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: top;">
+ *              <code>DAY_OF_WEEK_IN_MONTH<br></code>
+ *       </td>
+ *       <td style="vertical-align: top;">
+ *              <code>1<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
+ *              <code>AM_PM<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
+ *              <code>AM<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle;">
+ *              <code>HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle;">
+ *              <code>0<br></code>
+ *       </td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ * <br>Default values are not applicable for the fields not listed above.
+ *
+ * <p>
+ * <strong>Example:</strong>
+ * <blockquote>
+ * <pre>
+ * // get the supported ids for GMT-08:00 (Pacific Standard Time)
+ * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
+ * // if no ids were returned, something is wrong. get out.
+ * if (ids.length == 0)
+ *     System.exit(0);
+ *
+ *  // begin output
+ * System.out.println("Current Time");
+ *
+ * // create a Pacific Standard Time time zone
+ * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
+ *
+ * // set up rules for Daylight Saving Time
+ * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
+ * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
+ *
+ * // create a GregorianCalendar with the Pacific Daylight time zone
+ * // and the current date and time
+ * Calendar calendar = new GregorianCalendar(pdt);
+ * Date trialTime = new Date();
+ * calendar.setTime(trialTime);
+ *
+ * // print out a bunch of interesting things
+ * System.out.println("ERA: " + calendar.get(Calendar.ERA));
+ * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
+ * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
+ * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
+ * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
+ * System.out.println("DATE: " + calendar.get(Calendar.DATE));
+ * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
+ * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
+ * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
+ * System.out.println("DAY_OF_WEEK_IN_MONTH: "
+ *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
+ * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
+ * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
+ * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
+ * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
+ * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
+ * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
+ * System.out.println("ZONE_OFFSET: "
+ *                    + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
+ * System.out.println("DST_OFFSET: "
+ *                    + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
+
+ * System.out.println("Current Time, with hour reset to 3");
+ * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
+ * calendar.set(Calendar.HOUR, 3);
+ * System.out.println("ERA: " + calendar.get(Calendar.ERA));
+ * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
+ * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
+ * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
+ * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
+ * System.out.println("DATE: " + calendar.get(Calendar.DATE));
+ * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
+ * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
+ * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
+ * System.out.println("DAY_OF_WEEK_IN_MONTH: "
+ *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
+ * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
+ * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
+ * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
+ * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
+ * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
+ * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
+ * System.out.println("ZONE_OFFSET: "
+ *        + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
+ * System.out.println("DST_OFFSET: "
+ *        + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
+ * </pre>
+ * </blockquote>
+ *
+ * @see          TimeZone
+ * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
+ * @since JDK1.1
+ */
+public class GregorianCalendar extends Calendar {
+    /*
+     * Implementation Notes
+     *
+     * The epoch is the number of days or milliseconds from some defined
+     * starting point. The epoch for java.util.Date is used here; that is,
+     * milliseconds from January 1, 1970 (Gregorian), midnight UTC.  Other
+     * epochs which are used are January 1, year 1 (Gregorian), which is day 1
+     * of the Gregorian calendar, and December 30, year 0 (Gregorian), which is
+     * day 1 of the Julian calendar.
+     *
+     * We implement the proleptic Julian and Gregorian calendars.  This means we
+     * implement the modern definition of the calendar even though the
+     * historical usage differs.  For example, if the Gregorian change is set
+     * to new Date(Long.MIN_VALUE), we have a pure Gregorian calendar which
+     * labels dates preceding the invention of the Gregorian calendar in 1582 as
+     * if the calendar existed then.
+     *
+     * Likewise, with the Julian calendar, we assume a consistent
+     * 4-year leap year rule, even though the historical pattern of
+     * leap years is irregular, being every 3 years from 45 BCE
+     * through 9 BCE, then every 4 years from 8 CE onwards, with no
+     * leap years in-between.  Thus date computations and functions
+     * such as isLeapYear() are not intended to be historically
+     * accurate.
+     */
+
+//////////////////
+// Class Variables
+//////////////////
+
+    /**
+     * Value of the <code>ERA</code> field indicating
+     * the period before the common era (before Christ), also known as BCE.
+     * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
+     * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
+     *
+     * @see #ERA
+     */
+    public static final int BC = 0;
+
+    /**
+     * Value of the {@link #ERA} field indicating
+     * the period before the common era, the same value as {@link #BC}.
+     *
+     * @see #CE
+     */
+    static final int BCE = 0;
+
+    /**
+     * Value of the <code>ERA</code> field indicating
+     * the common era (Anno Domini), also known as CE.
+     * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
+     * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
+     *
+     * @see #ERA
+     */
+    public static final int AD = 1;
+
+    /**
+     * Value of the {@link #ERA} field indicating
+     * the common era, the same value as {@link #AD}.
+     *
+     * @see #BCE
+     */
+    static final int CE = 1;
+
+    private static final int EPOCH_OFFSET   = 719163; // Fixed date of January 1, 1970 (Gregorian)
+    private static final int EPOCH_YEAR     = 1970;
+
+    static final int MONTH_LENGTH[]
+        = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
+    static final int LEAP_MONTH_LENGTH[]
+        = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
+
+    // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
+    // into ints, they must be longs in order to prevent arithmetic overflow
+    // when performing (bug 4173516).
+    private static final int  ONE_SECOND = 1000;
+    private static final int  ONE_MINUTE = 60*ONE_SECOND;
+    private static final int  ONE_HOUR   = 60*ONE_MINUTE;
+    private static final long ONE_DAY    = 24*ONE_HOUR;
+    private static final long ONE_WEEK   = 7*ONE_DAY;
+
+    /*
+     * <pre>
+     *                            Greatest       Least
+     * Field name        Minimum   Minimum     Maximum     Maximum
+     * ----------        -------   -------     -------     -------
+     * ERA                     0         0           1           1
+     * YEAR                    1         1   292269054   292278994
+     * MONTH                   0         0          11          11
+     * WEEK_OF_YEAR            1         1          52*         53
+     * WEEK_OF_MONTH           0         0           4*          6
+     * DAY_OF_MONTH            1         1          28*         31
+     * DAY_OF_YEAR             1         1         365*        366
+     * DAY_OF_WEEK             1         1           7           7
+     * DAY_OF_WEEK_IN_MONTH   -1        -1           4*          6
+     * AM_PM                   0         0           1           1
+     * HOUR                    0         0          11          11
+     * HOUR_OF_DAY             0         0          23          23
+     * MINUTE                  0         0          59          59
+     * SECOND                  0         0          59          59
+     * MILLISECOND             0         0         999         999
+     * ZONE_OFFSET        -13:00    -13:00       14:00       14:00
+     * DST_OFFSET           0:00      0:00        0:20        2:00
+     * </pre>
+     * *: depends on the Gregorian change date
+     */
+    static final int MIN_VALUES[] = {
+        BCE,            // ERA
+        1,              // YEAR
+        JANUARY,        // MONTH
+        1,              // WEEK_OF_YEAR
+        0,              // WEEK_OF_MONTH
+        1,              // DAY_OF_MONTH
+        1,              // DAY_OF_YEAR
+        SUNDAY,         // DAY_OF_WEEK
+        1,              // DAY_OF_WEEK_IN_MONTH
+        AM,             // AM_PM
+        0,              // HOUR
+        0,              // HOUR_OF_DAY
+        0,              // MINUTE
+        0,              // SECOND
+        0,              // MILLISECOND
+        -13*ONE_HOUR,   // ZONE_OFFSET (UNIX compatibility)
+        0               // DST_OFFSET
+    };
+    static final int LEAST_MAX_VALUES[] = {
+        CE,             // ERA
+        292269054,      // YEAR
+        DECEMBER,       // MONTH
+        52,             // WEEK_OF_YEAR
+        4,              // WEEK_OF_MONTH
+        28,             // DAY_OF_MONTH
+        365,            // DAY_OF_YEAR
+        SATURDAY,       // DAY_OF_WEEK
+        4,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        20*ONE_MINUTE   // DST_OFFSET (historical least maximum)
+    };
+    static final int MAX_VALUES[] = {
+        CE,             // ERA
+        292278994,      // YEAR
+        DECEMBER,       // MONTH
+        53,             // WEEK_OF_YEAR
+        6,              // WEEK_OF_MONTH
+        31,             // DAY_OF_MONTH
+        366,            // DAY_OF_YEAR
+        SATURDAY,       // DAY_OF_WEEK
+        6,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        2*ONE_HOUR      // DST_OFFSET (double summer time)
+    };
+
+    // Proclaim serialization compatibility with JDK 1.1
+    @SuppressWarnings("FieldNameHidesFieldInSuperclass")
+    static final long serialVersionUID = -8125100834729963327L;
+
+    // Reference to the sun.util.calendar.Gregorian instance (singleton).
+    private static final Gregorian gcal =
+                                CalendarSystem.getGregorianCalendar();
+
+    // Reference to the JulianCalendar instance (singleton), set as needed. See
+    // getJulianCalendarSystem().
+    private static JulianCalendar jcal;
+
+    // JulianCalendar eras. See getJulianCalendarSystem().
+    private static Era[] jeras;
+
+    // The default value of gregorianCutover.
+    static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
+
+/////////////////////
+// Instance Variables
+/////////////////////
+
+    /**
+     * The point at which the Gregorian calendar rules are used, measured in
+     * milliseconds from the standard epoch.  Default is October 15, 1582
+     * (Gregorian) 00:00:00 UTC or -12219292800000L.  For this value, October 4,
+     * 1582 (Julian) is followed by October 15, 1582 (Gregorian).  This
+     * corresponds to Julian day number 2299161.
+     * @serial
+     */
+    private long gregorianCutover = DEFAULT_GREGORIAN_CUTOVER;
+
+    /**
+     * The fixed date of the gregorianCutover.
+     */
+    private transient long gregorianCutoverDate =
+        (((DEFAULT_GREGORIAN_CUTOVER + 1)/ONE_DAY) - 1) + EPOCH_OFFSET; // == 577736
+
+    /**
+     * The normalized year of the gregorianCutover in Gregorian, with
+     * 0 representing 1 BCE, -1 representing 2 BCE, etc.
+     */
+    private transient int gregorianCutoverYear = 1582;
+
+    /**
+     * The normalized year of the gregorianCutover in Julian, with 0
+     * representing 1 BCE, -1 representing 2 BCE, etc.
+     */
+    private transient int gregorianCutoverYearJulian = 1582;
+
+    /**
+     * gdate always has a sun.util.calendar.Gregorian.Date instance to
+     * avoid overhead of creating it. The assumption is that most
+     * applications will need only Gregorian calendar calculations.
+     */
+    private transient BaseCalendar.Date gdate;
+
+    /**
+     * Reference to either gdate or a JulianCalendar.Date
+     * instance. After calling complete(), this value is guaranteed to
+     * be set.
+     */
+    private transient BaseCalendar.Date cdate;
+
+    /**
+     * The CalendarSystem used to calculate the date in cdate. After
+     * calling complete(), this value is guaranteed to be set and
+     * consistent with the cdate value.
+     */
+    private transient BaseCalendar calsys;
+
+    /**
+     * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
+     * the GMT offset value and zoneOffsets[1] gets the DST saving
+     * value.
+     */
+    private transient int[] zoneOffsets;
+
+    /**
+     * Temporary storage for saving original fields[] values in
+     * non-lenient mode.
+     */
+    private transient int[] originalFields;
+
+///////////////
+// Constructors
+///////////////
+
+    /**
+     * Constructs a default <code>GregorianCalendar</code> using the current time
+     * in the default time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     */
+    public GregorianCalendar() {
+        this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
+        setZoneShared(true);
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> based on the current time
+     * in the given time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     *
+     * @param zone the given time zone.
+     */
+    public GregorianCalendar(TimeZone zone) {
+        this(zone, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> based on the current time
+     * in the default time zone with the given locale.
+     *
+     * @param aLocale the given locale.
+     */
+    public GregorianCalendar(Locale aLocale) {
+        this(TimeZone.getDefaultRef(), aLocale);
+        setZoneShared(true);
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> based on the current time
+     * in the given time zone with the given locale.
+     *
+     * @param zone the given time zone.
+     * @param aLocale the given locale.
+     */
+    public GregorianCalendar(TimeZone zone, Locale aLocale) {
+        super(zone, aLocale);
+        gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
+        setTimeInMillis(System.currentTimeMillis());
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> with the given date set
+     * in the default time zone with the default locale.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
+     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth) {
+        this(year, month, dayOfMonth, 0, 0, 0, 0);
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> with the given date
+     * and time set for the default time zone with the default locale.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
+     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
+     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
+     * in the calendar.
+     * @param minute the value used to set the <code>MINUTE</code> calendar field
+     * in the calendar.
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
+                             int minute) {
+        this(year, month, dayOfMonth, hourOfDay, minute, 0, 0);
+    }
+
+    /**
+     * Constructs a GregorianCalendar with the given date
+     * and time set for the default time zone with the default locale.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
+     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
+     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
+     * in the calendar.
+     * @param minute the value used to set the <code>MINUTE</code> calendar field
+     * in the calendar.
+     * @param second the value used to set the <code>SECOND</code> calendar field
+     * in the calendar.
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
+                             int minute, int second) {
+        this(year, month, dayOfMonth, hourOfDay, minute, second, 0);
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> with the given date
+     * and time set for the default time zone with the default locale.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
+     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
+     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
+     * in the calendar.
+     * @param minute the value used to set the <code>MINUTE</code> calendar field
+     * in the calendar.
+     * @param second the value used to set the <code>SECOND</code> calendar field
+     * in the calendar.
+     * @param millis the value used to set the <code>MILLISECOND</code> calendar field
+     */
+    GregorianCalendar(int year, int month, int dayOfMonth,
+                      int hourOfDay, int minute, int second, int millis) {
+        super();
+        gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
+        this.set(YEAR, year);
+        this.set(MONTH, month);
+        this.set(DAY_OF_MONTH, dayOfMonth);
+
+        // Set AM_PM and HOUR here to set their stamp values before
+        // setting HOUR_OF_DAY (6178071).
+        if (hourOfDay >= 12 && hourOfDay <= 23) {
+            // If hourOfDay is a valid PM hour, set the correct PM values
+            // so that it won't throw an exception in case it's set to
+            // non-lenient later.
+            this.internalSet(AM_PM, PM);
+            this.internalSet(HOUR, hourOfDay - 12);
+        } else {
+            // The default value for AM_PM is AM.
+            // We don't care any out of range value here for leniency.
+            this.internalSet(HOUR, hourOfDay);
+        }
+        // The stamp values of AM_PM and HOUR must be COMPUTED. (6440854)
+        setFieldsComputed(HOUR_MASK|AM_PM_MASK);
+
+        this.set(HOUR_OF_DAY, hourOfDay);
+        this.set(MINUTE, minute);
+        this.set(SECOND, second);
+        // should be changed to set() when this constructor is made
+        // public.
+        this.internalSet(MILLISECOND, millis);
+    }
+
+    /**
+     * Constructs an empty GregorianCalendar.
+     *
+     * @param zone    the given time zone
+     * @param locale the given locale
+     * @param flag    the flag requesting an empty instance
+     */
+    GregorianCalendar(TimeZone zone, Locale locale, boolean flag) {
+        super(zone, locale);
+        gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
+    }
+
+    // BEGIN Android-added
+    GregorianCalendar(long milliseconds) {
+        this();
+        setTimeInMillis(milliseconds);
+    }
+    // END Android-added
+
+/////////////////
+// Public methods
+/////////////////
+
+    /**
+     * Sets the <code>GregorianCalendar</code> change date. This is the point when the switch
+     * from Julian dates to Gregorian dates occurred. Default is October 15,
+     * 1582 (Gregorian). Previous to this, dates will be in the Julian calendar.
+     * <p>
+     * To obtain a pure Julian calendar, set the change date to
+     * <code>Date(Long.MAX_VALUE)</code>.  To obtain a pure Gregorian calendar,
+     * set the change date to <code>Date(Long.MIN_VALUE)</code>.
+     *
+     * @param date the given Gregorian cutover date.
+     */
+    public void setGregorianChange(Date date) {
+        long cutoverTime = date.getTime();
+        if (cutoverTime == gregorianCutover) {
+            return;
+        }
+        // Before changing the cutover date, make sure to have the
+        // time of this calendar.
+        complete();
+        setGregorianChange(cutoverTime);
+    }
+
+    private void setGregorianChange(long cutoverTime) {
+        gregorianCutover = cutoverTime;
+        gregorianCutoverDate = CalendarUtils.floorDivide(cutoverTime, ONE_DAY)
+                                + EPOCH_OFFSET;
+
+        // To provide the "pure" Julian calendar as advertised.
+        // Strictly speaking, the last millisecond should be a
+        // Gregorian date. However, the API doc specifies that setting
+        // the cutover date to Long.MAX_VALUE will make this calendar
+        // a pure Julian calendar. (See 4167995)
+        if (cutoverTime == Long.MAX_VALUE) {
+            gregorianCutoverDate++;
+        }
+
+        BaseCalendar.Date d = getGregorianCutoverDate();
+
+        // Set the cutover year (in the Gregorian year numbering)
+        gregorianCutoverYear = d.getYear();
+
+        BaseCalendar julianCal = getJulianCalendarSystem();
+        d = (BaseCalendar.Date) julianCal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        julianCal.getCalendarDateFromFixedDate(d, gregorianCutoverDate - 1);
+        gregorianCutoverYearJulian = d.getNormalizedYear();
+
+        if (time < gregorianCutover) {
+            // The field values are no longer valid under the new
+            // cutover date.
+            setUnnormalized();
+        }
+    }
+
+    /**
+     * Gets the Gregorian Calendar change date.  This is the point when the
+     * switch from Julian dates to Gregorian dates occurred. Default is
+     * October 15, 1582 (Gregorian). Previous to this, dates will be in the Julian
+     * calendar.
+     *
+     * @return the Gregorian cutover date for this <code>GregorianCalendar</code> object.
+     */
+    public final Date getGregorianChange() {
+        return new Date(gregorianCutover);
+    }
+
+    /**
+     * Determines if the given year is a leap year. Returns <code>true</code> if
+     * the given year is a leap year. To specify BC year numbers,
+     * <code>1 - year number</code> must be given. For example, year BC 4 is
+     * specified as -3.
+     *
+     * @param year the given year.
+     * @return <code>true</code> if the given year is a leap year; <code>false</code> otherwise.
+     */
+    public boolean isLeapYear(int year) {
+        if ((year & 3) != 0) {
+            return false;
+        }
+
+        if (year > gregorianCutoverYear) {
+            return (year%100 != 0) || (year%400 == 0); // Gregorian
+        }
+        if (year < gregorianCutoverYearJulian) {
+            return true; // Julian
+        }
+        boolean gregorian;
+        // If the given year is the Gregorian cutover year, we need to
+        // determine which calendar system to be applied to February in the year.
+        if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+            BaseCalendar.Date d = getCalendarDate(gregorianCutoverDate); // Gregorian
+            gregorian = d.getMonth() < BaseCalendar.MARCH;
+        } else {
+            gregorian = year == gregorianCutoverYear;
+        }
+        return gregorian ? (year%100 != 0) || (year%400 == 0) : true;
+    }
+
+    /**
+     * Returns {@code "gregory"} as the calendar type.
+     *
+     * @return {@code "gregory"}
+     * @since 1.8
+     */
+    @Override
+    public String getCalendarType() {
+        return "gregory";
+    }
+
+    /**
+     * Compares this <code>GregorianCalendar</code> to the specified
+     * <code>Object</code>. The result is <code>true</code> if and
+     * only if the argument is a <code>GregorianCalendar</code> object
+     * that represents the same time value (millisecond offset from
+     * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
+     * <code>Calendar</code> parameters and Gregorian change date as
+     * this object.
+     *
+     * @param obj the object to compare with.
+     * @return <code>true</code> if this object is equal to <code>obj</code>;
+     * <code>false</code> otherwise.
+     * @see Calendar#compareTo(Calendar)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof GregorianCalendar &&
+            super.equals(obj) &&
+            gregorianCutover == ((GregorianCalendar)obj).gregorianCutover;
+    }
+
+    /**
+     * Generates the hash code for this <code>GregorianCalendar</code> object.
+     */
+    @Override
+    public int hashCode() {
+        return super.hashCode() ^ (int)gregorianCutoverDate;
+    }
+
+    /**
+     * Adds the specified (signed) amount of time to the given calendar field,
+     * based on the calendar's rules.
+     *
+     * <p><em>Add rule 1</em>. The value of <code>field</code>
+     * after the call minus the value of <code>field</code> before the
+     * call is <code>amount</code>, modulo any overflow that has occurred in
+     * <code>field</code>. Overflow occurs when a field value exceeds its
+     * range and, as a result, the next larger field is incremented or
+     * decremented and the field value is adjusted back into its range.</p>
+     *
+     * <p><em>Add rule 2</em>. If a smaller field is expected to be
+     * invariant, but it is impossible for it to be equal to its
+     * prior value because of changes in its minimum or maximum after
+     * <code>field</code> is changed, then its value is adjusted to be as close
+     * as possible to its expected value. A smaller field represents a
+     * smaller unit of time. <code>HOUR</code> is a smaller field than
+     * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
+     * that are not expected to be invariant. The calendar system
+     * determines what fields are expected to be invariant.</p>
+     *
+     * @param field the calendar field.
+     * @param amount the amount of date or time to be added to the field.
+     * @exception IllegalArgumentException if <code>field</code> is
+     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     */
+    @Override
+    public void add(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;   // Do nothing!
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        if (field == YEAR) {
+            int year = internalGet(YEAR);
+            if (internalGetEra() == CE) {
+                year += amount;
+                if (year > 0) {
+                    set(YEAR, year);
+                } else { // year <= 0
+                    set(YEAR, 1 - year);
+                    // if year == 0, you get 1 BCE.
+                    set(ERA, BCE);
+                }
+            }
+            else { // era == BCE
+                year -= amount;
+                if (year > 0) {
+                    set(YEAR, year);
+                } else { // year <= 0
+                    set(YEAR, 1 - year);
+                    // if year == 0, you get 1 CE
+                    set(ERA, CE);
+                }
+            }
+            pinDayOfMonth();
+        } else if (field == MONTH) {
+            int month = internalGet(MONTH) + amount;
+            int year = internalGet(YEAR);
+            int y_amount;
+
+            if (month >= 0) {
+                y_amount = month/12;
+            } else {
+                y_amount = (month+1)/12 - 1;
+            }
+            if (y_amount != 0) {
+                if (internalGetEra() == CE) {
+                    year += y_amount;
+                    if (year > 0) {
+                        set(YEAR, year);
+                    } else { // year <= 0
+                        set(YEAR, 1 - year);
+                        // if year == 0, you get 1 BCE
+                        set(ERA, BCE);
+                    }
+                }
+                else { // era == BCE
+                    year -= y_amount;
+                    if (year > 0) {
+                        set(YEAR, year);
+                    } else { // year <= 0
+                        set(YEAR, 1 - year);
+                        // if year == 0, you get 1 CE
+                        set(ERA, CE);
+                    }
+                }
+            }
+
+            if (month >= 0) {
+                set(MONTH,  month % 12);
+            } else {
+                // month < 0
+                month %= 12;
+                if (month < 0) {
+                    month += 12;
+                }
+                set(MONTH, JANUARY + month);
+            }
+            pinDayOfMonth();
+        } else if (field == ERA) {
+            int era = internalGet(ERA) + amount;
+            if (era < 0) {
+                era = 0;
+            }
+            if (era > 1) {
+                era = 1;
+            }
+            set(ERA, era);
+        } else {
+            long delta = amount;
+            long timeOfDay = 0;
+            switch (field) {
+            // Handle the time fields here. Convert the given
+            // amount to milliseconds and call setTimeInMillis.
+            case HOUR:
+            case HOUR_OF_DAY:
+                delta *= 60 * 60 * 1000;        // hours to minutes
+                break;
+
+            case MINUTE:
+                delta *= 60 * 1000;             // minutes to seconds
+                break;
+
+            case SECOND:
+                delta *= 1000;                  // seconds to milliseconds
+                break;
+
+            case MILLISECOND:
+                break;
+
+            // Handle week, day and AM_PM fields which involves
+            // time zone offset change adjustment. Convert the
+            // given amount to the number of days.
+            case WEEK_OF_YEAR:
+            case WEEK_OF_MONTH:
+            case DAY_OF_WEEK_IN_MONTH:
+                delta *= 7;
+                break;
+
+            case DAY_OF_MONTH: // synonym of DATE
+            case DAY_OF_YEAR:
+            case DAY_OF_WEEK:
+                break;
+
+            case AM_PM:
+                // Convert the amount to the number of days (delta)
+                // and +12 or -12 hours (timeOfDay).
+                delta = amount / 2;
+                timeOfDay = 12 * (amount % 2);
+                break;
+            }
+
+            // The time fields don't require time zone offset change
+            // adjustment.
+            if (field >= HOUR) {
+                setTimeInMillis(time + delta);
+                return;
+            }
+
+            // The rest of the fields (week, day or AM_PM fields)
+            // require time zone offset (both GMT and DST) change
+            // adjustment.
+
+            // Translate the current time to the fixed date and time
+            // of the day.
+            long fd = getCurrentFixedDate();
+            timeOfDay += internalGet(HOUR_OF_DAY);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(MINUTE);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(SECOND);
+            timeOfDay *= 1000;
+            timeOfDay += internalGet(MILLISECOND);
+            if (timeOfDay >= ONE_DAY) {
+                fd++;
+                timeOfDay -= ONE_DAY;
+            } else if (timeOfDay < 0) {
+                fd--;
+                timeOfDay += ONE_DAY;
+            }
+
+            fd += delta; // fd is the expected fixed date after the calculation
+            // BEGIN Android-changed: time zone related calculation via helper methods
+            // Calculate the time in the UTC time zone.
+            long utcTime = (fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
+
+            // Neither of the time zone related fields are relevant because they have not been
+            // set since the call to complete() above.
+            int tzMask = 0;
+
+            // Adjust the time to account for zone and daylight savings time offset.
+            long millis = adjustForZoneAndDaylightSavingsTime(tzMask, utcTime, getZone());
+
+            // Update the time and recompute the fields.
+            setTimeInMillis(millis);
+            // END Android-changed: time zone related calculation via helper methods
+        }
+    }
+
+    /**
+     * Adds or subtracts (up/down) a single unit of time on the given time
+     * field without changing larger fields.
+     * <p>
+     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
+     * originally set to December 31, 1999. Calling {@link #roll(int,boolean) roll(Calendar.MONTH, true)}
+     * sets the calendar to January 31, 1999.  The <code>YEAR</code> field is unchanged
+     * because it is a larger field than <code>MONTH</code>.</p>
+     *
+     * @param up indicates if the value of the specified calendar field is to be
+     * rolled up or rolled down. Use <code>true</code> if rolling up, <code>false</code> otherwise.
+     * @exception IllegalArgumentException if <code>field</code> is
+     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     * @see #add(int,int)
+     * @see #set(int,int)
+     */
+    @Override
+    public void roll(int field, boolean up) {
+        roll(field, up ? +1 : -1);
+    }
+
+    /**
+     * Adds a signed amount to the specified calendar field without changing larger fields.
+     * A negative roll amount means to subtract from field without changing
+     * larger fields. If the specified amount is 0, this method performs nothing.
+     *
+     * <p>This method calls {@link #complete()} before adding the
+     * amount so that all the calendar fields are normalized. If there
+     * is any calendar field having an out-of-range value in non-lenient mode, then an
+     * <code>IllegalArgumentException</code> is thrown.
+     *
+     * <p>
+     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
+     * originally set to August 31, 1999. Calling <code>roll(Calendar.MONTH,
+     * 8)</code> sets the calendar to April 30, <strong>1999</strong>. Using a
+     * <code>GregorianCalendar</code>, the <code>DAY_OF_MONTH</code> field cannot
+     * be 31 in the month April. <code>DAY_OF_MONTH</code> is set to the closest possible
+     * value, 30. The <code>YEAR</code> field maintains the value of 1999 because it
+     * is a larger field than <code>MONTH</code>.
+     * <p>
+     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
+     * originally set to Sunday June 6, 1999. Calling
+     * <code>roll(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
+     * Tuesday June 1, 1999, whereas calling
+     * <code>add(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
+     * Sunday May 30, 1999. This is because the roll rule imposes an
+     * additional constraint: The <code>MONTH</code> must not change when the
+     * <code>WEEK_OF_MONTH</code> is rolled. Taken together with add rule 1,
+     * the resultant date must be between Tuesday June 1 and Saturday June
+     * 5. According to add rule 2, the <code>DAY_OF_WEEK</code>, an invariant
+     * when changing the <code>WEEK_OF_MONTH</code>, is set to Tuesday, the
+     * closest possible value to Sunday (where Sunday is the first day of the
+     * week).</p>
+     *
+     * @param field the calendar field.
+     * @param amount the signed amount to add to <code>field</code>.
+     * @exception IllegalArgumentException if <code>field</code> is
+     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     * @see #roll(int,boolean)
+     * @see #add(int,int)
+     * @see #set(int,int)
+     * @since 1.2
+     */
+    @Override
+    public void roll(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        int min = getMinimum(field);
+        int max = getMaximum(field);
+
+        switch (field) {
+        case AM_PM:
+        case ERA:
+        case YEAR:
+        case MINUTE:
+        case SECOND:
+        case MILLISECOND:
+            // These fields are handled simply, since they have fixed minima
+            // and maxima.  The field DAY_OF_MONTH is almost as simple.  Other
+            // fields are complicated, since the range within they must roll
+            // varies depending on the date.
+            break;
+
+        case HOUR:
+        case HOUR_OF_DAY:
+            {
+                int unit = max + 1; // 12 or 24 hours
+                int h = internalGet(field);
+                int nh = (h + amount) % unit;
+                if (nh < 0) {
+                    nh += unit;
+                }
+                time += ONE_HOUR * (nh - h);
+
+                // The day might have changed, which could happen if
+                // the daylight saving time transition brings it to
+                // the next day, although it's very unlikely. But we
+                // have to make sure not to change the larger fields.
+                CalendarDate d = calsys.getCalendarDate(time, getZone());
+                if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
+                    d.setDate(internalGet(YEAR),
+                              internalGet(MONTH) + 1,
+                              internalGet(DAY_OF_MONTH));
+                    if (field == HOUR) {
+                        assert (internalGet(AM_PM) == PM);
+                        d.addHours(+12); // restore PM
+                    }
+                    time = calsys.getTime(d);
+                }
+                int hourOfDay = d.getHours();
+                internalSet(field, hourOfDay % unit);
+                if (field == HOUR) {
+                    internalSet(HOUR_OF_DAY, hourOfDay);
+                } else {
+                    internalSet(AM_PM, hourOfDay / 12);
+                    internalSet(HOUR, hourOfDay % 12);
+                }
+
+                // Time zone offset and/or daylight saving might have changed.
+                int zoneOffset = d.getZoneOffset();
+                int saving = d.getDaylightSaving();
+                internalSet(ZONE_OFFSET, zoneOffset - saving);
+                internalSet(DST_OFFSET, saving);
+                return;
+            }
+
+        case MONTH:
+            // Rolling the month involves both pinning the final value to [0, 11]
+            // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
+            // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
+            // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
+            {
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    int mon = (internalGet(MONTH) + amount) % 12;
+                    if (mon < 0) {
+                        mon += 12;
+                    }
+                    set(MONTH, mon);
+
+                    // Keep the day of month in the range.  We don't want to spill over
+                    // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
+                    // mar3.
+                    int monthLen = monthLength(mon);
+                    if (internalGet(DAY_OF_MONTH) > monthLen) {
+                        set(DAY_OF_MONTH, monthLen);
+                    }
+                } else {
+                    // We need to take care of different lengths in
+                    // year and month due to the cutover.
+                    int yearLength = getActualMaximum(MONTH) + 1;
+                    int mon = (internalGet(MONTH) + amount) % yearLength;
+                    if (mon < 0) {
+                        mon += yearLength;
+                    }
+                    set(MONTH, mon);
+                    int monthLen = getActualMaximum(DAY_OF_MONTH);
+                    if (internalGet(DAY_OF_MONTH) > monthLen) {
+                        set(DAY_OF_MONTH, monthLen);
+                    }
+                }
+                return;
+            }
+
+        case WEEK_OF_YEAR:
+            {
+                int y = cdate.getNormalizedYear();
+                max = getActualMaximum(WEEK_OF_YEAR);
+                set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
+                int woy = internalGet(WEEK_OF_YEAR);
+                int value = woy + amount;
+                if (!isCutoverYear(y)) {
+                    int weekYear = getWeekYear();
+                    if (weekYear == y) {
+                        // If the new value is in between min and max
+                        // (exclusive), then we can use the value.
+                        if (value > min && value < max) {
+                            set(WEEK_OF_YEAR, value);
+                            return;
+                        }
+                        long fd = getCurrentFixedDate();
+                        // Make sure that the min week has the current DAY_OF_WEEK
+                        // in the calendar year
+                        long day1 = fd - (7 * (woy - min));
+                        if (calsys.getYearFromFixedDate(day1) != y) {
+                            min++;
+                        }
+
+                        // Make sure the same thing for the max week
+                        fd += 7 * (max - internalGet(WEEK_OF_YEAR));
+                        if (calsys.getYearFromFixedDate(fd) != y) {
+                            max--;
+                        }
+                    } else {
+                        // When WEEK_OF_YEAR and YEAR are out of sync,
+                        // adjust woy and amount to stay in the calendar year.
+                        if (weekYear > y) {
+                            if (amount < 0) {
+                                amount++;
+                            }
+                            woy = max;
+                        } else {
+                            if (amount > 0) {
+                                amount -= woy - max;
+                            }
+                            woy = min;
+                        }
+                    }
+                    set(field, getRolledValue(woy, amount, min, max));
+                    return;
+                }
+
+                // Handle cutover here.
+                long fd = getCurrentFixedDate();
+                BaseCalendar cal;
+                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+                    cal = getCutoverCalendarSystem();
+                } else if (y == gregorianCutoverYear) {
+                    cal = gcal;
+                } else {
+                    cal = getJulianCalendarSystem();
+                }
+                long day1 = fd - (7 * (woy - min));
+                // Make sure that the min week has the current DAY_OF_WEEK
+                if (cal.getYearFromFixedDate(day1) != y) {
+                    min++;
+                }
+
+                // Make sure the same thing for the max week
+                fd += 7 * (max - woy);
+                cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
+                if (cal.getYearFromFixedDate(fd) != y) {
+                    max--;
+                }
+                // value: the new WEEK_OF_YEAR which must be converted
+                // to month and day of month.
+                value = getRolledValue(woy, amount, min, max) - 1;
+                BaseCalendar.Date d = getCalendarDate(day1 + value * 7);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case WEEK_OF_MONTH:
+            {
+                boolean isCutoverYear = isCutoverYear(cdate.getNormalizedYear());
+                // dow: relative day of week from first day of week
+                int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
+                if (dow < 0) {
+                    dow += 7;
+                }
+
+                long fd = getCurrentFixedDate();
+                long month1;     // fixed date of the first day (usually 1) of the month
+                int monthLength; // actual month length
+                if (isCutoverYear) {
+                    month1 = getFixedDateMonth1(cdate, fd);
+                    monthLength = actualMonthLength();
+                } else {
+                    month1 = fd - internalGet(DAY_OF_MONTH) + 1;
+                    monthLength = calsys.getMonthLength(cdate);
+                }
+
+                // the first day of week of the month.
+                long monthDay1st = BaseCalendar.getDayOfWeekDateOnOrBefore(month1 + 6,
+                                                                           getFirstDayOfWeek());
+                // if the week has enough days to form a week, the
+                // week starts from the previous month.
+                if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
+                    monthDay1st -= 7;
+                }
+                max = getActualMaximum(field);
+
+                // value: the new WEEK_OF_MONTH value
+                int value = getRolledValue(internalGet(field), amount, 1, max) - 1;
+
+                // nfd: fixed date of the rolled date
+                long nfd = monthDay1st + value * 7 + dow;
+
+                // Unlike WEEK_OF_YEAR, we need to change day of week if the
+                // nfd is out of the month.
+                if (nfd < month1) {
+                    nfd = month1;
+                } else if (nfd >= (month1 + monthLength)) {
+                    nfd = month1 + monthLength - 1;
+                }
+                int dayOfMonth;
+                if (isCutoverYear) {
+                    // If we are in the cutover year, convert nfd to
+                    // its calendar date and use dayOfMonth.
+                    BaseCalendar.Date d = getCalendarDate(nfd);
+                    dayOfMonth = d.getDayOfMonth();
+                } else {
+                    dayOfMonth = (int)(nfd - month1) + 1;
+                }
+                set(DAY_OF_MONTH, dayOfMonth);
+                return;
+            }
+
+        case DAY_OF_MONTH:
+            {
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    max = calsys.getMonthLength(cdate);
+                    break;
+                }
+
+                // Cutover year handling
+                long fd = getCurrentFixedDate();
+                long month1 = getFixedDateMonth1(cdate, fd);
+                // It may not be a regular month. Convert the date and range to
+                // the relative values, perform the roll, and
+                // convert the result back to the rolled date.
+                int value = getRolledValue((int)(fd - month1), amount, 0, actualMonthLength() - 1);
+                BaseCalendar.Date d = getCalendarDate(month1 + value);
+                assert d.getMonth()-1 == internalGet(MONTH);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_YEAR:
+            {
+                max = getActualMaximum(field);
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    break;
+                }
+
+                // Handle cutover here.
+                long fd = getCurrentFixedDate();
+                long jan1 = fd - internalGet(DAY_OF_YEAR) + 1;
+                int value = getRolledValue((int)(fd - jan1) + 1, amount, min, max);
+                BaseCalendar.Date d = getCalendarDate(jan1 + value - 1);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK:
+            {
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    // If the week of year is in the same year, we can
+                    // just change DAY_OF_WEEK.
+                    int weekOfYear = internalGet(WEEK_OF_YEAR);
+                    if (weekOfYear > 1 && weekOfYear < 52) {
+                        set(WEEK_OF_YEAR, weekOfYear); // update stamp[WEEK_OF_YEAR]
+                        max = SATURDAY;
+                        break;
+                    }
+                }
+
+                // We need to handle it in a different way around year
+                // boundaries and in the cutover year. Note that
+                // changing era and year values violates the roll
+                // rule: not changing larger calendar fields...
+                amount %= 7;
+                if (amount == 0) {
+                    return;
+                }
+                long fd = getCurrentFixedDate();
+                long dowFirst = BaseCalendar.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
+                fd += amount;
+                if (fd < dowFirst) {
+                    fd += 7;
+                } else if (fd >= dowFirst + 7) {
+                    fd -= 7;
+                }
+                BaseCalendar.Date d = getCalendarDate(fd);
+                set(ERA, (d.getNormalizedYear() <= 0 ? BCE : CE));
+                set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK_IN_MONTH:
+            {
+                min = 1; // after normalized, min should be 1.
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    int dom = internalGet(DAY_OF_MONTH);
+                    int monthLength = calsys.getMonthLength(cdate);
+                    int lastDays = monthLength % 7;
+                    max = monthLength / 7;
+                    int x = (dom - 1) % 7;
+                    if (x < lastDays) {
+                        max++;
+                    }
+                    set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
+                    break;
+                }
+
+                // Cutover year handling
+                long fd = getCurrentFixedDate();
+                long month1 = getFixedDateMonth1(cdate, fd);
+                int monthLength = actualMonthLength();
+                int lastDays = monthLength % 7;
+                max = monthLength / 7;
+                int x = (int)(fd - month1) % 7;
+                if (x < lastDays) {
+                    max++;
+                }
+                int value = getRolledValue(internalGet(field), amount, min, max) - 1;
+                fd = month1 + value * 7 + x;
+                BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
+                BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                cal.getCalendarDateFromFixedDate(d, fd);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+        }
+
+        set(field, getRolledValue(internalGet(field), amount, min, max));
+    }
+
+    /**
+     * Returns the minimum value for the given calendar field of this
+     * <code>GregorianCalendar</code> instance. The minimum value is
+     * defined as the smallest value returned by the {@link
+     * Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the minimum value for the given calendar field.
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getMinimum(int field) {
+        return MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the maximum value for the given calendar field of this
+     * <code>GregorianCalendar</code> instance. The maximum value is
+     * defined as the largest value returned by the {@link
+     * Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getMaximum(int field) {
+        switch (field) {
+        case MONTH:
+        case DAY_OF_MONTH:
+        case DAY_OF_YEAR:
+        case WEEK_OF_YEAR:
+        case WEEK_OF_MONTH:
+        case DAY_OF_WEEK_IN_MONTH:
+        case YEAR:
+            {
+                // On or after Gregorian 200-3-1, Julian and Gregorian
+                // calendar dates are the same or Gregorian dates are
+                // larger (i.e., there is a "gap") after 300-3-1.
+                if (gregorianCutoverYear > 200) {
+                    break;
+                }
+                // There might be "overlapping" dates.
+                GregorianCalendar gc = (GregorianCalendar) clone();
+                gc.setLenient(true);
+                gc.setTimeInMillis(gregorianCutover);
+                int v1 = gc.getActualMaximum(field);
+                gc.setTimeInMillis(gregorianCutover-1);
+                int v2 = gc.getActualMaximum(field);
+                return Math.max(MAX_VALUES[field], Math.max(v1, v2));
+            }
+        }
+        return MAX_VALUES[field];
+    }
+
+    /**
+     * Returns the highest minimum value for the given calendar field
+     * of this <code>GregorianCalendar</code> instance. The highest
+     * minimum value is defined as the largest value returned by
+     * {@link #getActualMinimum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the highest minimum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getGreatestMinimum(int field) {
+        if (field == DAY_OF_MONTH) {
+            BaseCalendar.Date d = getGregorianCutoverDate();
+            long mon1 = getFixedDateMonth1(d, gregorianCutoverDate);
+            d = getCalendarDate(mon1);
+            return Math.max(MIN_VALUES[field], d.getDayOfMonth());
+        }
+        return MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the lowest maximum value for the given calendar field
+     * of this <code>GregorianCalendar</code> instance. The lowest
+     * maximum value is defined as the smallest value returned by
+     * {@link #getActualMaximum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field
+     * @return the lowest maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getLeastMaximum(int field) {
+        switch (field) {
+        case MONTH:
+        case DAY_OF_MONTH:
+        case DAY_OF_YEAR:
+        case WEEK_OF_YEAR:
+        case WEEK_OF_MONTH:
+        case DAY_OF_WEEK_IN_MONTH:
+        case YEAR:
+            {
+                GregorianCalendar gc = (GregorianCalendar) clone();
+                gc.setLenient(true);
+                gc.setTimeInMillis(gregorianCutover);
+                int v1 = gc.getActualMaximum(field);
+                gc.setTimeInMillis(gregorianCutover-1);
+                int v2 = gc.getActualMaximum(field);
+                return Math.min(LEAST_MAX_VALUES[field], Math.min(v1, v2));
+            }
+        }
+        return LEAST_MAX_VALUES[field];
+    }
+
+    /**
+     * Returns the minimum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * <p>For example, if the Gregorian change date is January 10,
+     * 1970 and the date of this <code>GregorianCalendar</code> is
+     * January 20, 1970, the actual minimum value of the
+     * <code>DAY_OF_MONTH</code> field is 10 because the previous date
+     * of January 10, 1970 is December 27, 1996 (in the Julian
+     * calendar). Therefore, December 28, 1969 to January 9, 1970
+     * don't exist.
+     *
+     * @param field the calendar field
+     * @return the minimum of the given field for the time value of
+     * this <code>GregorianCalendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMaximum(int)
+     * @since 1.2
+     */
+    @Override
+    public int getActualMinimum(int field) {
+        if (field == DAY_OF_MONTH) {
+            GregorianCalendar gc = getNormalizedCalendar();
+            int year = gc.cdate.getNormalizedYear();
+            if (year == gregorianCutoverYear || year == gregorianCutoverYearJulian) {
+                long month1 = getFixedDateMonth1(gc.cdate, gc.calsys.getFixedDate(gc.cdate));
+                BaseCalendar.Date d = getCalendarDate(month1);
+                return d.getDayOfMonth();
+            }
+        }
+        return getMinimum(field);
+    }
+
+    /**
+     * Returns the maximum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     * For example, if the date of this instance is February 1, 2004,
+     * the actual maximum value of the <code>DAY_OF_MONTH</code> field
+     * is 29 because 2004 is a leap year, and if the date of this
+     * instance is February 1, 2005, it's 28.
+     *
+     * <p>This method calculates the maximum value of {@link
+     * Calendar#WEEK_OF_YEAR WEEK_OF_YEAR} based on the {@link
+     * Calendar#YEAR YEAR} (calendar year) value, not the <a
+     * href="#week_year">week year</a>. Call {@link
+     * #getWeeksInWeekYear()} to get the maximum value of {@code
+     * WEEK_OF_YEAR} in the week year of this {@code GregorianCalendar}.
+     *
+     * @param field the calendar field
+     * @return the maximum of the given field for the time value of
+     * this <code>GregorianCalendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @since 1.2
+     */
+    @Override
+    public int getActualMaximum(int field) {
+        final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
+            HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
+            ZONE_OFFSET_MASK|DST_OFFSET_MASK;
+        if ((fieldsForFixedMax & (1<<field)) != 0) {
+            return getMaximum(field);
+        }
+
+        GregorianCalendar gc = getNormalizedCalendar();
+        BaseCalendar.Date date = gc.cdate;
+        BaseCalendar cal = gc.calsys;
+        int normalizedYear = date.getNormalizedYear();
+
+        int value = -1;
+        switch (field) {
+        case MONTH:
+            {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    value = DECEMBER;
+                    break;
+                }
+
+                // January 1 of the next year may or may not exist.
+                long nextJan1;
+                do {
+                    nextJan1 = gcal.getFixedDate(++normalizedYear, BaseCalendar.JANUARY, 1, null);
+                } while (nextJan1 < gregorianCutoverDate);
+                BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
+                cal.getCalendarDateFromFixedDate(d, nextJan1 - 1);
+                value = d.getMonth() - 1;
+            }
+            break;
+
+        case DAY_OF_MONTH:
+            {
+                value = cal.getMonthLength(date);
+                if (!gc.isCutoverYear(normalizedYear) || date.getDayOfMonth() == value) {
+                    break;
+                }
+
+                // Handle cutover year.
+                long fd = gc.getCurrentFixedDate();
+                if (fd >= gregorianCutoverDate) {
+                    break;
+                }
+                int monthLength = gc.actualMonthLength();
+                long monthEnd = gc.getFixedDateMonth1(gc.cdate, fd) + monthLength - 1;
+                // Convert the fixed date to its calendar date.
+                BaseCalendar.Date d = gc.getCalendarDate(monthEnd);
+                value = d.getDayOfMonth();
+            }
+            break;
+
+        case DAY_OF_YEAR:
+            {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    value = cal.getYearLength(date);
+                    break;
+                }
+
+                // Handle cutover year.
+                long jan1;
+                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+                    BaseCalendar cocal = gc.getCutoverCalendarSystem();
+                    jan1 = cocal.getFixedDate(normalizedYear, 1, 1, null);
+                } else if (normalizedYear == gregorianCutoverYearJulian) {
+                    jan1 = cal.getFixedDate(normalizedYear, 1, 1, null);
+                } else {
+                    jan1 = gregorianCutoverDate;
+                }
+                // January 1 of the next year may or may not exist.
+                long nextJan1 = gcal.getFixedDate(++normalizedYear, 1, 1, null);
+                if (nextJan1 < gregorianCutoverDate) {
+                    nextJan1 = gregorianCutoverDate;
+                }
+                assert jan1 <= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
+                                                date.getDayOfMonth(), date);
+                assert nextJan1 >= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
+                                                date.getDayOfMonth(), date);
+                value = (int)(nextJan1 - jan1);
+            }
+            break;
+
+        case WEEK_OF_YEAR:
+            {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    // Get the day of week of January 1 of the year
+                    CalendarDate d = cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                    d.setDate(date.getYear(), BaseCalendar.JANUARY, 1);
+                    int dayOfWeek = cal.getDayOfWeek(d);
+                    // Normalize the day of week with the firstDayOfWeek value
+                    dayOfWeek -= getFirstDayOfWeek();
+                    if (dayOfWeek < 0) {
+                        dayOfWeek += 7;
+                    }
+                    value = 52;
+                    int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
+                    if ((magic == 6) ||
+                        (date.isLeapYear() && (magic == 5 || magic == 12))) {
+                        value++;
+                    }
+                    break;
+                }
+
+                if (gc == this) {
+                    gc = (GregorianCalendar) gc.clone();
+                }
+                int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
+                gc.set(DAY_OF_YEAR, maxDayOfYear);
+                value = gc.get(WEEK_OF_YEAR);
+                if (internalGet(YEAR) != gc.getWeekYear()) {
+                    gc.set(DAY_OF_YEAR, maxDayOfYear - 7);
+                    value = gc.get(WEEK_OF_YEAR);
+                }
+            }
+            break;
+
+        case WEEK_OF_MONTH:
+            {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    CalendarDate d = cal.newCalendarDate(null);
+                    d.setDate(date.getYear(), date.getMonth(), 1);
+                    int dayOfWeek = cal.getDayOfWeek(d);
+                    int monthLength = cal.getMonthLength(d);
+                    dayOfWeek -= getFirstDayOfWeek();
+                    if (dayOfWeek < 0) {
+                        dayOfWeek += 7;
+                    }
+                    int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
+                    value = 3;
+                    if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
+                        value++;
+                    }
+                    monthLength -= nDaysFirstWeek + 7 * 3;
+                    if (monthLength > 0) {
+                        value++;
+                        if (monthLength > 7) {
+                            value++;
+                        }
+                    }
+                    break;
+                }
+
+                // Cutover year handling
+                if (gc == this) {
+                    gc = (GregorianCalendar) gc.clone();
+                }
+                int y = gc.internalGet(YEAR);
+                int m = gc.internalGet(MONTH);
+                do {
+                    value = gc.get(WEEK_OF_MONTH);
+                    gc.add(WEEK_OF_MONTH, +1);
+                } while (gc.get(YEAR) == y && gc.get(MONTH) == m);
+            }
+            break;
+
+        case DAY_OF_WEEK_IN_MONTH:
+            {
+                // may be in the Gregorian cutover month
+                int ndays, dow1;
+                int dow = date.getDayOfWeek();
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
+                    ndays = cal.getMonthLength(d);
+                    d.setDayOfMonth(1);
+                    cal.normalize(d);
+                    dow1 = d.getDayOfWeek();
+                } else {
+                    // Let a cloned GregorianCalendar take care of the cutover cases.
+                    if (gc == this) {
+                        gc = (GregorianCalendar) clone();
+                    }
+                    ndays = gc.actualMonthLength();
+                    gc.set(DAY_OF_MONTH, gc.getActualMinimum(DAY_OF_MONTH));
+                    dow1 = gc.get(DAY_OF_WEEK);
+                }
+                int x = dow - dow1;
+                if (x < 0) {
+                    x += 7;
+                }
+                ndays -= x;
+                value = (ndays + 6) / 7;
+            }
+            break;
+
+        case YEAR:
+            /* The year computation is no different, in principle, from the
+             * others, however, the range of possible maxima is large.  In
+             * addition, the way we know we've exceeded the range is different.
+             * For these reasons, we use the special case code below to handle
+             * this field.
+             *
+             * The actual maxima for YEAR depend on the type of calendar:
+             *
+             *     Gregorian = May 17, 292275056 BCE - Aug 17, 292278994 CE
+             *     Julian    = Dec  2, 292269055 BCE - Jan  3, 292272993 CE
+             *     Hybrid    = Dec  2, 292269055 BCE - Aug 17, 292278994 CE
+             *
+             * We know we've exceeded the maximum when either the month, date,
+             * time, or era changes in response to setting the year.  We don't
+             * check for month, date, and time here because the year and era are
+             * sufficient to detect an invalid year setting.  NOTE: If code is
+             * added to check the month and date in the future for some reason,
+             * Feb 29 must be allowed to shift to Mar 1 when setting the year.
+             */
+            {
+                if (gc == this) {
+                    gc = (GregorianCalendar) clone();
+                }
+
+                // Calculate the millisecond offset from the beginning
+                // of the year of this calendar and adjust the max
+                // year value if we are beyond the limit in the max
+                // year.
+                long current = gc.getYearOffsetInMillis();
+
+                if (gc.internalGetEra() == CE) {
+                    gc.setTimeInMillis(Long.MAX_VALUE);
+                    value = gc.get(YEAR);
+                    long maxEnd = gc.getYearOffsetInMillis();
+                    if (current > maxEnd) {
+                        value--;
+                    }
+                } else {
+                    CalendarSystem mincal = gc.getTimeInMillis() >= gregorianCutover ?
+                        gcal : getJulianCalendarSystem();
+                    CalendarDate d = mincal.getCalendarDate(Long.MIN_VALUE, getZone());
+                    long maxEnd = (cal.getDayOfYear(d) - 1) * 24 + d.getHours();
+                    maxEnd *= 60;
+                    maxEnd += d.getMinutes();
+                    maxEnd *= 60;
+                    maxEnd += d.getSeconds();
+                    maxEnd *= 1000;
+                    maxEnd += d.getMillis();
+                    value = d.getYear();
+                    if (value <= 0) {
+                        assert mincal == gcal;
+                        value = 1 - value;
+                    }
+                    if (current < maxEnd) {
+                        value--;
+                    }
+                }
+            }
+            break;
+
+        default:
+            throw new ArrayIndexOutOfBoundsException(field);
+        }
+        return value;
+    }
+
+    /**
+     * Returns the millisecond offset from the beginning of this
+     * year. This Calendar object must have been normalized.
+     */
+    private long getYearOffsetInMillis() {
+        long t = (internalGet(DAY_OF_YEAR) - 1) * 24;
+        t += internalGet(HOUR_OF_DAY);
+        t *= 60;
+        t += internalGet(MINUTE);
+        t *= 60;
+        t += internalGet(SECOND);
+        t *= 1000;
+        return t + internalGet(MILLISECOND) -
+            (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET));
+    }
+
+    @Override
+    public Object clone()
+    {
+        GregorianCalendar other = (GregorianCalendar) super.clone();
+
+        other.gdate = (BaseCalendar.Date) gdate.clone();
+        if (cdate != null) {
+            if (cdate != gdate) {
+                other.cdate = (BaseCalendar.Date) cdate.clone();
+            } else {
+                other.cdate = other.gdate;
+            }
+        }
+        other.originalFields = null;
+        other.zoneOffsets = null;
+        return other;
+    }
+
+    @Override
+    public TimeZone getTimeZone() {
+        TimeZone zone = super.getTimeZone();
+        // To share the zone by CalendarDates
+        gdate.setZone(zone);
+        if (cdate != null && cdate != gdate) {
+            cdate.setZone(zone);
+        }
+        return zone;
+    }
+
+    @Override
+    public void setTimeZone(TimeZone zone) {
+        super.setTimeZone(zone);
+        // To share the zone by CalendarDates
+        gdate.setZone(zone);
+        if (cdate != null && cdate != gdate) {
+            cdate.setZone(zone);
+        }
+    }
+
+    /**
+     * Returns {@code true} indicating this {@code GregorianCalendar}
+     * supports week dates.
+     *
+     * @return {@code true} (always)
+     * @see #getWeekYear()
+     * @see #setWeekDate(int,int,int)
+     * @see #getWeeksInWeekYear()
+     * @since 1.7
+     */
+    @Override
+    public final boolean isWeekDateSupported() {
+        return true;
+    }
+
+    /**
+     * Returns the <a href="#week_year">week year</a> represented by this
+     * {@code GregorianCalendar}. The dates in the weeks between 1 and the
+     * maximum week number of the week year have the same week year value
+     * that may be one year before or after the {@link Calendar#YEAR YEAR}
+     * (calendar year) value.
+     *
+     * <p>This method calls {@link Calendar#complete()} before
+     * calculating the week year.
+     *
+     * @return the week year represented by this {@code GregorianCalendar}.
+     *         If the {@link Calendar#ERA ERA} value is {@link #BC}, the year is
+     *         represented by 0 or a negative number: BC 1 is 0, BC 2
+     *         is -1, BC 3 is -2, and so on.
+     * @throws IllegalArgumentException
+     *         if any of the calendar fields is invalid in non-lenient mode.
+     * @see #isWeekDateSupported()
+     * @see #getWeeksInWeekYear()
+     * @see Calendar#getFirstDayOfWeek()
+     * @see Calendar#getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    @Override
+    public int getWeekYear() {
+        int year = get(YEAR); // implicitly calls complete()
+        if (internalGetEra() == BCE) {
+            year = 1 - year;
+        }
+
+        // Fast path for the Gregorian calendar years that are never
+        // affected by the Julian-Gregorian transition
+        if (year > gregorianCutoverYear + 1) {
+            int weekOfYear = internalGet(WEEK_OF_YEAR);
+            if (internalGet(MONTH) == JANUARY) {
+                if (weekOfYear >= 52) {
+                    --year;
+                }
+            } else {
+                if (weekOfYear == 1) {
+                    ++year;
+                }
+            }
+            return year;
+        }
+
+        // General (slow) path
+        int dayOfYear = internalGet(DAY_OF_YEAR);
+        int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
+        int minimalDays = getMinimalDaysInFirstWeek();
+
+        // Quickly check the possibility of year adjustments before
+        // cloning this GregorianCalendar.
+        if (dayOfYear > minimalDays && dayOfYear < (maxDayOfYear - 6)) {
+            return year;
+        }
+
+        // Create a clone to work on the calculation
+        GregorianCalendar cal = (GregorianCalendar) clone();
+        cal.setLenient(true);
+        // Use GMT so that intermediate date calculations won't
+        // affect the time of day fields.
+        cal.setTimeZone(TimeZone.getTimeZone("GMT"));
+        // Go to the first day of the year, which is usually January 1.
+        cal.set(DAY_OF_YEAR, 1);
+        cal.complete();
+
+        // Get the first day of the first day-of-week in the year.
+        int delta = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
+        if (delta != 0) {
+            if (delta < 0) {
+                delta += 7;
+            }
+            cal.add(DAY_OF_YEAR, delta);
+        }
+        int minDayOfYear = cal.get(DAY_OF_YEAR);
+        if (dayOfYear < minDayOfYear) {
+            if (minDayOfYear <= minimalDays) {
+                --year;
+            }
+        } else {
+            cal.set(YEAR, year + 1);
+            cal.set(DAY_OF_YEAR, 1);
+            cal.complete();
+            int del = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
+            if (del != 0) {
+                if (del < 0) {
+                    del += 7;
+                }
+                cal.add(DAY_OF_YEAR, del);
+            }
+            minDayOfYear = cal.get(DAY_OF_YEAR) - 1;
+            if (minDayOfYear == 0) {
+                minDayOfYear = 7;
+            }
+            if (minDayOfYear >= minimalDays) {
+                int days = maxDayOfYear - dayOfYear + 1;
+                if (days <= (7 - minDayOfYear)) {
+                    ++year;
+                }
+            }
+        }
+        return year;
+    }
+
+    /**
+     * Sets this {@code GregorianCalendar} to the date given by the
+     * date specifiers - <a href="#week_year">{@code weekYear}</a>,
+     * {@code weekOfYear}, and {@code dayOfWeek}. {@code weekOfYear}
+     * follows the <a href="#week_and_year">{@code WEEK_OF_YEAR}
+     * numbering</a>.  The {@code dayOfWeek} value must be one of the
+     * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} values: {@link
+     * Calendar#SUNDAY SUNDAY} to {@link Calendar#SATURDAY SATURDAY}.
+     *
+     * <p>Note that the numeric day-of-week representation differs from
+     * the ISO 8601 standard, and that the {@code weekOfYear}
+     * numbering is compatible with the standard when {@code
+     * getFirstDayOfWeek()} is {@code MONDAY} and {@code
+     * getMinimalDaysInFirstWeek()} is 4.
+     *
+     * <p>Unlike the {@code set} method, all of the calendar fields
+     * and the instant of time value are calculated upon return.
+     *
+     * <p>If {@code weekOfYear} is out of the valid week-of-year
+     * range in {@code weekYear}, the {@code weekYear}
+     * and {@code weekOfYear} values are adjusted in lenient
+     * mode, or an {@code IllegalArgumentException} is thrown in
+     * non-lenient mode.
+     *
+     * @param weekYear    the week year
+     * @param weekOfYear  the week number based on {@code weekYear}
+     * @param dayOfWeek   the day of week value: one of the constants
+     *                    for the {@link #DAY_OF_WEEK DAY_OF_WEEK} field:
+     *                    {@link Calendar#SUNDAY SUNDAY}, ...,
+     *                    {@link Calendar#SATURDAY SATURDAY}.
+     * @exception IllegalArgumentException
+     *            if any of the given date specifiers is invalid,
+     *            or if any of the calendar fields are inconsistent
+     *            with the given date specifiers in non-lenient mode
+     * @see GregorianCalendar#isWeekDateSupported()
+     * @see Calendar#getFirstDayOfWeek()
+     * @see Calendar#getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    @Override
+    public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
+        if (dayOfWeek < SUNDAY || dayOfWeek > SATURDAY) {
+            throw new IllegalArgumentException("invalid dayOfWeek: " + dayOfWeek);
+        }
+
+        // To avoid changing the time of day fields by date
+        // calculations, use a clone with the GMT time zone.
+        GregorianCalendar gc = (GregorianCalendar) clone();
+        gc.setLenient(true);
+        int era = gc.get(ERA);
+        gc.clear();
+        gc.setTimeZone(TimeZone.getTimeZone("GMT"));
+        gc.set(ERA, era);
+        gc.set(YEAR, weekYear);
+        gc.set(WEEK_OF_YEAR, 1);
+        gc.set(DAY_OF_WEEK, getFirstDayOfWeek());
+        int days = dayOfWeek - getFirstDayOfWeek();
+        if (days < 0) {
+            days += 7;
+        }
+        days += 7 * (weekOfYear - 1);
+        if (days != 0) {
+            gc.add(DAY_OF_YEAR, days);
+        } else {
+            gc.complete();
+        }
+
+        if (!isLenient() &&
+            (gc.getWeekYear() != weekYear
+             || gc.internalGet(WEEK_OF_YEAR) != weekOfYear
+             || gc.internalGet(DAY_OF_WEEK) != dayOfWeek)) {
+            throw new IllegalArgumentException();
+        }
+
+        set(ERA, gc.internalGet(ERA));
+        set(YEAR, gc.internalGet(YEAR));
+        set(MONTH, gc.internalGet(MONTH));
+        set(DAY_OF_MONTH, gc.internalGet(DAY_OF_MONTH));
+
+        // to avoid throwing an IllegalArgumentException in
+        // non-lenient, set WEEK_OF_YEAR internally
+        internalSet(WEEK_OF_YEAR, weekOfYear);
+        complete();
+    }
+
+    /**
+     * Returns the number of weeks in the <a href="#week_year">week year</a>
+     * represented by this {@code GregorianCalendar}.
+     *
+     * <p>For example, if this {@code GregorianCalendar}'s date is
+     * December 31, 2008 with <a href="#iso8601_compatible_setting">the ISO
+     * 8601 compatible setting</a>, this method will return 53 for the
+     * period: December 29, 2008 to January 3, 2010 while {@link
+     * #getActualMaximum(int) getActualMaximum(WEEK_OF_YEAR)} will return
+     * 52 for the period: December 31, 2007 to December 28, 2008.
+     *
+     * @return the number of weeks in the week year.
+     * @see Calendar#WEEK_OF_YEAR
+     * @see #getWeekYear()
+     * @see #getActualMaximum(int)
+     * @since 1.7
+     */
+    @Override
+    public int getWeeksInWeekYear() {
+        GregorianCalendar gc = getNormalizedCalendar();
+        int weekYear = gc.getWeekYear();
+        if (weekYear == gc.internalGet(YEAR)) {
+            return gc.getActualMaximum(WEEK_OF_YEAR);
+        }
+
+        // Use the 2nd week for calculating the max of WEEK_OF_YEAR
+        if (gc == this) {
+            gc = (GregorianCalendar) gc.clone();
+        }
+        gc.setWeekDate(weekYear, 2, internalGet(DAY_OF_WEEK));
+        return gc.getActualMaximum(WEEK_OF_YEAR);
+    }
+
+/////////////////////////////
+// Time => Fields computation
+/////////////////////////////
+
+    /**
+     * The fixed date corresponding to gdate. If the value is
+     * Long.MIN_VALUE, the fixed date value is unknown. Currently,
+     * Julian calendar dates are not cached.
+     */
+    transient private long cachedFixedDate = Long.MIN_VALUE;
+
+    /**
+     * Converts the time value (millisecond offset from the <a
+     * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
+     * The time is <em>not</em>
+     * recomputed first; to recompute the time, then the fields, call the
+     * <code>complete</code> method.
+     *
+     * @see Calendar#complete
+     */
+    @Override
+    protected void computeFields() {
+        int mask;
+        if (isPartiallyNormalized()) {
+            // Determine which calendar fields need to be computed.
+            mask = getSetStateFields();
+            int fieldMask = ~mask & ALL_FIELDS;
+            // We have to call computTime in case calsys == null in
+            // order to set calsys and cdate. (6263644)
+            if (fieldMask != 0 || calsys == null) {
+                mask |= computeFields(fieldMask,
+                                      mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
+                assert mask == ALL_FIELDS;
+            }
+        } else {
+            mask = ALL_FIELDS;
+            computeFields(mask, 0);
+        }
+        // After computing all the fields, set the field state to `COMPUTED'.
+        setFieldsComputed(mask);
+    }
+
+    /**
+     * This computeFields implements the conversion from UTC
+     * (millisecond offset from the Epoch) to calendar
+     * field values. fieldMask specifies which fields to change the
+     * setting state to COMPUTED, although all fields are set to
+     * the correct values. This is required to fix 4685354.
+     *
+     * @param fieldMask a bit mask to specify which fields to change
+     * the setting state.
+     * @param tzMask a bit mask to specify which time zone offset
+     * fields to be used for time calculations
+     * @return a new field mask that indicates what field values have
+     * actually been set.
+     */
+    private int computeFields(int fieldMask, int tzMask) {
+        int zoneOffset = 0;
+        TimeZone tz = getZone();
+        if (zoneOffsets == null) {
+            zoneOffsets = new int[2];
+        }
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            if (tz instanceof ZoneInfo) {
+                // BEGIN Android-changed: use libcore.util.ZoneInfo
+                // The method name to get offsets differs from sun.util.calendar.ZoneInfo
+                // zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
+                ZoneInfo zoneInfo = (ZoneInfo) tz;
+                zoneOffset = zoneInfo.getOffsetsByUtcTime(time, zoneOffsets);
+                // END Android-changed: use libcore.util.ZoneInfo
+            } else {
+                zoneOffset = tz.getOffset(time);
+                zoneOffsets[0] = tz.getRawOffset();
+                zoneOffsets[1] = zoneOffset - zoneOffsets[0];
+            }
+        }
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffsets[0] = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                zoneOffsets[1] = internalGet(DST_OFFSET);
+            }
+            zoneOffset = zoneOffsets[0] + zoneOffsets[1];
+        }
+
+        // By computing time and zoneOffset separately, we can take
+        // the wider range of time+zoneOffset than the previous
+        // implementation.
+        long fixedDate = zoneOffset / ONE_DAY;
+        int timeOfDay = zoneOffset % (int)ONE_DAY;
+        fixedDate += time / ONE_DAY;
+        timeOfDay += (int) (time % ONE_DAY);
+        if (timeOfDay >= ONE_DAY) {
+            timeOfDay -= ONE_DAY;
+            ++fixedDate;
+        } else {
+            while (timeOfDay < 0) {
+                timeOfDay += ONE_DAY;
+                --fixedDate;
+            }
+        }
+        fixedDate += EPOCH_OFFSET;
+
+        int era = CE;
+        int year;
+        if (fixedDate >= gregorianCutoverDate) {
+            // Handle Gregorian dates.
+            assert cachedFixedDate == Long.MIN_VALUE || gdate.isNormalized()
+                        : "cache control: not normalized";
+            assert cachedFixedDate == Long.MIN_VALUE ||
+                   gcal.getFixedDate(gdate.getNormalizedYear(),
+                                          gdate.getMonth(),
+                                          gdate.getDayOfMonth(), gdate)
+                                == cachedFixedDate
+                        : "cache control: inconsictency" +
+                          ", cachedFixedDate=" + cachedFixedDate +
+                          ", computed=" +
+                          gcal.getFixedDate(gdate.getNormalizedYear(),
+                                                 gdate.getMonth(),
+                                                 gdate.getDayOfMonth(),
+                                                 gdate) +
+                          ", date=" + gdate;
+
+            // See if we can use gdate to avoid date calculation.
+            if (fixedDate != cachedFixedDate) {
+                gcal.getCalendarDateFromFixedDate(gdate, fixedDate);
+                cachedFixedDate = fixedDate;
+            }
+
+            year = gdate.getYear();
+            if (year <= 0) {
+                year = 1 - year;
+                era = BCE;
+            }
+            calsys = gcal;
+            cdate = gdate;
+            assert cdate.getDayOfWeek() > 0 : "dow="+cdate.getDayOfWeek()+", date="+cdate;
+        } else {
+            // Handle Julian calendar dates.
+            calsys = getJulianCalendarSystem();
+            cdate = (BaseCalendar.Date) jcal.newCalendarDate(getZone());
+            jcal.getCalendarDateFromFixedDate(cdate, fixedDate);
+            Era e = cdate.getEra();
+            if (e == jeras[0]) {
+                era = BCE;
+            }
+            year = cdate.getYear();
+        }
+
+        // Always set the ERA and YEAR values.
+        internalSet(ERA, era);
+        internalSet(YEAR, year);
+        int mask = fieldMask | (ERA_MASK|YEAR_MASK);
+
+        int month =  cdate.getMonth() - 1; // 0-based
+        int dayOfMonth = cdate.getDayOfMonth();
+
+        // Set the basic date fields.
+        if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
+            != 0) {
+            internalSet(MONTH, month);
+            internalSet(DAY_OF_MONTH, dayOfMonth);
+            internalSet(DAY_OF_WEEK, cdate.getDayOfWeek());
+            mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
+        }
+
+        if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                          |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
+            if (timeOfDay != 0) {
+                int hours = timeOfDay / ONE_HOUR;
+                internalSet(HOUR_OF_DAY, hours);
+                internalSet(AM_PM, hours / 12); // Assume AM == 0
+                internalSet(HOUR, hours % 12);
+                int r = timeOfDay % ONE_HOUR;
+                internalSet(MINUTE, r / ONE_MINUTE);
+                r %= ONE_MINUTE;
+                internalSet(SECOND, r / ONE_SECOND);
+                internalSet(MILLISECOND, r % ONE_SECOND);
+            } else {
+                internalSet(HOUR_OF_DAY, 0);
+                internalSet(AM_PM, AM);
+                internalSet(HOUR, 0);
+                internalSet(MINUTE, 0);
+                internalSet(SECOND, 0);
+                internalSet(MILLISECOND, 0);
+            }
+            mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                     |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
+        }
+
+        if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
+            internalSet(ZONE_OFFSET, zoneOffsets[0]);
+            internalSet(DST_OFFSET, zoneOffsets[1]);
+            mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+        }
+
+        if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
+            int normalizedYear = cdate.getNormalizedYear();
+            long fixedDateJan1 = calsys.getFixedDate(normalizedYear, 1, 1, cdate);
+            int dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+            long fixedDateMonth1 = fixedDate - dayOfMonth + 1;
+            int cutoverGap = 0;
+            int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
+            int relativeDayOfMonth = dayOfMonth - 1;
+
+            // If we are in the cutover year, we need some special handling.
+            if (normalizedYear == cutoverYear) {
+                // Need to take care of the "missing" days.
+                if (gregorianCutoverYearJulian <= gregorianCutoverYear) {
+                    // We need to find out where we are. The cutover
+                    // gap could even be more than one year.  (One
+                    // year difference in ~48667 years.)
+                    fixedDateJan1 = getFixedDateJan1(cdate, fixedDate);
+                    if (fixedDate >= gregorianCutoverDate) {
+                        fixedDateMonth1 = getFixedDateMonth1(cdate, fixedDate);
+                    }
+                }
+                int realDayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+                cutoverGap = dayOfYear - realDayOfYear;
+                dayOfYear = realDayOfYear;
+                relativeDayOfMonth = (int)(fixedDate - fixedDateMonth1);
+            }
+            internalSet(DAY_OF_YEAR, dayOfYear);
+            internalSet(DAY_OF_WEEK_IN_MONTH, relativeDayOfMonth / 7 + 1);
+
+            int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
+
+            // The spec is to calculate WEEK_OF_YEAR in the
+            // ISO8601-style. This creates problems, though.
+            if (weekOfYear == 0) {
+                // If the date belongs to the last week of the
+                // previous year, use the week number of "12/31" of
+                // the "previous" year. Again, if the previous year is
+                // the Gregorian cutover year, we need to take care of
+                // it.  Usually the previous day of January 1 is
+                // December 31, which is not always true in
+                // GregorianCalendar.
+                long fixedDec31 = fixedDateJan1 - 1;
+                long prevJan1  = fixedDateJan1 - 365;
+                if (normalizedYear > (cutoverYear + 1)) {
+                    if (CalendarUtils.isGregorianLeapYear(normalizedYear - 1)) {
+                        --prevJan1;
+                    }
+                } else if (normalizedYear <= gregorianCutoverYearJulian) {
+                    if (CalendarUtils.isJulianLeapYear(normalizedYear - 1)) {
+                        --prevJan1;
+                    }
+                } else {
+                    BaseCalendar calForJan1 = calsys;
+                    //int prevYear = normalizedYear - 1;
+                    int prevYear = getCalendarDate(fixedDec31).getNormalizedYear();
+                    if (prevYear == gregorianCutoverYear) {
+                        calForJan1 = getCutoverCalendarSystem();
+                        if (calForJan1 == jcal) {
+                            prevJan1 = calForJan1.getFixedDate(prevYear,
+                                                               BaseCalendar.JANUARY,
+                                                               1,
+                                                               null);
+                        } else {
+                            prevJan1 = gregorianCutoverDate;
+                            calForJan1 = gcal;
+                        }
+                    } else if (prevYear <= gregorianCutoverYearJulian) {
+                        calForJan1 = getJulianCalendarSystem();
+                        prevJan1 = calForJan1.getFixedDate(prevYear,
+                                                           BaseCalendar.JANUARY,
+                                                           1,
+                                                           null);
+                    }
+                }
+                weekOfYear = getWeekNumber(prevJan1, fixedDec31);
+            } else {
+                if (normalizedYear > gregorianCutoverYear ||
+                    normalizedYear < (gregorianCutoverYearJulian - 1)) {
+                    // Regular years
+                    if (weekOfYear >= 52) {
+                        long nextJan1 = fixedDateJan1 + 365;
+                        if (cdate.isLeapYear()) {
+                            nextJan1++;
+                        }
+                        long nextJan1st = BaseCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                  getFirstDayOfWeek());
+                        int ndays = (int)(nextJan1st - nextJan1);
+                        if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                            // The first days forms a week in which the date is included.
+                            weekOfYear = 1;
+                        }
+                    }
+                } else {
+                    BaseCalendar calForJan1 = calsys;
+                    int nextYear = normalizedYear + 1;
+                    if (nextYear == (gregorianCutoverYearJulian + 1) &&
+                        nextYear < gregorianCutoverYear) {
+                        // In case the gap is more than one year.
+                        nextYear = gregorianCutoverYear;
+                    }
+                    if (nextYear == gregorianCutoverYear) {
+                        calForJan1 = getCutoverCalendarSystem();
+                    }
+
+                    long nextJan1;
+                    if (nextYear > gregorianCutoverYear
+                        || gregorianCutoverYearJulian == gregorianCutoverYear
+                        || nextYear == gregorianCutoverYearJulian) {
+                        nextJan1 = calForJan1.getFixedDate(nextYear,
+                                                           BaseCalendar.JANUARY,
+                                                           1,
+                                                           null);
+                    } else {
+                        nextJan1 = gregorianCutoverDate;
+                        calForJan1 = gcal;
+                    }
+
+                    long nextJan1st = BaseCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                              getFirstDayOfWeek());
+                    int ndays = (int)(nextJan1st - nextJan1);
+                    if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                        // The first days forms a week in which the date is included.
+                        weekOfYear = 1;
+                    }
+                }
+            }
+            internalSet(WEEK_OF_YEAR, weekOfYear);
+            internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
+            mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
+        }
+        return mask;
+    }
+
+    /**
+     * Returns the number of weeks in a period between fixedDay1 and
+     * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
+     * is applied to calculate the number of weeks.
+     *
+     * @param fixedDay1 the fixed date of the first day of the period
+     * @param fixedDate the fixed date of the last day of the period
+     * @return the number of weeks of the given period
+     */
+    private int getWeekNumber(long fixedDay1, long fixedDate) {
+        // We can always use `gcal' since Julian and Gregorian are the
+        // same thing for this calculation.
+        long fixedDay1st = Gregorian.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
+                                                                getFirstDayOfWeek());
+        int ndays = (int)(fixedDay1st - fixedDay1);
+        assert ndays <= 7;
+        if (ndays >= getMinimalDaysInFirstWeek()) {
+            fixedDay1st -= 7;
+        }
+        int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
+        if (normalizedDayOfPeriod >= 0) {
+            return normalizedDayOfPeriod / 7 + 1;
+        }
+        return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
+    }
+
+    /**
+     * Converts calendar field values to the time value (millisecond
+     * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
+     *
+     * @exception IllegalArgumentException if any calendar fields are invalid.
+     */
+    @Override
+    protected void computeTime() {
+        // In non-lenient mode, perform brief checking of calendar
+        // fields which have been set externally. Through this
+        // checking, the field values are stored in originalFields[]
+        // to see if any of them are normalized later.
+        if (!isLenient()) {
+            if (originalFields == null) {
+                originalFields = new int[FIELD_COUNT];
+            }
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                int value = internalGet(field);
+                if (isExternallySet(field)) {
+                    // Quick validation for any out of range values
+                    if (value < getMinimum(field) || value > getMaximum(field)) {
+                        throw new IllegalArgumentException(getFieldName(field));
+                    }
+                }
+                originalFields[field] = value;
+            }
+        }
+
+        // Let the super class determine which calendar fields to be
+        // used to calculate the time.
+        int fieldMask = selectFields();
+
+        // The year defaults to the epoch start. We don't check
+        // fieldMask for YEAR because YEAR is a mandatory field to
+        // determine the date.
+        int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
+
+        int era = internalGetEra();
+        if (era == BCE) {
+            year = 1 - year;
+        } else if (era != CE) {
+            // Even in lenient mode we disallow ERA values other than CE & BCE.
+            // (The same normalization rule as add()/roll() could be
+            // applied here in lenient mode. But this checking is kept
+            // unchanged for compatibility as of 1.5.)
+            throw new IllegalArgumentException("Invalid era");
+        }
+
+        // If year is 0 or negative, we need to set the ERA value later.
+        if (year <= 0 && !isSet(ERA)) {
+            fieldMask |= ERA_MASK;
+            setFieldsComputed(ERA_MASK);
+        }
+
+        // Calculate the time of day. We rely on the convention that
+        // an UNSET field has 0.
+        long timeOfDay = 0;
+        if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
+            timeOfDay += (long) internalGet(HOUR_OF_DAY);
+        } else {
+            timeOfDay += internalGet(HOUR);
+            // The default value of AM_PM is 0 which designates AM.
+            if (isFieldSet(fieldMask, AM_PM)) {
+                timeOfDay += 12 * internalGet(AM_PM);
+            }
+        }
+        timeOfDay *= 60;
+        timeOfDay += internalGet(MINUTE);
+        timeOfDay *= 60;
+        timeOfDay += internalGet(SECOND);
+        timeOfDay *= 1000;
+        timeOfDay += internalGet(MILLISECOND);
+
+        // Convert the time of day to the number of days and the
+        // millisecond offset from midnight.
+        long fixedDate = timeOfDay / ONE_DAY;
+        timeOfDay %= ONE_DAY;
+        while (timeOfDay < 0) {
+            timeOfDay += ONE_DAY;
+            --fixedDate;
+        }
+
+        // Calculate the fixed date since January 1, 1 (Gregorian).
+        calculateFixedDate: {
+            long gfd, jfd;
+            if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) {
+                gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
+                if (gfd >= gregorianCutoverDate) {
+                    fixedDate = gfd;
+                    break calculateFixedDate;
+                }
+                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
+            } else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) {
+                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
+                if (jfd < gregorianCutoverDate) {
+                    fixedDate = jfd;
+                    break calculateFixedDate;
+                }
+                gfd = jfd;
+            } else {
+                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
+                gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
+            }
+
+            // Now we have to determine which calendar date it is.
+
+            // If the date is relative from the beginning of the year
+            // in the Julian calendar, then use jfd;
+            if (isFieldSet(fieldMask, DAY_OF_YEAR) || isFieldSet(fieldMask, WEEK_OF_YEAR)) {
+                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+                    fixedDate = jfd;
+                    break calculateFixedDate;
+                } else if (year == gregorianCutoverYear) {
+                    fixedDate = gfd;
+                    break calculateFixedDate;
+                }
+            }
+
+            if (gfd >= gregorianCutoverDate) {
+                if (jfd >= gregorianCutoverDate) {
+                    fixedDate = gfd;
+                } else {
+                    // The date is in an "overlapping" period. No way
+                    // to disambiguate it. Determine it using the
+                    // previous date calculation.
+                    if (calsys == gcal || calsys == null) {
+                        fixedDate = gfd;
+                    } else {
+                        fixedDate = jfd;
+                    }
+                }
+            } else {
+                if (jfd < gregorianCutoverDate) {
+                    fixedDate = jfd;
+                } else {
+                    // The date is in a "missing" period.
+                    if (!isLenient()) {
+                        throw new IllegalArgumentException("the specified date doesn't exist");
+                    }
+                    // Take the Julian date for compatibility, which
+                    // will produce a Gregorian date.
+                    fixedDate = jfd;
+                }
+            }
+        }
+
+        // millis represents local wall-clock time in milliseconds.
+        long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
+
+        // Compute the time zone offset and DST offset.  There are two potential
+        // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
+        // for discussion purposes here.
+        // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
+        //    can be in standard or in DST depending.  However, 2:00 am is an invalid
+        //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
+        //    We assume standard time.
+        // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
+        //    can be in standard or DST.  Both are valid representations (the rep
+        //    jumps from 1:59:59 DST to 1:00:00 Std).
+        //    Again, we assume standard time.
+        // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
+        // or DST_OFFSET fields; then we use those fields.
+        TimeZone zone = getZone();
+        // BEGIN Android-changed: time zone related calculation via helper methods
+        int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+
+        millis = adjustForZoneAndDaylightSavingsTime(tzMask, millis, zone);
+        // END Android-changed: time zone related calculation via helper methods
+
+        // Set this calendar's time in milliseconds
+        time = millis;
+
+        int mask = computeFields(fieldMask | getSetStateFields(), tzMask);
+
+        if (!isLenient()) {
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                if (!isExternallySet(field)) {
+                    continue;
+                }
+                if (originalFields[field] != internalGet(field)) {
+                    String s = originalFields[field] + " -> " + internalGet(field);
+                    // Restore the original field values
+                    System.arraycopy(originalFields, 0, fields, 0, fields.length);
+                    throw new IllegalArgumentException(getFieldName(field) + ": " + s);
+                }
+            }
+        }
+        setFieldsNormalized(mask);
+    }
+
+    // BEGIN Android-added: helper methods for time zone related calculation
+    /**
+     * Calculates the time in milliseconds that this calendar represents using the UTC time,
+     * timezone information (specifically Daylight Savings Time (DST) rules, if any) and knowledge
+     * of what fields were explicitly set on the calendar.
+     *
+     * <p>A time is represented as the number of milliseconds since
+     * <i>1st January 1970 00:00:00.000 UTC</i>.
+     *
+     * <p>This uses the terms {@link SimpleTimeZone#STANDARD_TIME standard time},
+     * {@link SimpleTimeZone#WALL_TIME} wall time} and {@link SimpleTimeZone#UTC_TIME UTC time} as
+     * used in {@link SimpleTimeZone}. Specifically:
+     *
+     * <dl>
+     * <dt><b>UTC time</b></dt>
+     * <dd>This is the time within the UTC time zone. UTC does not support DST so the UTC time,
+     * standard time and wall time are all identical within the UTC time zone.</dd>
+     * <dt><b>standard time</b></dt>
+     * <dd>This is the local time within the time zone and is not affected by DST.</dd>
+     * <dt><b>wall time</b></dt>
+     * <dd>This is the local time within the time zone as shown on a wall clock. If the time zone
+     * supports DST then it will be the same as <b>standard time</b> when outside DST and it will
+     * differ (usually be an hour later) when inside DST. This is what the fields on the Calendar
+     * represent.</dd>
+     * </dl>
+     *
+     * <p>The {@code utcTimeInMillis} value supplied was calculated as if the fields represented
+     * a standard time in the {@code UTC} time zone. It is the value that would be returned by
+     * {@link #getTimeInMillis()} when called on this calendar if it was in UTC time zone. e.g. If
+     * the calendar was set to say <i>2014 March 19th 13:27.53 -08:00</i> then the value of
+     * {@code utcTimeInMillis} would be the value of {@link #getTimeInMillis()} when called on a
+     * calendar set to <i>2014 March 19th 13:27.53 -00:00</i>, note the time zone offset is set to
+     * 0.
+     *
+     * <p>To adjust from a UTC time in millis to the standard time in millis we must
+     * <em>subtract</em> the offset from UTC. e.g. given an offset of UTC-08:00, to convert
+     * "14:00 UTC" to "14:00 UTC-08:00" we must subtract -08:00 (i.e. add 8 hours). Another way to
+     * think about it is that 8 hours has to elapse after 14:00 UTC before it is 14:00 UTC-08:00.
+     *
+     * <p>As the zone offset can depend on the time and we cannot calculate the time properly until
+     * we know the time there is a bit of a catch-22. So, what this does is use the
+     * {@link TimeZone#getRawOffset() raw offset} to calculate a ballpark standard time and then
+     * uses that value to retrieve the appropriate zone and DST offsets from the time zone. They
+     * are then used to make the final wall time calculation.
+     *
+     * <p>The DST offset will need clearing if the standard time is not a valid wall clock. See
+     * {@link #adjustDstOffsetForInvalidWallClock(long, TimeZone, int)} for more information.
+     *
+     * @param tzMask the set of time zone related fields, i.e. {@link #ZONE_OFFSET_MASK} and
+     * {@link #DST_OFFSET_MASK}
+     * @param utcTimeInMillis the time in millis, calculated assuming the time zone was GMT.
+     * @param zone the actual time zone.
+     * @return the UTC time in millis after adjusting for zone and DST offset.
+     */
+    private long adjustForZoneAndDaylightSavingsTime(
+            int tzMask, long utcTimeInMillis, TimeZone zone) {
+
+        // The following don't actually need to be initialized because they are always set before
+        // they are used but the compiler cannot detect that.
+        int zoneOffset = 0;
+        int dstOffset = 0;
+
+        // If either of the ZONE_OFFSET or DST_OFFSET fields are not set then get the information
+        // from the TimeZone.
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            if (zoneOffsets == null) {
+                zoneOffsets = new int[2];
+            }
+            int gmtOffset = isFieldSet(tzMask, ZONE_OFFSET) ?
+                                internalGet(ZONE_OFFSET) : zone.getRawOffset();
+
+            // Calculate the standard time (no DST) in the supplied zone. This is a ballpark figure
+            // and not used in the final calculation as the offset used here may not be the same as
+            // the actual offset the time zone requires be used for this time. This is to handle
+            // situations like Honolulu, where its raw offset changed from GMT-10:30 to GMT-10:00
+            // in 1947. The TimeZone always uses a raw offset of -10:00 but will return -10:30
+            // for dates before the change over.
+            long standardTimeInZone = utcTimeInMillis - gmtOffset;
+
+            // Retrieve the correct zone and DST offsets from the time zone.
+            if (zone instanceof ZoneInfo) {
+                // Android-changed: libcore ZoneInfo uses different method to get offsets.
+                ZoneInfo zoneInfo = (ZoneInfo) zone;
+                zoneInfo.getOffsetsByUtcTime(standardTimeInZone, zoneOffsets);
+            } else {
+                zone.getOffsets(standardTimeInZone, zoneOffsets);
+            }
+            zoneOffset = zoneOffsets[0];
+            dstOffset = zoneOffsets[1];
+
+            // If necessary adjust the DST offset to handle an invalid wall clock sensibly.
+            dstOffset = adjustDstOffsetForInvalidWallClock(standardTimeInZone, zone, dstOffset);
+        }
+
+        // If either ZONE_OFFSET of DST_OFFSET fields are set then get the information from the
+        // fields, potentially overriding information from the TimeZone.
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffset = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                dstOffset = internalGet(DST_OFFSET);
+            }
+        }
+
+        // Adjust the time zone offset values to get the UTC time.
+        long standardTimeInZone = utcTimeInMillis - zoneOffset;
+        return standardTimeInZone - dstOffset;
+    }
+
+    /**
+     * If the supplied millis is in daylight savings time (DST) and is the result of an invalid
+     * wall clock then adjust the DST offset to ensure sensible behavior.
+     *
+     * <p>When transitioning into DST, i.e. when the clocks spring forward (usually by one hour)
+     * there is a wall clock period that is invalid, it literally doesn't exist. e.g. If clocks
+     * go forward one hour at 02:00 on 9th March 2014 (standard time) then the wall time of
+     * 02:00-02:59:59.999 is not a valid. The wall clock jumps straight from 01:59:59.999 to
+     * 03:00. The following table shows the relationship between the time in millis, the standard
+     * time and the wall time at the point of transitioning into DST. As can be seen there is no
+     * 02:00 in the wall time.
+     *
+     * <pre>
+     * Time In Millis - ......  x+1h .....  x+2h .....  x+3h
+     * Standard Time  - ...... 01:00 ..... 02:00 ..... 03:00 .....
+     * Wall Time      - ...... 01:00 ..... 03:00 ..... 04:00 .....
+     *                                       ^
+     *                                 02:00 missing
+     * </pre>
+     *
+     * <p>The calendar fields represent wall time. If the user sets the fields on the calendar so
+     * that it is in that invalid period then this code attempts to do something sensible. It
+     * treats 02:MM:SS.SSS as if it is {@code 01:MM:SS.SSS + 1 hour}. That makes sense from both
+     * the input calendar fields perspective and from the time in millis perspective. Of course the
+     * result of that is that when the time is formatted in that time zone that the time is
+     * actually 03:MM:SS.SSS.
+     *
+     * <pre>
+     * Wall Time      - ...... 01:00 ..... <b>02:00 .....</b> 03:00 ..... 04:00 .....
+     * Time In Millis - ......  x+1h ..... <b> x+2h .....</b>  x+2h .....  x+3h .....
+     * </pre>
+     *
+     * <p>The way that works is as follows. First the standard time is calculated and the DST
+     * offset is determined. Then if the time is in DST (the DST offset is not 0) but it was not in
+     * DST an hour earlier (or however long the DST offset is) then it must be in that invalid
+     * period, in which case set the DST offset to 0. That is then subtracted from the time in
+     * millis to produce the correct result. The following diagram illustrates the process.
+     *
+     * <pre>
+     * Standard Time  - ...... 01:00 ..... 02:00 ..... 03:00 ..... 04:00 .....
+     * Time In Millis - ......  x+1h .....  x+2h .....  x+3h .....  x+4h .....
+     * DST Offset     - ......    0h .....    1h .....    1h .....    1h .....
+     * Adjusted DST   - ......    0h .....    <b>0h</b> .....    1h .....    1h .....
+     * Adjusted Time  - ......  x+1h .....  x+2h .....  <b>x+2h</b> .....  <b>x+3h</b> .....
+     * </pre>
+     *
+     * @return the adjusted DST offset.
+     */
+    private int adjustDstOffsetForInvalidWallClock(
+            long standardTimeInZone, TimeZone zone, int dstOffset) {
+
+        if (dstOffset != 0) {
+            // If applying the DST offset produces a time that is outside DST then it must be
+            // an invalid wall clock so clear the DST offset to avoid that happening.
+            if (!zone.inDaylightTime(new Date(standardTimeInZone - dstOffset))) {
+                dstOffset = 0;
+            }
+        }
+        return dstOffset;
+    }
+    // END Android-added: helper methods for time zone related calculation
+
+    /**
+     * Computes the fixed date under either the Gregorian or the
+     * Julian calendar, using the given year and the specified calendar fields.
+     *
+     * @param cal the CalendarSystem to be used for the date calculation
+     * @param year the normalized year number, with 0 indicating the
+     * year 1 BCE, -1 indicating 2 BCE, etc.
+     * @param fieldMask the calendar fields to be used for the date calculation
+     * @return the fixed date
+     * @see Calendar#selectFields
+     */
+    private long getFixedDate(BaseCalendar cal, int year, int fieldMask) {
+        int month = JANUARY;
+        if (isFieldSet(fieldMask, MONTH)) {
+            // No need to check if MONTH has been set (no isSet(MONTH)
+            // call) since its unset value happens to be JANUARY (0).
+            month = internalGet(MONTH);
+
+            // If the month is out of range, adjust it into range
+            if (month > DECEMBER) {
+                year += month / 12;
+                month %= 12;
+            } else if (month < JANUARY) {
+                int[] rem = new int[1];
+                year += CalendarUtils.floorDivide(month, 12, rem);
+                month = rem[0];
+            }
+        }
+
+        // Get the fixed date since Jan 1, 1 (Gregorian). We are on
+        // the first day of either `month' or January in 'year'.
+        long fixedDate = cal.getFixedDate(year, month + 1, 1,
+                                          cal == gcal ? gdate : null);
+        if (isFieldSet(fieldMask, MONTH)) {
+            // Month-based calculations
+            if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
+                // We are on the first day of the month. Just add the
+                // offset if DAY_OF_MONTH is set. If the isSet call
+                // returns false, that means DAY_OF_MONTH has been
+                // selected just because of the selected
+                // combination. We don't need to add any since the
+                // default value is the 1st.
+                if (isSet(DAY_OF_MONTH)) {
+                    // To avoid underflow with DAY_OF_MONTH-1, add
+                    // DAY_OF_MONTH, then subtract 1.
+                    fixedDate += internalGet(DAY_OF_MONTH);
+                    fixedDate--;
+                }
+            } else {
+                if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
+                    long firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                                  getFirstDayOfWeek());
+                    // If we have enough days in the first week, then
+                    // move to the previous week.
+                    if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                        firstDayOfWeek -= 7;
+                    }
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                 internalGet(DAY_OF_WEEK));
+                    }
+                    // In lenient mode, we treat days of the previous
+                    // months as a part of the specified
+                    // WEEK_OF_MONTH. See 4633646.
+                    fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
+                } else {
+                    int dayOfWeek;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        dayOfWeek = internalGet(DAY_OF_WEEK);
+                    } else {
+                        dayOfWeek = getFirstDayOfWeek();
+                    }
+                    // We are basing this on the day-of-week-in-month.  The only
+                    // trickiness occurs if the day-of-week-in-month is
+                    // negative.
+                    int dowim;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
+                        dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
+                    } else {
+                        dowim = 1;
+                    }
+                    if (dowim >= 0) {
+                        fixedDate = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
+                                                                            dayOfWeek);
+                    } else {
+                        // Go to the first day of the next week of
+                        // the specified week boundary.
+                        int lastDate = monthLength(month, year) + (7 * (dowim + 1));
+                        // Then, get the day of week date on or before the last date.
+                        fixedDate = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
+                                                                            dayOfWeek);
+                    }
+                }
+            }
+        } else {
+            if (year == gregorianCutoverYear && cal == gcal
+                && fixedDate < gregorianCutoverDate
+                && gregorianCutoverYear != gregorianCutoverYearJulian) {
+                // January 1 of the year doesn't exist.  Use
+                // gregorianCutoverDate as the first day of the
+                // year.
+                fixedDate = gregorianCutoverDate;
+            }
+            // We are on the first day of the year.
+            if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
+                // Add the offset, then subtract 1. (Make sure to avoid underflow.)
+                fixedDate += internalGet(DAY_OF_YEAR);
+                fixedDate--;
+            } else {
+                long firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                              getFirstDayOfWeek());
+                // If we have enough days in the first week, then move
+                // to the previous week.
+                if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                    firstDayOfWeek -= 7;
+                }
+                if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                    int dayOfWeek = internalGet(DAY_OF_WEEK);
+                    if (dayOfWeek != getFirstDayOfWeek()) {
+                        firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                 dayOfWeek);
+                    }
+                }
+                fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
+            }
+        }
+
+        return fixedDate;
+    }
+
+    /**
+     * Returns this object if it's normalized (all fields and time are
+     * in sync). Otherwise, a cloned object is returned after calling
+     * complete() in lenient mode.
+     */
+    private GregorianCalendar getNormalizedCalendar() {
+        GregorianCalendar gc;
+        if (isFullyNormalized()) {
+            gc = this;
+        } else {
+            // Create a clone and normalize the calendar fields
+            gc = (GregorianCalendar) this.clone();
+            gc.setLenient(true);
+            gc.complete();
+        }
+        return gc;
+    }
+
+    /**
+     * Returns the Julian calendar system instance (singleton). 'jcal'
+     * and 'jeras' are set upon the return.
+     */
+    private static synchronized BaseCalendar getJulianCalendarSystem() {
+        if (jcal == null) {
+            jcal = (JulianCalendar) CalendarSystem.forName("julian");
+            jeras = jcal.getEras();
+        }
+        return jcal;
+    }
+
+    /**
+     * Returns the calendar system for dates before the cutover date
+     * in the cutover year. If the cutover date is January 1, the
+     * method returns Gregorian. Otherwise, Julian.
+     */
+    private BaseCalendar getCutoverCalendarSystem() {
+        if (gregorianCutoverYearJulian < gregorianCutoverYear) {
+            return gcal;
+        }
+        return getJulianCalendarSystem();
+    }
+
+    /**
+     * Determines if the specified year (normalized) is the Gregorian
+     * cutover year. This object must have been normalized.
+     */
+    private boolean isCutoverYear(int normalizedYear) {
+        int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
+        return normalizedYear == cutoverYear;
+    }
+
+    /**
+     * Returns the fixed date of the first day of the year (usually
+     * January 1) before the specified date.
+     *
+     * @param date the date for which the first day of the year is
+     * calculated. The date has to be in the cut-over year (Gregorian
+     * or Julian).
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateJan1(BaseCalendar.Date date, long fixedDate) {
+        assert date.getNormalizedYear() == gregorianCutoverYear ||
+            date.getNormalizedYear() == gregorianCutoverYearJulian;
+        if (gregorianCutoverYear != gregorianCutoverYearJulian) {
+            if (fixedDate >= gregorianCutoverDate) {
+                // Dates before the cutover date don't exist
+                // in the same (Gregorian) year. So, no
+                // January 1 exists in the year. Use the
+                // cutover date as the first day of the year.
+                return gregorianCutoverDate;
+            }
+        }
+        // January 1 of the normalized year should exist.
+        BaseCalendar juliancal = getJulianCalendarSystem();
+        return juliancal.getFixedDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1, null);
+    }
+
+    /**
+     * Returns the fixed date of the first date of the month (usually
+     * the 1st of the month) before the specified date.
+     *
+     * @param date the date for which the first day of the month is
+     * calculated. The date has to be in the cut-over year (Gregorian
+     * or Julian).
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateMonth1(BaseCalendar.Date date, long fixedDate) {
+        assert date.getNormalizedYear() == gregorianCutoverYear ||
+            date.getNormalizedYear() == gregorianCutoverYearJulian;
+        BaseCalendar.Date gCutover = getGregorianCutoverDate();
+        if (gCutover.getMonth() == BaseCalendar.JANUARY
+            && gCutover.getDayOfMonth() == 1) {
+            // The cutover happened on January 1.
+            return fixedDate - date.getDayOfMonth() + 1;
+        }
+
+        long fixedDateMonth1;
+        // The cutover happened sometime during the year.
+        if (date.getMonth() == gCutover.getMonth()) {
+            // The cutover happened in the month.
+            BaseCalendar.Date jLastDate = getLastJulianDate();
+            if (gregorianCutoverYear == gregorianCutoverYearJulian
+                && gCutover.getMonth() == jLastDate.getMonth()) {
+                // The "gap" fits in the same month.
+                fixedDateMonth1 = jcal.getFixedDate(date.getNormalizedYear(),
+                                                    date.getMonth(),
+                                                    1,
+                                                    null);
+            } else {
+                // Use the cutover date as the first day of the month.
+                fixedDateMonth1 = gregorianCutoverDate;
+            }
+        } else {
+            // The cutover happened before the month.
+            fixedDateMonth1 = fixedDate - date.getDayOfMonth() + 1;
+        }
+
+        return fixedDateMonth1;
+    }
+
+    /**
+     * Returns a CalendarDate produced from the specified fixed date.
+     *
+     * @param fd the fixed date
+     */
+    private BaseCalendar.Date getCalendarDate(long fd) {
+        BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
+        BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        cal.getCalendarDateFromFixedDate(d, fd);
+        return d;
+    }
+
+    /**
+     * Returns the Gregorian cutover date as a BaseCalendar.Date. The
+     * date is a Gregorian date.
+     */
+    private BaseCalendar.Date getGregorianCutoverDate() {
+        return getCalendarDate(gregorianCutoverDate);
+    }
+
+    /**
+     * Returns the day before the Gregorian cutover date as a
+     * BaseCalendar.Date. The date is a Julian date.
+     */
+    private BaseCalendar.Date getLastJulianDate() {
+        return getCalendarDate(gregorianCutoverDate - 1);
+    }
+
+    /**
+     * Returns the length of the specified month in the specified
+     * year. The year number must be normalized.
+     *
+     * @see #isLeapYear(int)
+     */
+    private int monthLength(int month, int year) {
+        return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month];
+    }
+
+    /**
+     * Returns the length of the specified month in the year provided
+     * by internalGet(YEAR).
+     *
+     * @see #isLeapYear(int)
+     */
+    private int monthLength(int month) {
+        int year = internalGet(YEAR);
+        if (internalGetEra() == BCE) {
+            year = 1 - year;
+        }
+        return monthLength(month, year);
+    }
+
+    private int actualMonthLength() {
+        int year = cdate.getNormalizedYear();
+        if (year != gregorianCutoverYear && year != gregorianCutoverYearJulian) {
+            return calsys.getMonthLength(cdate);
+        }
+        BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone();
+        long fd = calsys.getFixedDate(date);
+        long month1 = getFixedDateMonth1(date, fd);
+        long next1 = month1 + calsys.getMonthLength(date);
+        if (next1 < gregorianCutoverDate) {
+            return (int)(next1 - month1);
+        }
+        if (cdate != gdate) {
+            date = (BaseCalendar.Date) gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        }
+        gcal.getCalendarDateFromFixedDate(date, next1);
+        next1 = getFixedDateMonth1(date, next1);
+        return (int)(next1 - month1);
+    }
+
+    /**
+     * Returns the length (in days) of the specified year. The year
+     * must be normalized.
+     */
+    private int yearLength(int year) {
+        return isLeapYear(year) ? 366 : 365;
+    }
+
+    /**
+     * Returns the length (in days) of the year provided by
+     * internalGet(YEAR).
+     */
+    private int yearLength() {
+        int year = internalGet(YEAR);
+        if (internalGetEra() == BCE) {
+            year = 1 - year;
+        }
+        return yearLength(year);
+    }
+
+    /**
+     * After adjustments such as add(MONTH), add(YEAR), we don't want the
+     * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
+     * 3, we want it to go to Feb 28.  Adjustments which might run into this
+     * problem call this method to retain the proper month.
+     */
+    private void pinDayOfMonth() {
+        int year = internalGet(YEAR);
+        int monthLen;
+        if (year > gregorianCutoverYear || year < gregorianCutoverYearJulian) {
+            monthLen = monthLength(internalGet(MONTH));
+        } else {
+            GregorianCalendar gc = getNormalizedCalendar();
+            monthLen = gc.getActualMaximum(DAY_OF_MONTH);
+        }
+        int dom = internalGet(DAY_OF_MONTH);
+        if (dom > monthLen) {
+            set(DAY_OF_MONTH, monthLen);
+        }
+    }
+
+    /**
+     * Returns the fixed date value of this object. The time value and
+     * calendar fields must be in synch.
+     */
+    private long getCurrentFixedDate() {
+        return (calsys == gcal) ? cachedFixedDate : calsys.getFixedDate(cdate);
+    }
+
+    /**
+     * Returns the new value after 'roll'ing the specified value and amount.
+     */
+    private static int getRolledValue(int value, int amount, int min, int max) {
+        assert value >= min && value <= max;
+        int range = max - min + 1;
+        amount %= range;
+        int n = value + amount;
+        if (n > max) {
+            n -= range;
+        } else if (n < min) {
+            n += range;
+        }
+        assert n >= min && n <= max;
+        return n;
+    }
+
+    /**
+     * Returns the ERA.  We need a special method for this because the
+     * default ERA is CE, but a zero (unset) ERA is BCE.
+     */
+    private int internalGetEra() {
+        return isSet(ERA) ? internalGet(ERA) : CE;
+    }
+
+    /**
+     * Updates internal state.
+     */
+    private void readObject(ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+        stream.defaultReadObject();
+        if (gdate == null) {
+            gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
+            cachedFixedDate = Long.MIN_VALUE;
+        }
+        setGregorianChange(gregorianCutover);
+    }
+
+    /**
+     * Converts this object to a {@code ZonedDateTime} that represents
+     * the same point on the time-line as this {@code GregorianCalendar}.
+     * <p>
+     * Since this object supports a Julian-Gregorian cutover date and
+     * {@code ZonedDateTime} does not, it is possible that the resulting year,
+     * month and day will have different values.  The result will represent the
+     * correct date in the ISO calendar system, which will also be the same value
+     * for Modified Julian Days.
+     *
+     * @return a zoned date-time representing the same point on the time-line
+     *  as this gregorian calendar
+     * @since 1.8
+     */
+    public ZonedDateTime toZonedDateTime() {
+        return ZonedDateTime.ofInstant(Instant.ofEpochMilli(getTimeInMillis()),
+                                       getTimeZone().toZoneId());
+    }
+
+    /**
+     * Obtains an instance of {@code GregorianCalendar} with the default locale
+     * from a {@code ZonedDateTime} object.
+     * <p>
+     * Since {@code ZonedDateTime} does not support a Julian-Gregorian cutover
+     * date and uses ISO calendar system, the return GregorianCalendar is a pure
+     * Gregorian calendar and uses ISO 8601 standard for week definitions,
+     * which has {@code MONDAY} as the {@link Calendar#getFirstDayOfWeek()
+     * FirstDayOfWeek} and {@code 4} as the value of the
+     * {@link Calendar#getMinimalDaysInFirstWeek() MinimalDaysInFirstWeek}.
+     * <p>
+     * {@code ZoneDateTime} can store points on the time-line further in the
+     * future and further in the past than {@code GregorianCalendar}. In this
+     * scenario, this method will throw an {@code IllegalArgumentException}
+     * exception.
+     *
+     * @param zdt  the zoned date-time object to convert
+     * @return  the gregorian calendar representing the same point on the
+     *  time-line as the zoned date-time provided
+     * @exception NullPointerException if {@code zdt} is null
+     * @exception IllegalArgumentException if the zoned date-time is too
+     * large to represent as a {@code GregorianCalendar}
+     * @since 1.8
+     */
+    public static GregorianCalendar from(ZonedDateTime zdt) {
+        GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone(zdt.getZone()));
+        cal.setGregorianChange(new Date(Long.MIN_VALUE));
+        cal.setFirstDayOfWeek(MONDAY);
+        cal.setMinimalDaysInFirstWeek(4);
+        try {
+            cal.setTimeInMillis(Math.addExact(Math.multiplyExact(zdt.toEpochSecond(), 1000),
+                                              zdt.get(ChronoField.MILLI_OF_SECOND)));
+        } catch (ArithmeticException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+        return cal;
+    }
+}
diff --git a/java/util/HashMap.annotated.java b/java/util/HashMap.annotated.java
new file mode 100644
index 0000000..3bcc489
--- /dev/null
+++ b/java/util/HashMap.annotated.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class HashMap<K, V> extends java.util.AbstractMap<K,V> implements java.util.Map<K,V>, java.lang.Cloneable, java.io.Serializable {
+
+public HashMap(int initialCapacity, float loadFactor) { throw new RuntimeException("Stub!"); }
+
+public HashMap(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+public HashMap() { throw new RuntimeException("Stub!"); }
+
+public HashMap(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K, ? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
[email protected] public V get(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public boolean containsKey(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
[email protected] public V put(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public V remove(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public boolean containsValue(@libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public V getOrDefault(@libcore.util.Nullable java.lang.Object key, @libcore.util.Nullable V defaultValue) { throw new RuntimeException("Stub!"); }
+
[email protected] public V putIfAbsent(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object key, @libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public boolean replace(@libcore.util.NullFromTypeParam K key, @libcore.util.Nullable V oldValue, @libcore.util.NullFromTypeParam V newValue) { throw new RuntimeException("Stub!"); }
+
[email protected] public V replace(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
[email protected] public V computeIfAbsent(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NullFromTypeParam K,? extends @libcore.util.Nullable V> mappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public V computeIfPresent(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public V compute(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.Nullable V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public V merge(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull V value, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull V,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+public void forEach(@libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V> action) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(@libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V,? extends @libcore.util.NullFromTypeParam V> function) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/HashMap.java b/java/util/HashMap.java
new file mode 100644
index 0000000..2c01f6f
--- /dev/null
+++ b/java/util/HashMap.java
@@ -0,0 +1,2391 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.Serializable;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * Hash table based implementation of the <tt>Map</tt> interface.  This
+ * implementation provides all of the optional map operations, and permits
+ * <tt>null</tt> values and the <tt>null</tt> key.  (The <tt>HashMap</tt>
+ * class is roughly equivalent to <tt>Hashtable</tt>, except that it is
+ * unsynchronized and permits nulls.)  This class makes no guarantees as to
+ * the order of the map; in particular, it does not guarantee that the order
+ * will remain constant over time.
+ *
+ * <p>This implementation provides constant-time performance for the basic
+ * operations (<tt>get</tt> and <tt>put</tt>), assuming the hash function
+ * disperses the elements properly among the buckets.  Iteration over
+ * collection views requires time proportional to the "capacity" of the
+ * <tt>HashMap</tt> instance (the number of buckets) plus its size (the number
+ * of key-value mappings).  Thus, it's very important not to set the initial
+ * capacity too high (or the load factor too low) if iteration performance is
+ * important.
+ *
+ * <p>An instance of <tt>HashMap</tt> has two parameters that affect its
+ * performance: <i>initial capacity</i> and <i>load factor</i>.  The
+ * <i>capacity</i> is the number of buckets in the hash table, and the initial
+ * capacity is simply the capacity at the time the hash table is created.  The
+ * <i>load factor</i> is a measure of how full the hash table is allowed to
+ * get before its capacity is automatically increased.  When the number of
+ * entries in the hash table exceeds the product of the load factor and the
+ * current capacity, the hash table is <i>rehashed</i> (that is, internal data
+ * structures are rebuilt) so that the hash table has approximately twice the
+ * number of buckets.
+ *
+ * <p>As a general rule, the default load factor (.75) offers a good
+ * tradeoff between time and space costs.  Higher values decrease the
+ * space overhead but increase the lookup cost (reflected in most of
+ * the operations of the <tt>HashMap</tt> class, including
+ * <tt>get</tt> and <tt>put</tt>).  The expected number of entries in
+ * the map and its load factor should be taken into account when
+ * setting its initial capacity, so as to minimize the number of
+ * rehash operations.  If the initial capacity is greater than the
+ * maximum number of entries divided by the load factor, no rehash
+ * operations will ever occur.
+ *
+ * <p>If many mappings are to be stored in a <tt>HashMap</tt>
+ * instance, creating it with a sufficiently large capacity will allow
+ * the mappings to be stored more efficiently than letting it perform
+ * automatic rehashing as needed to grow the table.  Note that using
+ * many keys with the same {@code hashCode()} is a sure way to slow
+ * down performance of any hash table. To ameliorate impact, when keys
+ * are {@link Comparable}, this class may use comparison order among
+ * keys to help break ties.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a hash map concurrently, and at least one of
+ * the threads modifies the map structurally, it <i>must</i> be
+ * synchronized externally.  (A structural modification is any operation
+ * that adds or deletes one or more mappings; merely changing the value
+ * associated with a key that an instance already contains is not a
+ * structural modification.)  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the map.
+ *
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map:<pre>
+ *   Map m = Collections.synchronizedMap(new HashMap(...));</pre>
+ *
+ * <p>The iterators returned by all of this class's "collection view methods"
+ * are <i>fail-fast</i>: if the map is structurally modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * <tt>remove</tt> method, 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 time in the
+ * future.
+ *
+ * <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.
+ * 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>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Doug Lea
+ * @author  Josh Bloch
+ * @author  Arthur van Hoff
+ * @author  Neal Gafter
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Map
+ * @see     TreeMap
+ * @see     Hashtable
+ * @since   1.2
+ */
+public class HashMap<K,V> extends AbstractMap<K,V>
+    implements Map<K,V>, Cloneable, Serializable {
+
+    private static final long serialVersionUID = 362498820763181265L;
+
+    /*
+     * Implementation notes.
+     *
+     * This map usually acts as a binned (bucketed) hash table, but
+     * when bins get too large, they are transformed into bins of
+     * TreeNodes, each structured similarly to those in
+     * java.util.TreeMap. Most methods try to use normal bins, but
+     * relay to TreeNode methods when applicable (simply by checking
+     * instanceof a node).  Bins of TreeNodes may be traversed and
+     * used like any others, but additionally support faster lookup
+     * when overpopulated. However, since the vast majority of bins in
+     * normal use are not overpopulated, checking for existence of
+     * tree bins may be delayed in the course of table methods.
+     *
+     * Tree bins (i.e., bins whose elements are all TreeNodes) are
+     * ordered primarily by hashCode, but in the case of ties, if two
+     * elements are of the same "class C implements Comparable<C>",
+     * type then their compareTo method is used for ordering. (We
+     * conservatively check generic types via reflection to validate
+     * this -- see method comparableClassFor).  The added complexity
+     * of tree bins is worthwhile in providing worst-case O(log n)
+     * operations when keys either have distinct hashes or are
+     * orderable, Thus, performance degrades gracefully under
+     * accidental or malicious usages in which hashCode() methods
+     * return values that are poorly distributed, as well as those in
+     * which many keys share a hashCode, so long as they are also
+     * Comparable. (If neither of these apply, we may waste about a
+     * factor of two in time and space compared to taking no
+     * precautions. But the only known cases stem from poor user
+     * programming practices that are already so slow that this makes
+     * little difference.)
+     *
+     * Because TreeNodes are about twice the size of regular nodes, we
+     * use them only when bins contain enough nodes to warrant use
+     * (see TREEIFY_THRESHOLD). And when they become too small (due to
+     * removal or resizing) they are converted back to plain bins.  In
+     * usages with well-distributed user hashCodes, tree bins are
+     * rarely used.  Ideally, under random hashCodes, the frequency of
+     * nodes in bins follows a Poisson distribution
+     * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
+     * parameter of about 0.5 on average for the default resizing
+     * threshold of 0.75, although with a large variance because of
+     * resizing granularity. Ignoring variance, the expected
+     * occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
+     * factorial(k)). The first values are:
+     *
+     * 0:    0.60653066
+     * 1:    0.30326533
+     * 2:    0.07581633
+     * 3:    0.01263606
+     * 4:    0.00157952
+     * 5:    0.00015795
+     * 6:    0.00001316
+     * 7:    0.00000094
+     * 8:    0.00000006
+     * more: less than 1 in ten million
+     *
+     * The root of a tree bin is normally its first node.  However,
+     * sometimes (currently only upon Iterator.remove), the root might
+     * be elsewhere, but can be recovered following parent links
+     * (method TreeNode.root()).
+     *
+     * All applicable internal methods accept a hash code as an
+     * argument (as normally supplied from a public method), allowing
+     * them to call each other without recomputing user hashCodes.
+     * Most internal methods also accept a "tab" argument, that is
+     * normally the current table, but may be a new or old one when
+     * resizing or converting.
+     *
+     * When bin lists are treeified, split, or untreeified, we keep
+     * them in the same relative access/traversal order (i.e., field
+     * Node.next) to better preserve locality, and to slightly
+     * simplify handling of splits and traversals that invoke
+     * iterator.remove. When using comparators on insertion, to keep a
+     * total ordering (or as close as is required here) across
+     * rebalancings, we compare classes and identityHashCodes as
+     * tie-breakers.
+     *
+     * The use and transitions among plain vs tree modes is
+     * complicated by the existence of subclass LinkedHashMap. See
+     * below for hook methods defined to be invoked upon insertion,
+     * removal and access that allow LinkedHashMap internals to
+     * otherwise remain independent of these mechanics. (This also
+     * requires that a map instance be passed to some utility methods
+     * that may create new nodes.)
+     *
+     * The concurrent-programming-like SSA-based coding style helps
+     * avoid aliasing errors amid all of the twisty pointer operations.
+     */
+
+    /**
+     * The default initial capacity - MUST be a power of two.
+     */
+    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<30.
+     */
+    static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The load factor used when none specified in constructor.
+     */
+    static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+    /**
+     * The bin count threshold for using a tree rather than list for a
+     * bin.  Bins are converted to trees when adding an element to a
+     * bin with at least this many nodes. The value must be greater
+     * than 2 and should be at least 8 to mesh with assumptions in
+     * tree removal about conversion back to plain bins upon
+     * shrinkage.
+     */
+    static final int TREEIFY_THRESHOLD = 8;
+
+    /**
+     * The bin count threshold for untreeifying a (split) bin during a
+     * resize operation. Should be less than TREEIFY_THRESHOLD, and at
+     * most 6 to mesh with shrinkage detection under removal.
+     */
+    static final int UNTREEIFY_THRESHOLD = 6;
+
+    /**
+     * The smallest table capacity for which bins may be treeified.
+     * (Otherwise the table is resized if too many nodes in a bin.)
+     * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
+     * between resizing and treeification thresholds.
+     */
+    static final int MIN_TREEIFY_CAPACITY = 64;
+
+    /**
+     * Basic hash bin node, used for most entries.  (See below for
+     * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
+     */
+    static class Node<K,V> implements Map.Entry<K,V> {
+        final int hash;
+        final K key;
+        V value;
+        Node<K,V> next;
+
+        Node(int hash, K key, V value, Node<K,V> next) {
+            this.hash = hash;
+            this.key = key;
+            this.value = value;
+            this.next = next;
+        }
+
+        public final K getKey()        { return key; }
+        public final V getValue()      { return value; }
+        public final String toString() { return key + "=" + value; }
+
+        public final int hashCode() {
+            return Objects.hashCode(key) ^ Objects.hashCode(value);
+        }
+
+        public final V setValue(V newValue) {
+            V oldValue = value;
+            value = newValue;
+            return oldValue;
+        }
+
+        public final boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (o instanceof Map.Entry) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+                if (Objects.equals(key, e.getKey()) &&
+                    Objects.equals(value, e.getValue()))
+                    return true;
+            }
+            return false;
+        }
+    }
+
+    /* ---------------- Static utilities -------------- */
+
+    /**
+     * Computes key.hashCode() and spreads (XORs) higher bits of hash
+     * to lower.  Because the table uses power-of-two masking, sets of
+     * hashes that vary only in bits above the current mask will
+     * always collide. (Among known examples are sets of Float keys
+     * holding consecutive whole numbers in small tables.)  So we
+     * apply a transform that spreads the impact of higher bits
+     * downward. There is a tradeoff between speed, utility, and
+     * quality of bit-spreading. Because many common sets of hashes
+     * are already reasonably distributed (so don't benefit from
+     * spreading), and because we use trees to handle large sets of
+     * collisions in bins, we just XOR some shifted bits in the
+     * cheapest possible way to reduce systematic lossage, as well as
+     * to incorporate impact of the highest bits that would otherwise
+     * never be used in index calculations because of table bounds.
+     */
+    static final int hash(Object key) {
+        int h;
+        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
+    }
+
+    /**
+     * Returns x's Class if it is of the form "class C implements
+     * Comparable<C>", else null.
+     */
+    static Class<?> comparableClassFor(Object x) {
+        if (x instanceof Comparable) {
+            Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
+            if ((c = x.getClass()) == String.class) // bypass checks
+                return c;
+            if ((ts = c.getGenericInterfaces()) != null) {
+                for (int i = 0; i < ts.length; ++i) {
+                    if (((t = ts[i]) instanceof ParameterizedType) &&
+                        ((p = (ParameterizedType)t).getRawType() ==
+                         Comparable.class) &&
+                        (as = p.getActualTypeArguments()) != null &&
+                        as.length == 1 && as[0] == c) // type arg is c
+                        return c;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns k.compareTo(x) if x matches kc (k's screened comparable
+     * class), else 0.
+     */
+    @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
+    static int compareComparables(Class<?> kc, Object k, Object x) {
+        return (x == null || x.getClass() != kc ? 0 :
+                ((Comparable)k).compareTo(x));
+    }
+
+    /**
+     * Returns a power of two size for the given target capacity.
+     */
+    static final int tableSizeFor(int cap) {
+        int n = cap - 1;
+        n |= n >>> 1;
+        n |= n >>> 2;
+        n |= n >>> 4;
+        n |= n >>> 8;
+        n |= n >>> 16;
+        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
+    }
+
+    /* ---------------- Fields -------------- */
+
+    /**
+     * The table, initialized on first use, and resized as
+     * necessary. When allocated, length is always a power of two.
+     * (We also tolerate length zero in some operations to allow
+     * bootstrapping mechanics that are currently not needed.)
+     */
+    transient Node<K,V>[] table;
+
+    /**
+     * Holds cached entrySet(). Note that AbstractMap fields are used
+     * for keySet() and values().
+     */
+    transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * The number of key-value mappings contained in this map.
+     */
+    transient int size;
+
+    /**
+     * 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;
+
+    /**
+     * The next size value at which to resize (capacity * load factor).
+     *
+     * @serial
+     */
+    // (The javadoc description is true upon serialization.
+    // Additionally, if the table array has not been allocated, this
+    // field holds the initial array capacity, or zero signifying
+    // DEFAULT_INITIAL_CAPACITY.)
+    int threshold;
+
+    /**
+     * The load factor for the hash table.
+     *
+     * @serial
+     */
+    final float loadFactor;
+
+    /* ---------------- Public operations -------------- */
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and load factor.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public HashMap(int initialCapacity, float loadFactor) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal initial capacity: " +
+                                               initialCapacity);
+        if (initialCapacity > MAXIMUM_CAPACITY)
+            initialCapacity = MAXIMUM_CAPACITY;
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal load factor: " +
+                                               loadFactor);
+        this.loadFactor = loadFactor;
+        this.threshold = tableSizeFor(initialCapacity);
+    }
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param  initialCapacity the initial capacity.
+     * @throws IllegalArgumentException if the initial capacity is negative.
+     */
+    public HashMap(int initialCapacity) {
+        this(initialCapacity, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the default initial capacity
+     * (16) and the default load factor (0.75).
+     */
+    public HashMap() {
+        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
+    }
+
+    /**
+     * Constructs a new <tt>HashMap</tt> with the same mappings as the
+     * specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with
+     * default load factor (0.75) and an initial capacity sufficient to
+     * hold the mappings in the specified <tt>Map</tt>.
+     *
+     * @param   m the map whose mappings are to be placed in this map
+     * @throws  NullPointerException if the specified map is null
+     */
+    public HashMap(Map<? extends K, ? extends V> m) {
+        this.loadFactor = DEFAULT_LOAD_FACTOR;
+        putMapEntries(m, false);
+    }
+
+    /**
+     * Implements Map.putAll and Map constructor
+     *
+     * @param m the map
+     * @param evict false when initially constructing this map, else
+     * true (relayed to method afterNodeInsertion).
+     */
+    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
+        int s = m.size();
+        if (s > 0) {
+            if (table == null) { // pre-size
+                float ft = ((float)s / loadFactor) + 1.0F;
+                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
+                         (int)ft : MAXIMUM_CAPACITY);
+                if (t > threshold)
+                    threshold = tableSizeFor(t);
+            }
+            else if (s > threshold)
+                resize();
+            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
+                K key = e.getKey();
+                V value = e.getValue();
+                putVal(hash(key), key, value, false, evict);
+            }
+        }
+    }
+
+    /**
+     * 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 the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
+     * key.equals(k))}, then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} 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 {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @see #put(Object, Object)
+     */
+    public V get(Object key) {
+        Node<K,V> e;
+        return (e = getNode(hash(key), key)) == null ? null : e.value;
+    }
+
+    /**
+     * Implements Map.get and related methods
+     *
+     * @param hash hash for key
+     * @param key the key
+     * @return the node, or null if none
+     */
+    final Node<K,V> getNode(int hash, Object key) {
+        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
+        if ((tab = table) != null && (n = tab.length) > 0 &&
+            (first = tab[(n - 1) & hash]) != null) {
+            if (first.hash == hash && // always check first node
+                ((k = first.key) == key || (key != null && key.equals(k))))
+                return first;
+            if ((e = first.next) != null) {
+                if (first instanceof TreeNode)
+                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k))))
+                        return e;
+                } while ((e = e.next) != null);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains a mapping for the
+     * specified key.
+     *
+     * @param   key   The key whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map contains a mapping for the specified
+     * key.
+     */
+    public boolean containsKey(Object key) {
+        return getNode(hash(key), key) != null;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for the 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 the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
+     *         (A <tt>null</tt> return can also indicate that the map
+     *         previously associated <tt>null</tt> with <tt>key</tt>.)
+     */
+    public V put(K key, V value) {
+        return putVal(hash(key), key, value, false, true);
+    }
+
+    /**
+     * Implements Map.put and related methods
+     *
+     * @param hash hash for key
+     * @param key the key
+     * @param value the value to put
+     * @param onlyIfAbsent if true, don't change existing value
+     * @param evict if false, the table is in creation mode.
+     * @return previous value, or null if none
+     */
+    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
+                   boolean evict) {
+        Node<K,V>[] tab; Node<K,V> p; int n, i;
+        if ((tab = table) == null || (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((p = tab[i = (n - 1) & hash]) == null)
+            tab[i] = newNode(hash, key, value, null);
+        else {
+            Node<K,V> e; K k;
+            if (p.hash == hash &&
+                ((k = p.key) == key || (key != null && key.equals(k))))
+                e = p;
+            else if (p instanceof TreeNode)
+                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
+            else {
+                for (int binCount = 0; ; ++binCount) {
+                    if ((e = p.next) == null) {
+                        p.next = newNode(hash, key, value, null);
+                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
+                            treeifyBin(tab, hash);
+                        break;
+                    }
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k))))
+                        break;
+                    p = e;
+                }
+            }
+            if (e != null) { // existing mapping for key
+                V oldValue = e.value;
+                if (!onlyIfAbsent || oldValue == null)
+                    e.value = value;
+                afterNodeAccess(e);
+                return oldValue;
+            }
+        }
+        ++modCount;
+        if (++size > threshold)
+            resize();
+        afterNodeInsertion(evict);
+        return null;
+    }
+
+    /**
+     * Initializes or doubles table size.  If null, allocates in
+     * accord with initial capacity target held in field threshold.
+     * Otherwise, because we are using power-of-two expansion, the
+     * elements from each bin must either stay at same index, or move
+     * with a power of two offset in the new table.
+     *
+     * @return the table
+     */
+    final Node<K,V>[] resize() {
+        Node<K,V>[] oldTab = table;
+        int oldCap = (oldTab == null) ? 0 : oldTab.length;
+        int oldThr = threshold;
+        int newCap, newThr = 0;
+        if (oldCap > 0) {
+            if (oldCap >= MAXIMUM_CAPACITY) {
+                threshold = Integer.MAX_VALUE;
+                return oldTab;
+            }
+            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
+                     oldCap >= DEFAULT_INITIAL_CAPACITY)
+                newThr = oldThr << 1; // double threshold
+        }
+        else if (oldThr > 0) // initial capacity was placed in threshold
+            newCap = oldThr;
+        else {               // zero initial threshold signifies using defaults
+            newCap = DEFAULT_INITIAL_CAPACITY;
+            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
+        }
+        if (newThr == 0) {
+            float ft = (float)newCap * loadFactor;
+            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
+                      (int)ft : Integer.MAX_VALUE);
+        }
+        threshold = newThr;
+        @SuppressWarnings({"rawtypes","unchecked"})
+            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
+        table = newTab;
+        if (oldTab != null) {
+            for (int j = 0; j < oldCap; ++j) {
+                Node<K,V> e;
+                if ((e = oldTab[j]) != null) {
+                    oldTab[j] = null;
+                    if (e.next == null)
+                        newTab[e.hash & (newCap - 1)] = e;
+                    else if (e instanceof TreeNode)
+                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
+                    else { // preserve order
+                        Node<K,V> loHead = null, loTail = null;
+                        Node<K,V> hiHead = null, hiTail = null;
+                        Node<K,V> next;
+                        do {
+                            next = e.next;
+                            if ((e.hash & oldCap) == 0) {
+                                if (loTail == null)
+                                    loHead = e;
+                                else
+                                    loTail.next = e;
+                                loTail = e;
+                            }
+                            else {
+                                if (hiTail == null)
+                                    hiHead = e;
+                                else
+                                    hiTail.next = e;
+                                hiTail = e;
+                            }
+                        } while ((e = next) != null);
+                        if (loTail != null) {
+                            loTail.next = null;
+                            newTab[j] = loHead;
+                        }
+                        if (hiTail != null) {
+                            hiTail.next = null;
+                            newTab[j + oldCap] = hiHead;
+                        }
+                    }
+                }
+            }
+        }
+        return newTab;
+    }
+
+    /**
+     * Replaces all linked nodes in bin at index for given hash unless
+     * table is too small, in which case resizes instead.
+     */
+    final void treeifyBin(Node<K,V>[] tab, int hash) {
+        int n, index; Node<K,V> e;
+        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
+            resize();
+        else if ((e = tab[index = (n - 1) & hash]) != null) {
+            TreeNode<K,V> hd = null, tl = null;
+            do {
+                TreeNode<K,V> p = replacementTreeNode(e, null);
+                if (tl == null)
+                    hd = p;
+                else {
+                    p.prev = tl;
+                    tl.next = p;
+                }
+                tl = p;
+            } while ((e = e.next) != null);
+            if ((tab[index] = hd) != null)
+                hd.treeify(tab);
+        }
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for
+     * any of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        putMapEntries(m, true);
+    }
+
+    /**
+     * Removes the mapping for the specified key from this map if present.
+     *
+     * @param  key key whose mapping is to be removed from the map
+     * @return the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
+     *         (A <tt>null</tt> return can also indicate that the map
+     *         previously associated <tt>null</tt> with <tt>key</tt>.)
+     */
+    public V remove(Object key) {
+        Node<K,V> e;
+        return (e = removeNode(hash(key), key, null, false, true)) == null ?
+            null : e.value;
+    }
+
+    /**
+     * Implements Map.remove and related methods
+     *
+     * @param hash hash for key
+     * @param key the key
+     * @param value the value to match if matchValue, else ignored
+     * @param matchValue if true only remove if value is equal
+     * @param movable if false do not move other nodes while removing
+     * @return the node, or null if none
+     */
+    final Node<K,V> removeNode(int hash, Object key, Object value,
+                               boolean matchValue, boolean movable) {
+        Node<K,V>[] tab; Node<K,V> p; int n, index;
+        if ((tab = table) != null && (n = tab.length) > 0 &&
+            (p = tab[index = (n - 1) & hash]) != null) {
+            Node<K,V> node = null, e; K k; V v;
+            if (p.hash == hash &&
+                ((k = p.key) == key || (key != null && key.equals(k))))
+                node = p;
+            else if ((e = p.next) != null) {
+                if (p instanceof TreeNode)
+                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
+                else {
+                    do {
+                        if (e.hash == hash &&
+                            ((k = e.key) == key ||
+                             (key != null && key.equals(k)))) {
+                            node = e;
+                            break;
+                        }
+                        p = e;
+                    } while ((e = e.next) != null);
+                }
+            }
+            if (node != null && (!matchValue || (v = node.value) == value ||
+                                 (value != null && value.equals(v)))) {
+                if (node instanceof TreeNode)
+                    ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
+                else if (node == p)
+                    tab[index] = node.next;
+                else
+                    p.next = node.next;
+                ++modCount;
+                --size;
+                afterNodeRemoval(node);
+                return node;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        Node<K,V>[] tab;
+        modCount++;
+        if ((tab = table) != null && size > 0) {
+            size = 0;
+            for (int i = 0; i < tab.length; ++i)
+                tab[i] = 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) {
+        Node<K,V>[] tab; V v;
+        if ((tab = table) != null && size > 0) {
+            for (int i = 0; i < tab.length; ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+                    if ((v = e.value) == value ||
+                        (value != null && value.equals(v)))
+                        return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+     * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
+     * operations.
+     *
+     * @return a set view of the keys contained in this map
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    final class KeySet extends AbstractSet<K> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<K> iterator()     { return new KeyIterator(); }
+        public final boolean contains(Object o) { return containsKey(o); }
+        public final boolean remove(Object key) {
+            return removeNode(hash(key), key, null, false, true) != null;
+        }
+        public final Spliterator<K> spliterator() {
+            return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
+        }
+        public final void forEach(Consumer<? super K> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                // Android-changed: Detect changes to modCount early.
+                for (int i = 0; (i < tab.length && modCount == mc); ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e.key);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own <tt>remove</tt> operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
+     * support the <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @return a view of the values contained in this map
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    final class Values extends AbstractCollection<V> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<V> iterator()     { return new ValueIterator(); }
+        public final boolean contains(Object o) { return containsValue(o); }
+        public final Spliterator<V> spliterator() {
+            return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
+        }
+        public final void forEach(Consumer<? super V> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                // Android-changed: Detect changes to modCount early.
+                for (int i = 0; (i < tab.length && modCount == mc); ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e.value);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation, or through the
+     * <tt>setValue</tt> operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
+     * <tt>clear</tt> operations.  It does not support the
+     * <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @return a set view of the mappings contained in this map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es;
+        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
+    }
+
+    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+        public final boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+            Object key = e.getKey();
+            Node<K,V> candidate = getNode(hash(key), key);
+            return candidate != null && candidate.equals(e);
+        }
+        public final boolean remove(Object o) {
+            if (o instanceof Map.Entry) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                Object key = e.getKey();
+                Object value = e.getValue();
+                return removeNode(hash(key), key, value, true, true) != null;
+            }
+            return false;
+        }
+        public final Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
+        }
+        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                // Android-changed: Detect changes to modCount early.
+                for (int i = 0; (i < tab.length && modCount == mc); ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    // Overrides of JDK8 Map extension methods
+
+    @Override
+    public V getOrDefault(Object key, V defaultValue) {
+        Node<K,V> e;
+        return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
+    }
+
+    @Override
+    public V putIfAbsent(K key, V value) {
+        return putVal(hash(key), key, value, true, true);
+    }
+
+    @Override
+    public boolean remove(Object key, Object value) {
+        return removeNode(hash(key), key, value, true, true) != null;
+    }
+
+    @Override
+    public boolean replace(K key, V oldValue, V newValue) {
+        Node<K,V> e; V v;
+        if ((e = getNode(hash(key), key)) != null &&
+            ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
+            e.value = newValue;
+            afterNodeAccess(e);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public V replace(K key, V value) {
+        Node<K,V> e;
+        if ((e = getNode(hash(key), key)) != null) {
+            V oldValue = e.value;
+            e.value = value;
+            afterNodeAccess(e);
+            return oldValue;
+        }
+        return null;
+    }
+
+    @Override
+    public V computeIfAbsent(K key,
+                             Function<? super K, ? extends V> mappingFunction) {
+        if (mappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+            V oldValue;
+            if (old != null && (oldValue = old.value) != null) {
+                afterNodeAccess(old);
+                return oldValue;
+            }
+        }
+        V v = mappingFunction.apply(key);
+        if (v == null) {
+            return null;
+        } else if (old != null) {
+            old.value = v;
+            afterNodeAccess(old);
+            return v;
+        }
+        else if (t != null)
+            t.putTreeVal(this, tab, hash, key, v);
+        else {
+            tab[i] = newNode(hash, key, v, first);
+            if (binCount >= TREEIFY_THRESHOLD - 1)
+                treeifyBin(tab, hash);
+        }
+        ++modCount;
+        ++size;
+        afterNodeInsertion(true);
+        return v;
+    }
+
+    public V computeIfPresent(K key,
+                              BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (remappingFunction == null)
+            throw new NullPointerException();
+        Node<K,V> e; V oldValue;
+        int hash = hash(key);
+        if ((e = getNode(hash, key)) != null &&
+            (oldValue = e.value) != null) {
+            V v = remappingFunction.apply(key, oldValue);
+            if (v != null) {
+                e.value = v;
+                afterNodeAccess(e);
+                return v;
+            }
+            else
+                removeNode(hash, key, null, false, true);
+        }
+        return null;
+    }
+
+    @Override
+    public V compute(K key,
+                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (remappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+        }
+        V oldValue = (old == null) ? null : old.value;
+        V v = remappingFunction.apply(key, oldValue);
+        if (old != null) {
+            if (v != null) {
+                old.value = v;
+                afterNodeAccess(old);
+            }
+            else
+                removeNode(hash, key, null, false, true);
+        }
+        else if (v != null) {
+            if (t != null)
+                t.putTreeVal(this, tab, hash, key, v);
+            else {
+                tab[i] = newNode(hash, key, v, first);
+                if (binCount >= TREEIFY_THRESHOLD - 1)
+                    treeifyBin(tab, hash);
+            }
+            ++modCount;
+            ++size;
+            afterNodeInsertion(true);
+        }
+        return v;
+    }
+
+    @Override
+    public V merge(K key, V value,
+                   BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        if (value == null)
+            throw new NullPointerException();
+        if (remappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+        }
+        if (old != null) {
+            V v;
+            if (old.value != null)
+                v = remappingFunction.apply(old.value, value);
+            else
+                v = value;
+            if (v != null) {
+                old.value = v;
+                afterNodeAccess(old);
+            }
+            else
+                removeNode(hash, key, null, false, true);
+            return v;
+        }
+        if (value != null) {
+            if (t != null)
+                t.putTreeVal(this, tab, hash, key, value);
+            else {
+                tab[i] = newNode(hash, key, value, first);
+                if (binCount >= TREEIFY_THRESHOLD - 1)
+                    treeifyBin(tab, hash);
+            }
+            ++modCount;
+            ++size;
+            afterNodeInsertion(true);
+        }
+        return value;
+    }
+
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Node<K,V>[] tab;
+        if (action == null)
+            throw new NullPointerException();
+        if (size > 0 && (tab = table) != null) {
+            int mc = modCount;
+            // Android-changed: Detect changes to modCount early.
+            for (int i = 0; (i < tab.length && mc == modCount); ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                    action.accept(e.key, e.value);
+            }
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Node<K,V>[] tab;
+        if (function == null)
+            throw new NullPointerException();
+        if (size > 0 && (tab = table) != null) {
+            int mc = modCount;
+            for (int i = 0; i < tab.length; ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+                    e.value = function.apply(e.key, e.value);
+                }
+            }
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // Cloning and serialization
+
+    /**
+     * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
+     * values themselves are not cloned.
+     *
+     * @return a shallow copy of this map
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public Object clone() {
+        HashMap<K,V> result;
+        try {
+            result = (HashMap<K,V>)super.clone();
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+        result.reinitialize();
+        result.putMapEntries(this, false);
+        return result;
+    }
+
+    // These methods are also used when serializing HashSets
+    final float loadFactor() { return loadFactor; }
+    final int capacity() {
+        return (table != null) ? table.length :
+            (threshold > 0) ? threshold :
+            DEFAULT_INITIAL_CAPACITY;
+    }
+
+    /**
+     * Save the state of the <tt>HashMap</tt> instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <i>capacity</i> of the HashMap (the length of the
+     *             bucket array) is emitted (int), followed by the
+     *             <i>size</i> (an int, the number of key-value
+     *             mappings), followed by the key (Object) and value (Object)
+     *             for each key-value mapping.  The key-value mappings are
+     *             emitted in no particular order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws IOException {
+        int buckets = capacity();
+        // Write out the threshold, loadfactor, and any hidden stuff
+        s.defaultWriteObject();
+        s.writeInt(buckets);
+        s.writeInt(size);
+        internalWriteEntries(s);
+    }
+
+    /**
+     * Reconstitute the {@code HashMap} instance from a stream (i.e.,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws IOException, ClassNotFoundException {
+        // Read in the threshold (ignored), loadfactor, and any hidden stuff
+        s.defaultReadObject();
+        reinitialize();
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new InvalidObjectException("Illegal load factor: " +
+                                             loadFactor);
+        s.readInt();                // Read and ignore number of buckets
+        int mappings = s.readInt(); // Read number of mappings (size)
+        if (mappings < 0)
+            throw new InvalidObjectException("Illegal mappings count: " +
+                                             mappings);
+        else if (mappings > 0) { // (if zero, use defaults)
+            // Size the table using given load factor only if within
+            // range of 0.25...4.0
+            float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
+            float fc = (float)mappings / lf + 1.0f;
+            int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
+                       DEFAULT_INITIAL_CAPACITY :
+                       (fc >= MAXIMUM_CAPACITY) ?
+                       MAXIMUM_CAPACITY :
+                       tableSizeFor((int)fc));
+            float ft = (float)cap * lf;
+            threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
+                         (int)ft : Integer.MAX_VALUE);
+            @SuppressWarnings({"rawtypes","unchecked"})
+                Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
+            table = tab;
+
+            // Read the keys and values, and put the mappings in the HashMap
+            for (int i = 0; i < mappings; i++) {
+                @SuppressWarnings("unchecked")
+                    K key = (K) s.readObject();
+                @SuppressWarnings("unchecked")
+                    V value = (V) s.readObject();
+                putVal(hash(key), key, value, false, false);
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // iterators
+
+    abstract class HashIterator {
+        Node<K,V> next;        // next entry to return
+        Node<K,V> current;     // current entry
+        int expectedModCount;  // for fast-fail
+        int index;             // current slot
+
+        HashIterator() {
+            expectedModCount = modCount;
+            Node<K,V>[] t = table;
+            current = next = null;
+            index = 0;
+            if (t != null && size > 0) { // advance to first entry
+                do {} while (index < t.length && (next = t[index++]) == null);
+            }
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        final Node<K,V> nextNode() {
+            Node<K,V>[] t;
+            Node<K,V> e = next;
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (e == null)
+                throw new NoSuchElementException();
+            if ((next = (current = e).next) == null && (t = table) != null) {
+                do {} while (index < t.length && (next = t[index++]) == null);
+            }
+            return e;
+        }
+
+        public final void remove() {
+            Node<K,V> p = current;
+            if (p == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            current = null;
+            K key = p.key;
+            removeNode(hash(key), key, null, false, false);
+            expectedModCount = modCount;
+        }
+    }
+
+    final class KeyIterator extends HashIterator
+        implements Iterator<K> {
+        public final K next() { return nextNode().key; }
+    }
+
+    final class ValueIterator extends HashIterator
+        implements Iterator<V> {
+        public final V next() { return nextNode().value; }
+    }
+
+    final class EntryIterator extends HashIterator
+        implements Iterator<Map.Entry<K,V>> {
+        public final Map.Entry<K,V> next() { return nextNode(); }
+    }
+
+    /* ------------------------------------------------------------ */
+    // spliterators
+
+    static class HashMapSpliterator<K,V> {
+        final HashMap<K,V> map;
+        Node<K,V> current;          // current node
+        int index;                  // current index, modified on advance/split
+        int fence;                  // one past last index
+        int est;                    // size estimate
+        int expectedModCount;       // for comodification checks
+
+        HashMapSpliterator(HashMap<K,V> m, int origin,
+                           int fence, int est,
+                           int expectedModCount) {
+            this.map = m;
+            this.index = origin;
+            this.fence = fence;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getFence() { // initialize fence and size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                HashMap<K,V> m = map;
+                est = m.size;
+                expectedModCount = m.modCount;
+                Node<K,V>[] tab = m.table;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            return hi;
+        }
+
+        public final long estimateSize() {
+            getFence(); // force init
+            return (long) est;
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends HashMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(HashMap<K,V> m, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid || current != null) ? null :
+                new KeySpliterator<>(map, lo, index = mid, est >>>= 1,
+                                        expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            HashMap<K,V> m = map;
+            Node<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
+                current = null;
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        action.accept(p.key);
+                        p = p.next;
+                    }
+                } while (p != null || i < hi);
+                if (m.modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        K k = current.key;
+                        current = current.next;
+                        action.accept(k);
+                        if (map.modCount != expectedModCount)
+                            throw new ConcurrentModificationException();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+        extends HashMapSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(HashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid || current != null) ? null :
+                new ValueSpliterator<>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            HashMap<K,V> m = map;
+            Node<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
+                current = null;
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        action.accept(p.value);
+                        p = p.next;
+                    }
+                } while (p != null || i < hi);
+                if (m.modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        V v = current.value;
+                        current = current.next;
+                        action.accept(v);
+                        if (map.modCount != expectedModCount)
+                            throw new ConcurrentModificationException();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0);
+        }
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends HashMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(HashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid || current != null) ? null :
+                new EntrySpliterator<>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            HashMap<K,V> m = map;
+            Node<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
+                current = null;
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        action.accept(p);
+                        p = p.next;
+                    }
+                } while (p != null || i < hi);
+                if (m.modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Node<K,V> e = current;
+                        current = current.next;
+                        action.accept(e);
+                        if (map.modCount != expectedModCount)
+                            throw new ConcurrentModificationException();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // LinkedHashMap support
+
+
+    /*
+     * The following package-protected methods are designed to be
+     * overridden by LinkedHashMap, but not by any other subclass.
+     * Nearly all other internal methods are also package-protected
+     * but are declared final, so can be used by LinkedHashMap, view
+     * classes, and HashSet.
+     */
+
+    // Create a regular (non-tree) node
+    Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
+        return new Node<>(hash, key, value, next);
+    }
+
+    // For conversion from TreeNodes to plain nodes
+    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
+        return new Node<>(p.hash, p.key, p.value, next);
+    }
+
+    // Create a tree bin node
+    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
+        return new TreeNode<>(hash, key, value, next);
+    }
+
+    // For treeifyBin
+    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
+        return new TreeNode<>(p.hash, p.key, p.value, next);
+    }
+
+    /**
+     * Reset to initial default state.  Called by clone and readObject.
+     */
+    void reinitialize() {
+        table = null;
+        entrySet = null;
+        keySet = null;
+        values = null;
+        modCount = 0;
+        threshold = 0;
+        size = 0;
+    }
+
+    // Callbacks to allow LinkedHashMap post-actions
+    void afterNodeAccess(Node<K,V> p) { }
+    void afterNodeInsertion(boolean evict) { }
+    void afterNodeRemoval(Node<K,V> p) { }
+
+    // Called only from writeObject, to ensure compatible ordering.
+    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
+        Node<K,V>[] tab;
+        if (size > 0 && (tab = table) != null) {
+            for (int i = 0; i < tab.length; ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+                    s.writeObject(e.key);
+                    s.writeObject(e.value);
+                }
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // Tree bins
+
+    /**
+     * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
+     * extends Node) so can be used as extension of either regular or
+     * linked node.
+     */
+    static final class TreeNode<K,V> extends LinkedHashMap.LinkedHashMapEntry<K,V> {
+        TreeNode<K,V> parent;  // red-black tree links
+        TreeNode<K,V> left;
+        TreeNode<K,V> right;
+        TreeNode<K,V> prev;    // needed to unlink next upon deletion
+        boolean red;
+        TreeNode(int hash, K key, V val, Node<K,V> next) {
+            super(hash, key, val, next);
+        }
+
+        /**
+         * Returns root of tree containing this node.
+         */
+        final TreeNode<K,V> root() {
+            for (TreeNode<K,V> r = this, p;;) {
+                if ((p = r.parent) == null)
+                    return r;
+                r = p;
+            }
+        }
+
+        /**
+         * Ensures that the given root is the first node of its bin.
+         */
+        static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {
+            int n;
+            if (root != null && tab != null && (n = tab.length) > 0) {
+                int index = (n - 1) & root.hash;
+                TreeNode<K,V> first = (TreeNode<K,V>)tab[index];
+                if (root != first) {
+                    Node<K,V> rn;
+                    tab[index] = root;
+                    TreeNode<K,V> rp = root.prev;
+                    if ((rn = root.next) != null)
+                        ((TreeNode<K,V>)rn).prev = rp;
+                    if (rp != null)
+                        rp.next = rn;
+                    if (first != null)
+                        first.prev = root;
+                    root.next = first;
+                    root.prev = null;
+                }
+                assert checkInvariants(root);
+            }
+        }
+
+        /**
+         * Finds the node starting at root p with the given hash and key.
+         * The kc argument caches comparableClassFor(key) upon first use
+         * comparing keys.
+         */
+        final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
+            TreeNode<K,V> p = this;
+            do {
+                int ph, dir; K pk;
+                TreeNode<K,V> pl = p.left, pr = p.right, q;
+                if ((ph = p.hash) > h)
+                    p = pl;
+                else if (ph < h)
+                    p = pr;
+                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
+                    return p;
+                else if (pl == null)
+                    p = pr;
+                else if (pr == null)
+                    p = pl;
+                else if ((kc != null ||
+                          (kc = comparableClassFor(k)) != null) &&
+                         (dir = compareComparables(kc, k, pk)) != 0)
+                    p = (dir < 0) ? pl : pr;
+                else if ((q = pr.find(h, k, kc)) != null)
+                    return q;
+                else
+                    p = pl;
+            } while (p != null);
+            return null;
+        }
+
+        /**
+         * Calls find for root node.
+         */
+        final TreeNode<K,V> getTreeNode(int h, Object k) {
+            return ((parent != null) ? root() : this).find(h, k, null);
+        }
+
+        /**
+         * Tie-breaking utility for ordering insertions when equal
+         * hashCodes and non-comparable. We don't require a total
+         * order, just a consistent insertion rule to maintain
+         * equivalence across rebalancings. Tie-breaking further than
+         * necessary simplifies testing a bit.
+         */
+        static int tieBreakOrder(Object a, Object b) {
+            int d;
+            if (a == null || b == null ||
+                (d = a.getClass().getName().
+                 compareTo(b.getClass().getName())) == 0)
+                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
+                     -1 : 1);
+            return d;
+        }
+
+        /**
+         * Forms tree of the nodes linked from this node.
+         * @return root of tree
+         */
+        final void treeify(Node<K,V>[] tab) {
+            TreeNode<K,V> root = null;
+            for (TreeNode<K,V> x = this, next; x != null; x = next) {
+                next = (TreeNode<K,V>)x.next;
+                x.left = x.right = null;
+                if (root == null) {
+                    x.parent = null;
+                    x.red = false;
+                    root = x;
+                }
+                else {
+                    K k = x.key;
+                    int h = x.hash;
+                    Class<?> kc = null;
+                    for (TreeNode<K,V> p = root;;) {
+                        int dir, ph;
+                        K pk = p.key;
+                        if ((ph = p.hash) > h)
+                            dir = -1;
+                        else if (ph < h)
+                            dir = 1;
+                        else if ((kc == null &&
+                                  (kc = comparableClassFor(k)) == null) ||
+                                 (dir = compareComparables(kc, k, pk)) == 0)
+                            dir = tieBreakOrder(k, pk);
+
+                        TreeNode<K,V> xp = p;
+                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                            x.parent = xp;
+                            if (dir <= 0)
+                                xp.left = x;
+                            else
+                                xp.right = x;
+                            root = balanceInsertion(root, x);
+                            break;
+                        }
+                    }
+                }
+            }
+            moveRootToFront(tab, root);
+        }
+
+        /**
+         * Returns a list of non-TreeNodes replacing those linked from
+         * this node.
+         */
+        final Node<K,V> untreeify(HashMap<K,V> map) {
+            Node<K,V> hd = null, tl = null;
+            for (Node<K,V> q = this; q != null; q = q.next) {
+                Node<K,V> p = map.replacementNode(q, null);
+                if (tl == null)
+                    hd = p;
+                else
+                    tl.next = p;
+                tl = p;
+            }
+            return hd;
+        }
+
+        /**
+         * Tree version of putVal.
+         */
+        final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
+                                       int h, K k, V v) {
+            Class<?> kc = null;
+            boolean searched = false;
+            TreeNode<K,V> root = (parent != null) ? root() : this;
+            for (TreeNode<K,V> p = root;;) {
+                int dir, ph; K pk;
+                if ((ph = p.hash) > h)
+                    dir = -1;
+                else if (ph < h)
+                    dir = 1;
+                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
+                    return p;
+                else if ((kc == null &&
+                          (kc = comparableClassFor(k)) == null) ||
+                         (dir = compareComparables(kc, k, pk)) == 0) {
+                    if (!searched) {
+                        TreeNode<K,V> q, ch;
+                        searched = true;
+                        if (((ch = p.left) != null &&
+                             (q = ch.find(h, k, kc)) != null) ||
+                            ((ch = p.right) != null &&
+                             (q = ch.find(h, k, kc)) != null))
+                            return q;
+                    }
+                    dir = tieBreakOrder(k, pk);
+                }
+
+                TreeNode<K,V> xp = p;
+                if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                    Node<K,V> xpn = xp.next;
+                    TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
+                    if (dir <= 0)
+                        xp.left = x;
+                    else
+                        xp.right = x;
+                    xp.next = x;
+                    x.parent = x.prev = xp;
+                    if (xpn != null)
+                        ((TreeNode<K,V>)xpn).prev = x;
+                    moveRootToFront(tab, balanceInsertion(root, x));
+                    return null;
+                }
+            }
+        }
+
+        /**
+         * Removes the given node, that must be present before this call.
+         * This is messier than typical red-black deletion code because we
+         * cannot swap the contents of an interior node with a leaf
+         * successor that is pinned by "next" pointers that are accessible
+         * independently during traversal. So instead we swap the tree
+         * linkages. If the current tree appears to have too few nodes,
+         * the bin is converted back to a plain bin. (The test triggers
+         * somewhere between 2 and 6 nodes, depending on tree structure).
+         */
+        final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
+                                  boolean movable) {
+            int n;
+            if (tab == null || (n = tab.length) == 0)
+                return;
+            int index = (n - 1) & hash;
+            TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
+            TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
+            if (pred == null)
+                tab[index] = first = succ;
+            else
+                pred.next = succ;
+            if (succ != null)
+                succ.prev = pred;
+            if (first == null)
+                return;
+            if (root.parent != null)
+                root = root.root();
+            if (root == null || root.right == null ||
+                (rl = root.left) == null || rl.left == null) {
+                tab[index] = first.untreeify(map);  // too small
+                return;
+            }
+            TreeNode<K,V> p = this, pl = left, pr = right, replacement;
+            if (pl != null && pr != null) {
+                TreeNode<K,V> s = pr, sl;
+                while ((sl = s.left) != null) // find successor
+                    s = sl;
+                boolean c = s.red; s.red = p.red; p.red = c; // swap colors
+                TreeNode<K,V> sr = s.right;
+                TreeNode<K,V> pp = p.parent;
+                if (s == pr) { // p was s's direct parent
+                    p.parent = s;
+                    s.right = p;
+                }
+                else {
+                    TreeNode<K,V> sp = s.parent;
+                    if ((p.parent = sp) != null) {
+                        if (s == sp.left)
+                            sp.left = p;
+                        else
+                            sp.right = p;
+                    }
+                    if ((s.right = pr) != null)
+                        pr.parent = s;
+                }
+                p.left = null;
+                if ((p.right = sr) != null)
+                    sr.parent = p;
+                if ((s.left = pl) != null)
+                    pl.parent = s;
+                if ((s.parent = pp) == null)
+                    root = s;
+                else if (p == pp.left)
+                    pp.left = s;
+                else
+                    pp.right = s;
+                if (sr != null)
+                    replacement = sr;
+                else
+                    replacement = p;
+            }
+            else if (pl != null)
+                replacement = pl;
+            else if (pr != null)
+                replacement = pr;
+            else
+                replacement = p;
+            if (replacement != p) {
+                TreeNode<K,V> pp = replacement.parent = p.parent;
+                if (pp == null)
+                    root = replacement;
+                else if (p == pp.left)
+                    pp.left = replacement;
+                else
+                    pp.right = replacement;
+                p.left = p.right = p.parent = null;
+            }
+
+            TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);
+
+            if (replacement == p) {  // detach
+                TreeNode<K,V> pp = p.parent;
+                p.parent = null;
+                if (pp != null) {
+                    if (p == pp.left)
+                        pp.left = null;
+                    else if (p == pp.right)
+                        pp.right = null;
+                }
+            }
+            if (movable)
+                moveRootToFront(tab, r);
+        }
+
+        /**
+         * Splits nodes in a tree bin into lower and upper tree bins,
+         * or untreeifies if now too small. Called only from resize;
+         * see above discussion about split bits and indices.
+         *
+         * @param map the map
+         * @param tab the table for recording bin heads
+         * @param index the index of the table being split
+         * @param bit the bit of hash to split on
+         */
+        final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
+            TreeNode<K,V> b = this;
+            // Relink into lo and hi lists, preserving order
+            TreeNode<K,V> loHead = null, loTail = null;
+            TreeNode<K,V> hiHead = null, hiTail = null;
+            int lc = 0, hc = 0;
+            for (TreeNode<K,V> e = b, next; e != null; e = next) {
+                next = (TreeNode<K,V>)e.next;
+                e.next = null;
+                if ((e.hash & bit) == 0) {
+                    if ((e.prev = loTail) == null)
+                        loHead = e;
+                    else
+                        loTail.next = e;
+                    loTail = e;
+                    ++lc;
+                }
+                else {
+                    if ((e.prev = hiTail) == null)
+                        hiHead = e;
+                    else
+                        hiTail.next = e;
+                    hiTail = e;
+                    ++hc;
+                }
+            }
+
+            if (loHead != null) {
+                if (lc <= UNTREEIFY_THRESHOLD)
+                    tab[index] = loHead.untreeify(map);
+                else {
+                    tab[index] = loHead;
+                    if (hiHead != null) // (else is already treeified)
+                        loHead.treeify(tab);
+                }
+            }
+            if (hiHead != null) {
+                if (hc <= UNTREEIFY_THRESHOLD)
+                    tab[index + bit] = hiHead.untreeify(map);
+                else {
+                    tab[index + bit] = hiHead;
+                    if (loHead != null)
+                        hiHead.treeify(tab);
+                }
+            }
+        }
+
+        /* ------------------------------------------------------------ */
+        // Red-black tree methods, all adapted from CLR
+
+        static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
+                                              TreeNode<K,V> p) {
+            TreeNode<K,V> r, pp, rl;
+            if (p != null && (r = p.right) != null) {
+                if ((rl = p.right = r.left) != null)
+                    rl.parent = p;
+                if ((pp = r.parent = p.parent) == null)
+                    (root = r).red = false;
+                else if (pp.left == p)
+                    pp.left = r;
+                else
+                    pp.right = r;
+                r.left = p;
+                p.parent = r;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
+                                               TreeNode<K,V> p) {
+            TreeNode<K,V> l, pp, lr;
+            if (p != null && (l = p.left) != null) {
+                if ((lr = p.left = l.right) != null)
+                    lr.parent = p;
+                if ((pp = l.parent = p.parent) == null)
+                    (root = l).red = false;
+                else if (pp.right == p)
+                    pp.right = l;
+                else
+                    pp.left = l;
+                l.right = p;
+                p.parent = l;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
+                                                    TreeNode<K,V> x) {
+            x.red = true;
+            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
+                if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (!xp.red || (xpp = xp.parent) == null)
+                    return root;
+                if (xp == (xppl = xpp.left)) {
+                    if ((xppr = xpp.right) != null && xppr.red) {
+                        xppr.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.right) {
+                            root = rotateLeft(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateRight(root, xpp);
+                            }
+                        }
+                    }
+                }
+                else {
+                    if (xppl != null && xppl.red) {
+                        xppl.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.left) {
+                            root = rotateRight(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateLeft(root, xpp);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
+                                                   TreeNode<K,V> x) {
+            for (TreeNode<K,V> xp, xpl, xpr;;)  {
+                if (x == null || x == root)
+                    return root;
+                else if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (x.red) {
+                    x.red = false;
+                    return root;
+                }
+                else if ((xpl = xp.left) == x) {
+                    if ((xpr = xp.right) != null && xpr.red) {
+                        xpr.red = false;
+                        xp.red = true;
+                        root = rotateLeft(root, xp);
+                        xpr = (xp = x.parent) == null ? null : xp.right;
+                    }
+                    if (xpr == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpr.left, sr = xpr.right;
+                        if ((sr == null || !sr.red) &&
+                            (sl == null || !sl.red)) {
+                            xpr.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sr == null || !sr.red) {
+                                if (sl != null)
+                                    sl.red = false;
+                                xpr.red = true;
+                                root = rotateRight(root, xpr);
+                                xpr = (xp = x.parent) == null ?
+                                    null : xp.right;
+                            }
+                            if (xpr != null) {
+                                xpr.red = (xp == null) ? false : xp.red;
+                                if ((sr = xpr.right) != null)
+                                    sr.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateLeft(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+                else { // symmetric
+                    if (xpl != null && xpl.red) {
+                        xpl.red = false;
+                        xp.red = true;
+                        root = rotateRight(root, xp);
+                        xpl = (xp = x.parent) == null ? null : xp.left;
+                    }
+                    if (xpl == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpl.left, sr = xpl.right;
+                        if ((sl == null || !sl.red) &&
+                            (sr == null || !sr.red)) {
+                            xpl.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sl == null || !sl.red) {
+                                if (sr != null)
+                                    sr.red = false;
+                                xpl.red = true;
+                                root = rotateLeft(root, xpl);
+                                xpl = (xp = x.parent) == null ?
+                                    null : xp.left;
+                            }
+                            if (xpl != null) {
+                                xpl.red = (xp == null) ? false : xp.red;
+                                if ((sl = xpl.left) != null)
+                                    sl.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateRight(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Recursive invariant check
+         */
+        static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
+            TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
+                tb = t.prev, tn = (TreeNode<K,V>)t.next;
+            if (tb != null && tb.next != t)
+                return false;
+            if (tn != null && tn.prev != t)
+                return false;
+            if (tp != null && t != tp.left && t != tp.right)
+                return false;
+            if (tl != null && (tl.parent != t || tl.hash > t.hash))
+                return false;
+            if (tr != null && (tr.parent != t || tr.hash < t.hash))
+                return false;
+            if (t.red && tl != null && tl.red && tr != null && tr.red)
+                return false;
+            if (tl != null && !checkInvariants(tl))
+                return false;
+            if (tr != null && !checkInvariants(tr))
+                return false;
+            return true;
+        }
+    }
+
+}
diff --git a/java/util/HashSet.annotated.java b/java/util/HashSet.annotated.java
new file mode 100644
index 0000000..c099118
--- /dev/null
+++ b/java/util/HashSet.annotated.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class HashSet<E> extends java.util.AbstractSet<E> implements java.util.Set<E>, java.lang.Cloneable, java.io.Serializable {
+
+public HashSet() { throw new RuntimeException("Stub!"); }
+
+public HashSet(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public HashSet(int initialCapacity, float loadFactor) { throw new RuntimeException("Stub!"); }
+
+public HashSet(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/HashSet.java b/java/util/HashSet.java
new file mode 100644
index 0000000..f9b09ee
--- /dev/null
+++ b/java/util/HashSet.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.InvalidObjectException;
+
+/**
+ * This class implements the <tt>Set</tt> interface, backed by a hash table
+ * (actually a <tt>HashMap</tt> instance).  It makes no guarantees as to the
+ * iteration order of the set; in particular, it does not guarantee that the
+ * order will remain constant over time.  This class permits the <tt>null</tt>
+ * element.
+ *
+ * <p>This class offers constant time performance for the basic operations
+ * (<tt>add</tt>, <tt>remove</tt>, <tt>contains</tt> and <tt>size</tt>),
+ * assuming the hash function disperses the elements properly among the
+ * buckets.  Iterating over this set requires time proportional to the sum of
+ * the <tt>HashSet</tt> instance's size (the number of elements) plus the
+ * "capacity" of the backing <tt>HashMap</tt> instance (the number of
+ * buckets).  Thus, it's very important not to set the initial capacity too
+ * high (or the load factor too low) if iteration performance is important.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a hash set concurrently, and at least one of
+ * the threads modifies the set, it <i>must</i> be synchronized externally.
+ * This is typically accomplished by synchronizing on some object that
+ * naturally encapsulates the set.
+ *
+ * If no such object exists, the set should be "wrapped" using the
+ * {@link Collections#synchronizedSet Collections.synchronizedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the set:<pre>
+ *   Set s = Collections.synchronizedSet(new HashSet(...));</pre>
+ *
+ * <p>The iterators returned by this class's <tt>iterator</tt> method are
+ * <i>fail-fast</i>: if the set is modified at any time after the iterator is
+ * created, in any way except through the iterator's own <tt>remove</tt>
+ * method, the Iterator throws 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 time in the future.
+ *
+ * <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.
+ * 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>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Collection
+ * @see     Set
+ * @see     TreeSet
+ * @see     HashMap
+ * @since   1.2
+ */
+
+public class HashSet<E>
+    extends AbstractSet<E>
+    implements Set<E>, Cloneable, java.io.Serializable
+{
+    static final long serialVersionUID = -5024744406713321676L;
+
+    private transient HashMap<E,Object> map;
+
+    // Dummy value to associate with an Object in the backing Map
+    private static final Object PRESENT = new Object();
+
+    /**
+     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
+     * default initial capacity (16) and load factor (0.75).
+     */
+    public HashSet() {
+        map = new HashMap<>();
+    }
+
+    /**
+     * Constructs a new set containing the elements in the specified
+     * collection.  The <tt>HashMap</tt> is created with default load factor
+     * (0.75) and an initial capacity sufficient to contain the elements in
+     * the specified collection.
+     *
+     * @param c the collection whose elements are to be placed into this set
+     * @throws NullPointerException if the specified collection is null
+     */
+    public HashSet(Collection<? extends E> c) {
+        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
+        addAll(c);
+    }
+
+    /**
+     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
+     * the specified initial capacity and the specified load factor.
+     *
+     * @param      initialCapacity   the initial capacity of the hash map
+     * @param      loadFactor        the load factor of the hash map
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero, or if the load factor is nonpositive
+     */
+    public HashSet(int initialCapacity, float loadFactor) {
+        map = new HashMap<>(initialCapacity, loadFactor);
+    }
+
+    /**
+     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
+     * the specified initial capacity and default load factor (0.75).
+     *
+     * @param      initialCapacity   the initial capacity of the hash table
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero
+     */
+    public HashSet(int initialCapacity) {
+        map = new HashMap<>(initialCapacity);
+    }
+
+    /**
+     * Constructs a new, empty linked hash set.  (This package private
+     * constructor is only used by LinkedHashSet.) The backing
+     * HashMap instance is a LinkedHashMap with the specified initial
+     * capacity and the specified load factor.
+     *
+     * @param      initialCapacity   the initial capacity of the hash map
+     * @param      loadFactor        the load factor of the hash map
+     * @param      dummy             ignored (distinguishes this
+     *             constructor from other int, float constructor.)
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero, or if the load factor is nonpositive
+     */
+    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
+        map = new LinkedHashMap<>(initialCapacity, loadFactor);
+    }
+
+    /**
+     * Returns an iterator over the elements in this set.  The elements
+     * are returned in no particular order.
+     *
+     * @return an Iterator over the elements in this set
+     * @see ConcurrentModificationException
+     */
+    public Iterator<E> iterator() {
+        return map.keySet().iterator();
+    }
+
+    /**
+     * Returns the number of elements in this set (its cardinality).
+     *
+     * @return the number of elements in this set (its cardinality)
+     */
+    public int size() {
+        return map.size();
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains no elements.
+     *
+     * @return <tt>true</tt> if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains the specified element.
+     * More formally, returns <tt>true</tt> if and only if this set
+     * contains an element <tt>e</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     *
+     * @param o element whose presence in this set is to be tested
+     * @return <tt>true</tt> if this set contains the specified element
+     */
+    public boolean contains(Object o) {
+        return map.containsKey(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element <tt>e</tt> to this set if
+     * this set contains no element <tt>e2</tt> such that
+     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns <tt>false</tt>.
+     *
+     * @param e element to be added to this set
+     * @return <tt>true</tt> if this set did not already contain the specified
+     * element
+     */
+    public boolean add(E e) {
+        return map.put(e, PRESENT)==null;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element <tt>e</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>,
+     * if this set contains such an element.  Returns <tt>true</tt> if
+     * this set contained the element (or equivalently, if this set
+     * changed as a result of the call).  (This set will not contain the
+     * element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return <tt>true</tt> if the set contained the specified element
+     */
+    public boolean remove(Object o) {
+        return map.remove(o)==PRESENT;
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     * The set will be empty after this call returns.
+     */
+    public void clear() {
+        map.clear();
+    }
+
+    /**
+     * Returns a shallow copy of this <tt>HashSet</tt> instance: the elements
+     * themselves are not cloned.
+     *
+     * @return a shallow copy of this set
+     */
+    @SuppressWarnings("unchecked")
+    public Object clone() {
+        try {
+            HashSet<E> newSet = (HashSet<E>) super.clone();
+            newSet.map = (HashMap<E, Object>) map.clone();
+            return newSet;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Save the state of this <tt>HashSet</tt> instance to a stream (that is,
+     * serialize it).
+     *
+     * @serialData The capacity of the backing <tt>HashMap</tt> instance
+     *             (int), and its load factor (float) are emitted, followed by
+     *             the size of the set (the number of elements it contains)
+     *             (int), followed by all of its elements (each an Object) in
+     *             no particular order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out any hidden serialization magic
+        s.defaultWriteObject();
+
+        // Write out HashMap capacity and load factor
+        s.writeInt(map.capacity());
+        s.writeFloat(map.loadFactor());
+
+        // Write out size
+        s.writeInt(map.size());
+
+        // Write out all elements in the proper order.
+        for (E e : map.keySet())
+            s.writeObject(e);
+    }
+
+    /**
+     * Reconstitute the <tt>HashSet</tt> instance from a stream (that is,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in any hidden serialization magic
+        s.defaultReadObject();
+
+        // Read capacity and verify non-negative.
+        int capacity = s.readInt();
+        if (capacity < 0) {
+            throw new InvalidObjectException("Illegal capacity: " +
+                                             capacity);
+        }
+
+        // Read load factor and verify positive and non NaN.
+        float loadFactor = s.readFloat();
+        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
+            throw new InvalidObjectException("Illegal load factor: " +
+                                             loadFactor);
+        }
+
+        // Read size and verify non-negative.
+        int size = s.readInt();
+        if (size < 0) {
+            throw new InvalidObjectException("Illegal size: " +
+                                             size);
+        }
+
+        // Set the capacity according to the size and load factor ensuring that
+        // the HashMap is at least 25% full but clamping to maximum capacity.
+        capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
+                HashMap.MAXIMUM_CAPACITY);
+
+        // Create backing HashMap
+        map = (((HashSet<?>)this) instanceof LinkedHashSet ?
+               new LinkedHashMap<E,Object>(capacity, loadFactor) :
+               new HashMap<E,Object>(capacity, loadFactor));
+
+        // Read in all elements in the proper order.
+        for (int i=0; i<size; i++) {
+            @SuppressWarnings("unchecked")
+                E e = (E) s.readObject();
+            map.put(e, PRESENT);
+        }
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#DISTINCT}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0);
+    }
+}
diff --git a/java/util/Hashtable.java b/java/util/Hashtable.java
new file mode 100644
index 0000000..4c76a74
--- /dev/null
+++ b/java/util/Hashtable.java
@@ -0,0 +1,1432 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.*;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * This class implements a hash table, which maps keys to values. Any
+ * non-<code>null</code> object can be used as a key or as a value. <p>
+ *
+ * To successfully store and retrieve objects from a hashtable, the
+ * objects used as keys must implement the <code>hashCode</code>
+ * method and the <code>equals</code> method. <p>
+ *
+ * An instance of <code>Hashtable</code> has two parameters that affect its
+ * performance: <i>initial capacity</i> and <i>load factor</i>.  The
+ * <i>capacity</i> is the number of <i>buckets</i> in the hash table, and the
+ * <i>initial capacity</i> is simply the capacity at the time the hash table
+ * is created.  Note that the hash table is <i>open</i>: in the case of a "hash
+ * collision", a single bucket stores multiple entries, which must be searched
+ * sequentially.  The <i>load factor</i> is a measure of how full the hash
+ * table is allowed to get before its capacity is automatically increased.
+ * The initial capacity and load factor parameters are merely hints to
+ * the implementation.  The exact details as to when and whether the rehash
+ * method is invoked are implementation-dependent.<p>
+ *
+ * Generally, the default load factor (.75) offers a good tradeoff between
+ * time and space costs.  Higher values decrease the space overhead but
+ * increase the time cost to look up an entry (which is reflected in most
+ * <tt>Hashtable</tt> operations, including <tt>get</tt> and <tt>put</tt>).<p>
+ *
+ * The initial capacity controls a tradeoff between wasted space and the
+ * need for <code>rehash</code> operations, which are time-consuming.
+ * No <code>rehash</code> operations will <i>ever</i> occur if the initial
+ * capacity is greater than the maximum number of entries the
+ * <tt>Hashtable</tt> will contain divided by its load factor.  However,
+ * setting the initial capacity too high can waste space.<p>
+ *
+ * If many entries are to be made into a <code>Hashtable</code>,
+ * creating it with a sufficiently large capacity may allow the
+ * entries to be inserted more efficiently than letting it perform
+ * automatic rehashing as needed to grow the table. <p>
+ *
+ * This example creates a hashtable of numbers. It uses the names of
+ * the numbers as keys:
+ * <pre>   {@code
+ *   Hashtable<String, Integer> numbers
+ *     = new Hashtable<String, Integer>();
+ *   numbers.put("one", 1);
+ *   numbers.put("two", 2);
+ *   numbers.put("three", 3);}</pre>
+ *
+ * <p>To retrieve a number, use the following code:
+ * <pre>   {@code
+ *   Integer n = numbers.get("two");
+ *   if (n != null) {
+ *     System.out.println("two = " + n);
+ *   }}</pre>
+ *
+ * <p>The iterators returned by the <tt>iterator</tt> method of the collections
+ * returned by all of this class's "collection view methods" are
+ * <em>fail-fast</em>: if the Hashtable is structurally modified at any time
+ * after the iterator is created, in any way except through the iterator's own
+ * <tt>remove</tt> method, 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 time in the future.
+ * The Enumerations returned by Hashtable's keys and elements methods are
+ * <em>not</em> fail-fast.
+ *
+ * <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.
+ * 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>
+ *
+ * <p>As of the Java 2 platform v1.2, this class was retrofitted to
+ * implement the {@link Map} interface, making it a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ *
+ * Java Collections Framework</a>.  Unlike the new collection
+ * implementations, {@code Hashtable} is synchronized.  If a
+ * thread-safe implementation is not needed, it is recommended to use
+ * {@link HashMap} in place of {@code Hashtable}.  If a thread-safe
+ * highly-concurrent implementation is desired, then it is recommended
+ * to use {@link java.util.concurrent.ConcurrentHashMap} in place of
+ * {@code Hashtable}.
+ *
+ * @author  Arthur van Hoff
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Object#equals(java.lang.Object)
+ * @see     Object#hashCode()
+ * @see     Hashtable#rehash()
+ * @see     Collection
+ * @see     Map
+ * @see     HashMap
+ * @see     TreeMap
+ * @since JDK1.0
+ */
+public class Hashtable<K,V>
+    extends Dictionary<K,V>
+    implements Map<K,V>, Cloneable, java.io.Serializable {
+
+    /**
+     * The hash table data.
+     */
+    private transient HashtableEntry<?,?>[] table;
+
+    /**
+     * The total number of entries in the hash table.
+     */
+    private transient int count;
+
+    /**
+     * The table is rehashed when its size exceeds this threshold.  (The
+     * value of this field is (int)(capacity * loadFactor).)
+     *
+     * @serial
+     */
+    private int threshold;
+
+    /**
+     * The load factor for the hashtable.
+     *
+     * @serial
+     */
+    private float loadFactor;
+
+    /**
+     * The number of times this Hashtable has been structurally modified
+     * Structural modifications are those that change the number of entries in
+     * the Hashtable or otherwise modify its internal structure (e.g.,
+     * rehash).  This field is used to make iterators on Collection-views of
+     * the Hashtable fail-fast.  (See ConcurrentModificationException).
+     */
+    private transient int modCount = 0;
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = 1421746759512286392L;
+
+    /**
+     * Constructs a new, empty hashtable with the specified initial
+     * capacity and the specified load factor.
+     *
+     * @param      initialCapacity   the initial capacity of the hashtable.
+     * @param      loadFactor        the load factor of the hashtable.
+     * @exception  IllegalArgumentException  if the initial capacity is less
+     *             than zero, or if the load factor is nonpositive.
+     */
+    public Hashtable(int initialCapacity, float loadFactor) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Capacity: "+
+                                               initialCapacity);
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal Load: "+loadFactor);
+
+        if (initialCapacity==0)
+            initialCapacity = 1;
+        this.loadFactor = loadFactor;
+        table = new HashtableEntry<?,?>[initialCapacity];
+        // Android-changed: Ignore loadFactor when calculating threshold from initialCapacity
+        // threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
+        threshold = (int)Math.min(initialCapacity, MAX_ARRAY_SIZE + 1);
+    }
+
+    /**
+     * Constructs a new, empty hashtable with the specified initial capacity
+     * and default load factor (0.75).
+     *
+     * @param     initialCapacity   the initial capacity of the hashtable.
+     * @exception IllegalArgumentException if the initial capacity is less
+     *              than zero.
+     */
+    public Hashtable(int initialCapacity) {
+        this(initialCapacity, 0.75f);
+    }
+
+    /**
+     * Constructs a new, empty hashtable with a default initial capacity (11)
+     * and load factor (0.75).
+     */
+    public Hashtable() {
+        this(11, 0.75f);
+    }
+
+    /**
+     * Constructs a new hashtable with the same mappings as the given
+     * Map.  The hashtable is created with an initial capacity sufficient to
+     * hold the mappings in the given Map and a default load factor (0.75).
+     *
+     * @param t the map whose mappings are to be placed in this map.
+     * @throws NullPointerException if the specified map is null.
+     * @since   1.2
+     */
+    public Hashtable(Map<? extends K, ? extends V> t) {
+        this(Math.max(2*t.size(), 11), 0.75f);
+        putAll(t);
+    }
+
+    /**
+     * Returns the number of keys in this hashtable.
+     *
+     * @return  the number of keys in this hashtable.
+     */
+    public synchronized int size() {
+        return count;
+    }
+
+    /**
+     * Tests if this hashtable maps no keys to values.
+     *
+     * @return  <code>true</code> if this hashtable maps no keys to values;
+     *          <code>false</code> otherwise.
+     */
+    public synchronized boolean isEmpty() {
+        return count == 0;
+    }
+
+    /**
+     * Returns an enumeration of the keys in this hashtable.
+     *
+     * @return  an enumeration of the keys in this hashtable.
+     * @see     Enumeration
+     * @see     #elements()
+     * @see     #keySet()
+     * @see     Map
+     */
+    public synchronized Enumeration<K> keys() {
+        return this.<K>getEnumeration(KEYS);
+    }
+
+    /**
+     * Returns an enumeration of the values in this hashtable.
+     * Use the Enumeration methods on the returned object to fetch the elements
+     * sequentially.
+     *
+     * @return  an enumeration of the values in this hashtable.
+     * @see     java.util.Enumeration
+     * @see     #keys()
+     * @see     #values()
+     * @see     Map
+     */
+    public synchronized Enumeration<V> elements() {
+        return this.<V>getEnumeration(VALUES);
+    }
+
+    /**
+     * Tests if some key maps into the specified value in this hashtable.
+     * This operation is more expensive than the {@link #containsKey
+     * containsKey} method.
+     *
+     * <p>Note that this method is identical in functionality to
+     * {@link #containsValue containsValue}, (which is part of the
+     * {@link Map} interface in the collections framework).
+     *
+     * @param      value   a value to search for
+     * @return     <code>true</code> if and only if some key maps to the
+     *             <code>value</code> argument in this hashtable as
+     *             determined by the <tt>equals</tt> method;
+     *             <code>false</code> otherwise.
+     * @exception  NullPointerException  if the value is <code>null</code>
+     */
+    public synchronized boolean contains(Object value) {
+        if (value == null) {
+            throw new NullPointerException();
+        }
+
+        HashtableEntry<?,?> tab[] = table;
+        for (int i = tab.length ; i-- > 0 ;) {
+            for (HashtableEntry<?,?> e = tab[i] ; e != null ; e = e.next) {
+                if (e.value.equals(value)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if this hashtable maps one or more keys to this value.
+     *
+     * <p>Note that this method is identical in functionality to {@link
+     * #contains contains} (which predates the {@link Map} interface).
+     *
+     * @param value value whose presence in this hashtable is to be tested
+     * @return <tt>true</tt> if this map maps one or more keys to the
+     *         specified value
+     * @throws NullPointerException  if the value is <code>null</code>
+     * @since 1.2
+     */
+    public boolean containsValue(Object value) {
+        return contains(value);
+    }
+
+    /**
+     * Tests if the specified object is a key in this hashtable.
+     *
+     * @param   key   possible key
+     * @return  <code>true</code> if and only if the specified object
+     *          is a key in this hashtable, as determined by the
+     *          <tt>equals</tt> method; <code>false</code> otherwise.
+     * @throws  NullPointerException  if the key is <code>null</code>
+     * @see     #contains(Object)
+     */
+    public synchronized boolean containsKey(Object key) {
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key.equals(k))},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * @param key the key whose associated value is to be returned
+     * @return the value to which the specified key is mapped, or
+     *         {@code null} if this map contains no mapping for the key
+     * @throws NullPointerException if the specified key is null
+     * @see     #put(Object, Object)
+     */
+    @SuppressWarnings("unchecked")
+    public synchronized V get(Object key) {
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                return (V)e.value;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Increases the capacity of and internally reorganizes this
+     * hashtable, in order to accommodate and access its entries more
+     * efficiently.  This method is called automatically when the
+     * number of keys in the hashtable exceeds this hashtable's capacity
+     * and load factor.
+     */
+    @SuppressWarnings("unchecked")
+    protected void rehash() {
+        int oldCapacity = table.length;
+        HashtableEntry<?,?>[] oldMap = table;
+
+        // overflow-conscious code
+        int newCapacity = (oldCapacity << 1) + 1;
+        if (newCapacity - MAX_ARRAY_SIZE > 0) {
+            if (oldCapacity == MAX_ARRAY_SIZE)
+                // Keep running with MAX_ARRAY_SIZE buckets
+                return;
+            newCapacity = MAX_ARRAY_SIZE;
+        }
+        HashtableEntry<?,?>[] newMap = new HashtableEntry<?,?>[newCapacity];
+
+        modCount++;
+        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
+        table = newMap;
+
+        for (int i = oldCapacity ; i-- > 0 ;) {
+            for (HashtableEntry<K,V> old = (HashtableEntry<K,V>)oldMap[i] ; old != null ; ) {
+                HashtableEntry<K,V> e = old;
+                old = old.next;
+
+                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
+                e.next = (HashtableEntry<K,V>)newMap[index];
+                newMap[index] = e;
+            }
+        }
+    }
+
+    private void addEntry(int hash, K key, V value, int index) {
+        modCount++;
+
+        HashtableEntry<?,?> tab[] = table;
+        if (count >= threshold) {
+            // Rehash the table if the threshold is exceeded
+            rehash();
+
+            tab = table;
+            hash = key.hashCode();
+            index = (hash & 0x7FFFFFFF) % tab.length;
+        }
+
+        // Creates the new entry.
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>) tab[index];
+        tab[index] = new HashtableEntry<>(hash, key, value, e);
+        count++;
+    }
+
+    /**
+     * Maps the specified <code>key</code> to the specified
+     * <code>value</code> in this hashtable. Neither the key nor the
+     * value can be <code>null</code>. <p>
+     *
+     * The value can be retrieved by calling the <code>get</code> method
+     * with a key that is equal to the original key.
+     *
+     * @param      key     the hashtable key
+     * @param      value   the value
+     * @return     the previous value of the specified key in this hashtable,
+     *             or <code>null</code> if it did not have one
+     * @exception  NullPointerException  if the key or value is
+     *               <code>null</code>
+     * @see     Object#equals(Object)
+     * @see     #get(Object)
+     */
+    public synchronized V put(K key, V value) {
+        // Make sure the value is not null
+        if (value == null) {
+            throw new NullPointerException();
+        }
+
+        // Makes sure the key is not already in the hashtable.
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> entry = (HashtableEntry<K,V>)tab[index];
+        for(; entry != null ; entry = entry.next) {
+            if ((entry.hash == hash) && entry.key.equals(key)) {
+                V old = entry.value;
+                entry.value = value;
+                return old;
+            }
+        }
+
+        addEntry(hash, key, value, index);
+        return null;
+    }
+
+    /**
+     * Removes the key (and its corresponding value) from this
+     * hashtable. This method does nothing if the key is not in the hashtable.
+     *
+     * @param   key   the key that needs to be removed
+     * @return  the value to which the key had been mapped in this hashtable,
+     *          or <code>null</code> if the key did not have a mapping
+     * @throws  NullPointerException  if the key is <code>null</code>
+     */
+    public synchronized V remove(Object key) {
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for(HashtableEntry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                modCount++;
+                if (prev != null) {
+                    prev.next = e.next;
+                } else {
+                    tab[index] = e.next;
+                }
+                count--;
+                V oldValue = e.value;
+                e.value = null;
+                return oldValue;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this hashtable.
+     * These mappings will replace any mappings that this hashtable had for any
+     * of the keys currently in the specified map.
+     *
+     * @param t mappings to be stored in this map
+     * @throws NullPointerException if the specified map is null
+     * @since 1.2
+     */
+    public synchronized void putAll(Map<? extends K, ? extends V> t) {
+        for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * Clears this hashtable so that it contains no keys.
+     */
+    public synchronized void clear() {
+        HashtableEntry<?,?> tab[] = table;
+        modCount++;
+        for (int index = tab.length; --index >= 0; )
+            tab[index] = null;
+        count = 0;
+    }
+
+    /**
+     * Creates a shallow copy of this hashtable. All the structure of the
+     * hashtable itself is copied, but the keys and values are not cloned.
+     * This is a relatively expensive operation.
+     *
+     * @return  a clone of the hashtable
+     */
+    public synchronized Object clone() {
+        try {
+            Hashtable<?,?> t = (Hashtable<?,?>)super.clone();
+            t.table = new HashtableEntry<?,?>[table.length];
+            for (int i = table.length ; i-- > 0 ; ) {
+                t.table[i] = (table[i] != null)
+                    ? (HashtableEntry<?,?>) table[i].clone() : null;
+            }
+            t.keySet = null;
+            t.entrySet = null;
+            t.values = null;
+            t.modCount = 0;
+            return t;
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns a string representation of this <tt>Hashtable</tt> object
+     * in the form of a set of entries, enclosed in braces and separated
+     * by the ASCII characters "<tt>,&nbsp;</tt>" (comma and space). Each
+     * entry is rendered as the key, an equals sign <tt>=</tt>, and the
+     * associated element, where the <tt>toString</tt> method is used to
+     * convert the key and element to strings.
+     *
+     * @return  a string representation of this hashtable
+     */
+    public synchronized String toString() {
+        int max = size() - 1;
+        if (max == -1)
+            return "{}";
+
+        StringBuilder sb = new StringBuilder();
+        Iterator<Map.Entry<K,V>> it = entrySet().iterator();
+
+        sb.append('{');
+        for (int i = 0; ; i++) {
+            Map.Entry<K,V> e = it.next();
+            K key = e.getKey();
+            V value = e.getValue();
+            sb.append(key   == this ? "(this Map)" : key.toString());
+            sb.append('=');
+            sb.append(value == this ? "(this Map)" : value.toString());
+
+            if (i == max)
+                return sb.append('}').toString();
+            sb.append(", ");
+        }
+    }
+
+
+    private <T> Enumeration<T> getEnumeration(int type) {
+        if (count == 0) {
+            return Collections.emptyEnumeration();
+        } else {
+            return new Enumerator<>(type, false);
+        }
+    }
+
+    private <T> Iterator<T> getIterator(int type) {
+        if (count == 0) {
+            return Collections.emptyIterator();
+        } else {
+            return new Enumerator<>(type, true);
+        }
+    }
+
+    // Views
+
+    /**
+     * Each of these fields are initialized to contain an instance of the
+     * appropriate view the first time this view is requested.  The views are
+     * stateless, so there's no reason to create more than one of each.
+     */
+    private transient volatile Set<K> keySet;
+    private transient volatile Set<Map.Entry<K,V>> entrySet;
+    private transient volatile Collection<V> values;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+     * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
+     * operations.
+     *
+     * @since 1.2
+     */
+    public Set<K> keySet() {
+        if (keySet == null)
+            keySet = Collections.synchronizedSet(new KeySet(), this);
+        return keySet;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return getIterator(KEYS);
+        }
+        public int size() {
+            return count;
+        }
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+        public boolean remove(Object o) {
+            return Hashtable.this.remove(o) != null;
+        }
+        public void clear() {
+            Hashtable.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation, or through the
+     * <tt>setValue</tt> operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
+     * <tt>clear</tt> operations.  It does not support the
+     * <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @since 1.2
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        if (entrySet==null)
+            entrySet = Collections.synchronizedSet(new EntrySet(), this);
+        return entrySet;
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return getIterator(ENTRIES);
+        }
+
+        public boolean add(Map.Entry<K,V> o) {
+            return super.add(o);
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+            Object key = entry.getKey();
+            HashtableEntry<?,?>[] tab = table;
+            int hash = key.hashCode();
+            int index = (hash & 0x7FFFFFFF) % tab.length;
+
+            for (HashtableEntry<?,?> e = tab[index]; e != null; e = e.next)
+                if (e.hash==hash && e.equals(entry))
+                    return true;
+            return false;
+        }
+
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
+            Object key = entry.getKey();
+            HashtableEntry<?,?>[] tab = table;
+            int hash = key.hashCode();
+            int index = (hash & 0x7FFFFFFF) % tab.length;
+
+            @SuppressWarnings("unchecked")
+            HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+            for(HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+                if (e.hash==hash && e.equals(entry)) {
+                    modCount++;
+                    if (prev != null)
+                        prev.next = e.next;
+                    else
+                        tab[index] = e.next;
+
+                    count--;
+                    e.value = null;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int size() {
+            return count;
+        }
+
+        public void clear() {
+            Hashtable.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own <tt>remove</tt> operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
+     * support the <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @since 1.2
+     */
+    public Collection<V> values() {
+        if (values==null)
+            values = Collections.synchronizedCollection(new ValueCollection(),
+                                                        this);
+        return values;
+    }
+
+    private class ValueCollection extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return getIterator(VALUES);
+        }
+        public int size() {
+            return count;
+        }
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+        public void clear() {
+            Hashtable.this.clear();
+        }
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified Object with this Map for equality,
+     * as per the definition in the Map interface.
+     *
+     * @param  o object to be compared for equality with this hashtable
+     * @return true if the specified Object is equal to this Map
+     * @see Map#equals(Object)
+     * @since 1.2
+     */
+    public synchronized boolean equals(Object o) {
+        if (o == this)
+            return true;
+
+        if (!(o instanceof Map))
+            return false;
+        Map<?,?> t = (Map<?,?>) o;
+        if (t.size() != size())
+            return false;
+
+        try {
+            Iterator<Map.Entry<K,V>> i = entrySet().iterator();
+            while (i.hasNext()) {
+                Map.Entry<K,V> e = i.next();
+                K key = e.getKey();
+                V value = e.getValue();
+                if (value == null) {
+                    if (!(t.get(key)==null && t.containsKey(key)))
+                        return false;
+                } else {
+                    if (!value.equals(t.get(key)))
+                        return false;
+                }
+            }
+        } catch (ClassCastException unused)   {
+            return false;
+        } catch (NullPointerException unused) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns the hash code value for this Map as per the definition in the
+     * Map interface.
+     *
+     * @see Map#hashCode()
+     * @since 1.2
+     */
+    public synchronized int hashCode() {
+        /*
+         * This code detects the recursion caused by computing the hash code
+         * of a self-referential hash table and prevents the stack overflow
+         * that would otherwise result.  This allows certain 1.1-era
+         * applets with self-referential hash tables to work.  This code
+         * abuses the loadFactor field to do double-duty as a hashCode
+         * in progress flag, so as not to worsen the space performance.
+         * A negative load factor indicates that hash code computation is
+         * in progress.
+         */
+        int h = 0;
+        if (count == 0 || loadFactor < 0)
+            return h;  // Returns zero
+
+        loadFactor = -loadFactor;  // Mark hashCode computation in progress
+        HashtableEntry<?,?>[] tab = table;
+        for (HashtableEntry<?,?> entry : tab) {
+            while (entry != null) {
+                h += entry.hashCode();
+                entry = entry.next;
+            }
+        }
+
+        loadFactor = -loadFactor;  // Mark hashCode computation complete
+
+        return h;
+    }
+
+    @Override
+    public synchronized V getOrDefault(Object key, V defaultValue) {
+        V result = get(key);
+        return (null == result) ? defaultValue : result;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);     // explicit check required in case
+                                            // table is empty.
+        final int expectedModCount = modCount;
+
+        HashtableEntry<?, ?>[] tab = table;
+        for (HashtableEntry<?, ?> entry : tab) {
+            while (entry != null) {
+                action.accept((K)entry.key, (V)entry.value);
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);     // explicit check required in case
+                                              // table is empty.
+        final int expectedModCount = modCount;
+
+        HashtableEntry<K, V>[] tab = (HashtableEntry<K, V>[])table;
+        for (HashtableEntry<K, V> entry : tab) {
+            while (entry != null) {
+                entry.value = Objects.requireNonNull(
+                    function.apply(entry.key, entry.value));
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    @Override
+    public synchronized V putIfAbsent(K key, V value) {
+        Objects.requireNonNull(value);
+
+        // Makes sure the key is not already in the hashtable.
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> entry = (HashtableEntry<K,V>)tab[index];
+        for (; entry != null; entry = entry.next) {
+            if ((entry.hash == hash) && entry.key.equals(key)) {
+                V old = entry.value;
+                if (old == null) {
+                    entry.value = value;
+                }
+                return old;
+            }
+        }
+
+        addEntry(hash, key, value, index);
+        return null;
+    }
+
+    @Override
+    public synchronized boolean remove(Object key, Object value) {
+        Objects.requireNonNull(value);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {
+                modCount++;
+                if (prev != null) {
+                    prev.next = e.next;
+                } else {
+                    tab[index] = e.next;
+                }
+                count--;
+                e.value = null;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public synchronized boolean replace(K key, V oldValue, V newValue) {
+        Objects.requireNonNull(oldValue);
+        Objects.requireNonNull(newValue);
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (; e != null; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                if (e.value.equals(oldValue)) {
+                    e.value = newValue;
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public synchronized V replace(K key, V value) {
+        Objects.requireNonNull(value);
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (; e != null; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                V oldValue = e.value;
+                e.value = value;
+                return oldValue;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+        Objects.requireNonNull(mappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (; e != null; e = e.next) {
+            if (e.hash == hash && e.key.equals(key)) {
+                // Hashtable not accept null value
+                return e.value;
+            }
+        }
+
+        V newValue = mappingFunction.apply(key);
+        if (newValue != null) {
+            addEntry(hash, key, newValue, index);
+        }
+
+        return newValue;
+    }
+
+    @Override
+    public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if (e.hash == hash && e.key.equals(key)) {
+                V newValue = remappingFunction.apply(key, e.value);
+                if (newValue == null) {
+                    modCount++;
+                    if (prev != null) {
+                        prev.next = e.next;
+                    } else {
+                        tab[index] = e.next;
+                    }
+                    count--;
+                } else {
+                    e.value = newValue;
+                }
+                return newValue;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if (e.hash == hash && Objects.equals(e.key, key)) {
+                V newValue = remappingFunction.apply(key, e.value);
+                if (newValue == null) {
+                    modCount++;
+                    if (prev != null) {
+                        prev.next = e.next;
+                    } else {
+                        tab[index] = e.next;
+                    }
+                    count--;
+                } else {
+                    e.value = newValue;
+                }
+                return newValue;
+            }
+        }
+
+        V newValue = remappingFunction.apply(key, null);
+        if (newValue != null) {
+            addEntry(hash, key, newValue, index);
+        }
+
+        return newValue;
+    }
+
+    @Override
+    public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if (e.hash == hash && e.key.equals(key)) {
+                V newValue = remappingFunction.apply(e.value, value);
+                if (newValue == null) {
+                    modCount++;
+                    if (prev != null) {
+                        prev.next = e.next;
+                    } else {
+                        tab[index] = e.next;
+                    }
+                    count--;
+                } else {
+                    e.value = newValue;
+                }
+                return newValue;
+            }
+        }
+
+        if (value != null) {
+            addEntry(hash, key, value, index);
+        }
+
+        return value;
+    }
+
+    /**
+     * Save the state of the Hashtable to a stream (i.e., serialize it).
+     *
+     * @serialData The <i>capacity</i> of the Hashtable (the length of the
+     *             bucket array) is emitted (int), followed by the
+     *             <i>size</i> of the Hashtable (the number of key-value
+     *             mappings), followed by the key (Object) and value (Object)
+     *             for each key-value mapping represented by the Hashtable
+     *             The key-value mappings are emitted in no particular order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+            throws IOException {
+        HashtableEntry<Object, Object> entryStack = null;
+
+        synchronized (this) {
+            // Write out the threshold and loadFactor
+            s.defaultWriteObject();
+
+            // Write out the length and count of elements
+            s.writeInt(table.length);
+            s.writeInt(count);
+
+            // Stack copies of the entries in the table
+            for (int index = 0; index < table.length; index++) {
+                HashtableEntry<?,?> entry = table[index];
+
+                while (entry != null) {
+                    entryStack =
+                        new HashtableEntry<>(0, entry.key, entry.value, entryStack);
+                    entry = entry.next;
+                }
+            }
+        }
+
+        // Write out the key/value objects from the stacked entries
+        while (entryStack != null) {
+            s.writeObject(entryStack.key);
+            s.writeObject(entryStack.value);
+            entryStack = entryStack.next;
+        }
+    }
+
+    /**
+     * Reconstitute the Hashtable from a stream (i.e., deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+         throws IOException, ClassNotFoundException
+    {
+        // Read in the threshold and loadFactor
+        s.defaultReadObject();
+
+        // Validate loadFactor (ignore threshold - it will be re-computed)
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new StreamCorruptedException("Illegal Load: " + loadFactor);
+
+        // Read the original length of the array and number of elements
+        int origlength = s.readInt();
+        int elements = s.readInt();
+
+        // Validate # of elements
+        if (elements < 0)
+            throw new StreamCorruptedException("Illegal # of Elements: " + elements);
+
+        // Clamp original length to be more than elements / loadFactor
+        // (this is the invariant enforced with auto-growth)
+        origlength = Math.max(origlength, (int)(elements / loadFactor) + 1);
+
+        // Compute new length with a bit of room 5% + 3 to grow but
+        // no larger than the clamped original length.  Make the length
+        // odd if it's large enough, this helps distribute the entries.
+        // Guard against the length ending up zero, that's not valid.
+        int length = (int)((elements + elements / 20) / loadFactor) + 3;
+        if (length > elements && (length & 1) == 0)
+            length--;
+        length = Math.min(length, origlength);
+        table = new HashtableEntry<?,?>[length];
+        threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
+        count = 0;
+
+        // Read the number of elements and then all the key/value objects
+        for (; elements > 0; elements--) {
+            @SuppressWarnings("unchecked")
+                K key = (K)s.readObject();
+            @SuppressWarnings("unchecked")
+                V value = (V)s.readObject();
+            // sync is eliminated for performance
+            reconstitutionPut(table, key, value);
+        }
+    }
+
+    /**
+     * The put method used by readObject. This is provided because put
+     * is overridable and should not be called in readObject since the
+     * subclass will not yet be initialized.
+     *
+     * <p>This differs from the regular put method in several ways. No
+     * checking for rehashing is necessary since the number of elements
+     * initially in the table is known. The modCount is not incremented and
+     * there's no synchronization because we are creating a new instance.
+     * Also, no return value is needed.
+     */
+    private void reconstitutionPut(HashtableEntry<?,?>[] tab, K key, V value)
+        throws StreamCorruptedException
+    {
+        if (value == null) {
+            throw new java.io.StreamCorruptedException();
+        }
+        // Makes sure the key is not already in the hashtable.
+        // This should not happen in deserialized version.
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                throw new java.io.StreamCorruptedException();
+            }
+        }
+        // Creates the new entry.
+        @SuppressWarnings("unchecked")
+            HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        tab[index] = new HashtableEntry<>(hash, key, value, e);
+        count++;
+    }
+
+    /**
+     * Hashtable bucket collision list entry
+     */
+    // BEGIN Android-changed: Renamed Entry -> HashtableEntry.
+    // Code references to "HashTable.Entry" must mean Map.Entry
+    //
+    // This mirrors the corresponding rename of LinkedHashMap's
+    // Entry->LinkedHashMapEntry.
+    //
+    // This is for source compatibility with earlier versions of Android.
+    // Otherwise, it would hide Map.Entry which would break compilation
+    // of code like:
+    //
+    // Hashtable.Entry<K, V> entry = hashtable.entrySet().iterator.next();
+    //
+    // To compile, that code snippet's "HashtableMap.Entry" must
+    // mean java.util.Map.Entry which is the compile time type of
+    // entrySet()'s elements.
+    //
+    private static class HashtableEntry<K,V> implements Map.Entry<K,V> {
+    // END Android-changed: Renamed Entry -> HashtableEntry.
+        final int hash;
+        final K key;
+        V value;
+        HashtableEntry<K,V> next;
+
+        protected HashtableEntry(int hash, K key, V value, HashtableEntry<K,V> next) {
+            this.hash = hash;
+            this.key =  key;
+            this.value = value;
+            this.next = next;
+        }
+
+        @SuppressWarnings("unchecked")
+        protected Object clone() {
+            return new HashtableEntry<>(hash, key, value,
+                                  (next==null ? null : (HashtableEntry<K,V>) next.clone()));
+        }
+
+        // Map.Entry Ops
+
+        public K getKey() {
+            return key;
+        }
+
+        public V getValue() {
+            return value;
+        }
+
+        public V setValue(V value) {
+            if (value == null)
+                throw new NullPointerException();
+
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+
+            return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
+               (value==null ? e.getValue()==null : value.equals(e.getValue()));
+        }
+
+        public int hashCode() {
+            return hash ^ Objects.hashCode(value);
+        }
+
+        public String toString() {
+            return key.toString()+"="+value.toString();
+        }
+    }
+
+    // Types of Enumerations/Iterations
+    private static final int KEYS = 0;
+    private static final int VALUES = 1;
+    private static final int ENTRIES = 2;
+
+    /**
+     * A hashtable enumerator class.  This class implements both the
+     * Enumeration and Iterator interfaces, but individual instances
+     * can be created with the Iterator methods disabled.  This is necessary
+     * to avoid unintentionally increasing the capabilities granted a user
+     * by passing an Enumeration.
+     */
+    private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
+        HashtableEntry<?,?>[] table = Hashtable.this.table;
+        int index = table.length;
+        HashtableEntry<?,?> entry;
+        HashtableEntry<?,?> lastReturned;
+        int type;
+
+        /**
+         * Indicates whether this Enumerator is serving as an Iterator
+         * or an Enumeration.  (true -> Iterator).
+         */
+        boolean iterator;
+
+        /**
+         * The modCount value that the iterator believes that the backing
+         * Hashtable should have.  If this expectation is violated, the iterator
+         * has detected concurrent modification.
+         */
+        protected int expectedModCount = modCount;
+
+        Enumerator(int type, boolean iterator) {
+            this.type = type;
+            this.iterator = iterator;
+        }
+
+        public boolean hasMoreElements() {
+            HashtableEntry<?,?> e = entry;
+            int i = index;
+            HashtableEntry<?,?>[] t = table;
+            /* Use locals for faster loop iteration */
+            while (e == null && i > 0) {
+                e = t[--i];
+            }
+            entry = e;
+            index = i;
+            return e != null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T nextElement() {
+            HashtableEntry<?,?> et = entry;
+            int i = index;
+            HashtableEntry<?,?>[] t = table;
+            /* Use locals for faster loop iteration */
+            while (et == null && i > 0) {
+                et = t[--i];
+            }
+            entry = et;
+            index = i;
+            if (et != null) {
+                HashtableEntry<?,?> e = lastReturned = entry;
+                entry = e.next;
+                return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
+            }
+            throw new NoSuchElementException("Hashtable Enumerator");
+        }
+
+        // Iterator methods
+        public boolean hasNext() {
+            return hasMoreElements();
+        }
+
+        public T next() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return nextElement();
+        }
+
+        public void remove() {
+            if (!iterator)
+                throw new UnsupportedOperationException();
+            if (lastReturned == null)
+                throw new IllegalStateException("Hashtable Enumerator");
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            synchronized(Hashtable.this) {
+                HashtableEntry<?,?>[] tab = Hashtable.this.table;
+                int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
+
+                @SuppressWarnings("unchecked")
+                HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+                for(HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+                    if (e == lastReturned) {
+                        modCount++;
+                        expectedModCount++;
+                        if (prev == null)
+                            tab[index] = e.next;
+                        else
+                            prev.next = e.next;
+                        count--;
+                        lastReturned = null;
+                        return;
+                    }
+                }
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+}
diff --git a/java/util/IdentityHashMap.java b/java/util/IdentityHashMap.java
new file mode 100644
index 0000000..9dc0c26
--- /dev/null
+++ b/java/util/IdentityHashMap.java
@@ -0,0 +1,1597 @@
+/*
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.lang.reflect.Array;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
+/**
+ * This class implements the <tt>Map</tt> interface with a hash table, using
+ * reference-equality in place of object-equality when comparing keys (and
+ * values).  In other words, in an <tt>IdentityHashMap</tt>, two keys
+ * <tt>k1</tt> and <tt>k2</tt> are considered equal if and only if
+ * <tt>(k1==k2)</tt>.  (In normal <tt>Map</tt> implementations (like
+ * <tt>HashMap</tt>) two keys <tt>k1</tt> and <tt>k2</tt> are considered equal
+ * if and only if <tt>(k1==null ? k2==null : k1.equals(k2))</tt>.)
+ *
+ * <p><b>This class is <i>not</i> a general-purpose <tt>Map</tt>
+ * implementation!  While this class implements the <tt>Map</tt> interface, it
+ * intentionally violates <tt>Map's</tt> general contract, which mandates the
+ * use of the <tt>equals</tt> method when comparing objects.  This class is
+ * designed for use only in the rare cases wherein reference-equality
+ * semantics are required.</b>
+ *
+ * <p>A typical use of this class is <i>topology-preserving object graph
+ * transformations</i>, such as serialization or deep-copying.  To perform such
+ * a transformation, a program must maintain a "node table" that keeps track
+ * of all the object references that have already been processed.  The node
+ * table must not equate distinct objects even if they happen to be equal.
+ * Another typical use of this class is to maintain <i>proxy objects</i>.  For
+ * example, a debugging facility might wish to maintain a proxy object for
+ * each object in the program being debugged.
+ *
+ * <p>This class provides all of the optional map operations, and permits
+ * <tt>null</tt> values and the <tt>null</tt> key.  This class makes no
+ * guarantees as to the order of the map; in particular, it does not guarantee
+ * that the order will remain constant over time.
+ *
+ * <p>This class provides constant-time performance for the basic
+ * operations (<tt>get</tt> and <tt>put</tt>), assuming the system
+ * identity hash function ({@link System#identityHashCode(Object)})
+ * disperses elements properly among the buckets.
+ *
+ * <p>This class has one tuning parameter (which affects performance but not
+ * semantics): <i>expected maximum size</i>.  This parameter is the maximum
+ * number of key-value mappings that the map is expected to hold.  Internally,
+ * this parameter is used to determine the number of buckets initially
+ * comprising the hash table.  The precise relationship between the expected
+ * maximum size and the number of buckets is unspecified.
+ *
+ * <p>If the size of the map (the number of key-value mappings) sufficiently
+ * exceeds the expected maximum size, the number of buckets is increased.
+ * Increasing the number of buckets ("rehashing") may be fairly expensive, so
+ * it pays to create identity hash maps with a sufficiently large expected
+ * maximum size.  On the other hand, iteration over collection views requires
+ * time proportional to the number of buckets in the hash table, so it
+ * pays not to set the expected maximum size too high if you are especially
+ * concerned with iteration performance or memory usage.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access an identity hash map concurrently, and at
+ * least one of the threads modifies the map structurally, it <i>must</i>
+ * be synchronized externally.  (A structural modification is any operation
+ * that adds or deletes one or more mappings; merely changing the value
+ * associated with a key that an instance already contains is not a
+ * structural modification.)  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the map.
+ *
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map:<pre>
+ *   Map m = Collections.synchronizedMap(new IdentityHashMap(...));</pre>
+ *
+ * <p>The iterators returned by the <tt>iterator</tt> method of the
+ * collections returned by all of this class's "collection view
+ * methods" are <i>fail-fast</i>: if the map is structurally modified
+ * at any time after the iterator is created, in any way except
+ * through the iterator's own <tt>remove</tt> method, 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 time in the future.
+ *
+ * <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.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>fail-fast iterators should be used only
+ * to detect bugs.</i>
+ *
+ * <p>Implementation note: This is a simple <i>linear-probe</i> hash table,
+ * as described for example in texts by Sedgewick and Knuth.  The array
+ * alternates holding keys and values.  (This has better locality for large
+ * tables than does using separate arrays.)  For many JRE implementations
+ * and operation mixes, this class will yield better performance than
+ * {@link HashMap} (which uses <i>chaining</i> rather than linear-probing).
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @see     System#identityHashCode(Object)
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Map
+ * @see     HashMap
+ * @see     TreeMap
+ * @author  Doug Lea and Josh Bloch
+ * @since   1.4
+ */
+
+public class IdentityHashMap<K,V>
+    extends AbstractMap<K,V>
+    implements Map<K,V>, java.io.Serializable, Cloneable
+{
+    /**
+     * The initial capacity used by the no-args constructor.
+     * MUST be a power of two.  The value 32 corresponds to the
+     * (specified) expected maximum size of 21, given a load factor
+     * of 2/3.
+     */
+    private static final int DEFAULT_CAPACITY = 32;
+
+    /**
+     * The minimum capacity, used if a lower value is implicitly specified
+     * by either of the constructors with arguments.  The value 4 corresponds
+     * to an expected maximum size of 2, given a load factor of 2/3.
+     * MUST be a power of two.
+     */
+    private static final int MINIMUM_CAPACITY = 4;
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<29.
+     *
+     * In fact, the map can hold no more than MAXIMUM_CAPACITY-1 items
+     * because it has to have at least one slot with the key == null
+     * in order to avoid infinite loops in get(), put(), remove()
+     */
+    private static final int MAXIMUM_CAPACITY = 1 << 29;
+
+    /**
+     * The table, resized as necessary. Length MUST always be a power of two.
+     */
+    transient Object[] table; // non-private to simplify nested class access
+
+    /**
+     * The number of key-value mappings contained in this identity hash map.
+     *
+     * @serial
+     */
+    int size;
+
+    /**
+     * The number of modifications, to support fast-fail iterators
+     */
+    transient int modCount;
+
+    /**
+     * Value representing null keys inside tables.
+     */
+    static final Object NULL_KEY = new Object();
+
+    /**
+     * Use NULL_KEY for key if it is null.
+     */
+    private static Object maskNull(Object key) {
+        return (key == null ? NULL_KEY : key);
+    }
+
+    /**
+     * Returns internal representation of null key back to caller as null.
+     */
+    static final Object unmaskNull(Object key) {
+        return (key == NULL_KEY ? null : key);
+    }
+
+    /**
+     * Constructs a new, empty identity hash map with a default expected
+     * maximum size (21).
+     */
+    public IdentityHashMap() {
+        init(DEFAULT_CAPACITY);
+    }
+
+    /**
+     * Constructs a new, empty map with the specified expected maximum size.
+     * Putting more than the expected number of key-value mappings into
+     * the map may cause the internal data structure to grow, which may be
+     * somewhat time-consuming.
+     *
+     * @param expectedMaxSize the expected maximum size of the map
+     * @throws IllegalArgumentException if <tt>expectedMaxSize</tt> is negative
+     */
+    public IdentityHashMap(int expectedMaxSize) {
+        if (expectedMaxSize < 0)
+            throw new IllegalArgumentException("expectedMaxSize is negative: "
+                                               + expectedMaxSize);
+        init(capacity(expectedMaxSize));
+    }
+
+    /**
+     * Returns the appropriate capacity for the given expected maximum size.
+     * Returns the smallest power of two between MINIMUM_CAPACITY and
+     * MAXIMUM_CAPACITY, inclusive, that is greater than (3 *
+     * expectedMaxSize)/2, if such a number exists.  Otherwise returns
+     * MAXIMUM_CAPACITY.
+     */
+    private static int capacity(int expectedMaxSize) {
+        // assert expectedMaxSize >= 0;
+        return
+            (expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY :
+            (expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY :
+            Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1));
+    }
+
+    /**
+     * Initializes object to be an empty map with the specified initial
+     * capacity, which is assumed to be a power of two between
+     * MINIMUM_CAPACITY and MAXIMUM_CAPACITY inclusive.
+     */
+    private void init(int initCapacity) {
+        // assert (initCapacity & -initCapacity) == initCapacity; // power of 2
+        // assert initCapacity >= MINIMUM_CAPACITY;
+        // assert initCapacity <= MAXIMUM_CAPACITY;
+
+        table = new Object[2 * initCapacity];
+    }
+
+    /**
+     * Constructs a new identity hash map containing the keys-value mappings
+     * in the specified map.
+     *
+     * @param m the map whose mappings are to be placed into this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public IdentityHashMap(Map<? extends K, ? extends V> m) {
+        // Allow for a bit of growth
+        this((int) ((1 + m.size()) * 1.1));
+        putAll(m);
+    }
+
+    /**
+     * Returns the number of key-value mappings in this identity hash map.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this identity hash map contains no key-value
+     * mappings.
+     *
+     * @return <tt>true</tt> if this identity hash map contains no key-value
+     *         mappings
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Returns index for Object x.
+     */
+    private static int hash(Object x, int length) {
+        int h = System.identityHashCode(x);
+        // Multiply by -127, and left-shift to use least bit as part of hash
+        return ((h << 1) - (h << 8)) & (length - 1);
+    }
+
+    /**
+     * Circularly traverses table of size len.
+     */
+    private static int nextKeyIndex(int i, int len) {
+        return (i + 2 < len ? i + 2 : 0);
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key == k)},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} 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 {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @see #put(Object, Object)
+     */
+    @SuppressWarnings("unchecked")
+    public V get(Object key) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+        while (true) {
+            Object item = tab[i];
+            if (item == k)
+                return (V) tab[i + 1];
+            if (item == null)
+                return null;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Tests whether the specified object reference is a key in this identity
+     * hash map.
+     *
+     * @param   key   possible key
+     * @return  <code>true</code> if the specified object reference is a key
+     *          in this map
+     * @see     #containsValue(Object)
+     */
+    public boolean containsKey(Object key) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+        while (true) {
+            Object item = tab[i];
+            if (item == k)
+                return true;
+            if (item == null)
+                return false;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Tests whether the specified object reference is a value in this identity
+     * hash map.
+     *
+     * @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 object reference
+     * @see     #containsKey(Object)
+     */
+    public boolean containsValue(Object value) {
+        Object[] tab = table;
+        for (int i = 1; i < tab.length; i += 2)
+            if (tab[i] == value && tab[i - 1] != null)
+                return true;
+
+        return false;
+    }
+
+    /**
+     * Tests if the specified key-value mapping is in the map.
+     *
+     * @param   key   possible key
+     * @param   value possible value
+     * @return  <code>true</code> if and only if the specified key-value
+     *          mapping is in the map
+     */
+    private boolean containsMapping(Object key, Object value) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+        while (true) {
+            Object item = tab[i];
+            if (item == k)
+                return tab[i + 1] == value;
+            if (item == null)
+                return false;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Associates the specified value with the specified key in this identity
+     * hash map.  If the map previously contained a mapping for the key, the
+     * old value is replaced.
+     *
+     * @param key the key with which the specified value is to be associated
+     * @param value the value to be associated with the specified key
+     * @return the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
+     *         (A <tt>null</tt> return can also indicate that the map
+     *         previously associated <tt>null</tt> with <tt>key</tt>.)
+     * @see     Object#equals(Object)
+     * @see     #get(Object)
+     * @see     #containsKey(Object)
+     */
+    public V put(K key, V value) {
+        final Object k = maskNull(key);
+
+        retryAfterResize: for (;;) {
+            final Object[] tab = table;
+            final int len = tab.length;
+            int i = hash(k, len);
+
+            for (Object item; (item = tab[i]) != null;
+                 i = nextKeyIndex(i, len)) {
+                if (item == k) {
+                    @SuppressWarnings("unchecked")
+                        V oldValue = (V) tab[i + 1];
+                    tab[i + 1] = value;
+                    return oldValue;
+                }
+            }
+
+            final int s = size + 1;
+            // Use optimized form of 3 * s.
+            // Next capacity is len, 2 * current capacity.
+            if (s + (s << 1) > len && resize(len))
+                continue retryAfterResize;
+
+            modCount++;
+            tab[i] = k;
+            tab[i + 1] = value;
+            size = s;
+            return null;
+        }
+    }
+
+    /**
+     * Resizes the table if necessary to hold given capacity.
+     *
+     * @param newCapacity the new capacity, must be a power of two.
+     * @return whether a resize did in fact take place
+     */
+    private boolean resize(int newCapacity) {
+        // assert (newCapacity & -newCapacity) == newCapacity; // power of 2
+        int newLength = newCapacity * 2;
+
+        Object[] oldTable = table;
+        int oldLength = oldTable.length;
+        if (oldLength == 2 * MAXIMUM_CAPACITY) { // can't expand any further
+            if (size == MAXIMUM_CAPACITY - 1)
+                throw new IllegalStateException("Capacity exhausted.");
+            return false;
+        }
+        if (oldLength >= newLength)
+            return false;
+
+        Object[] newTable = new Object[newLength];
+
+        for (int j = 0; j < oldLength; j += 2) {
+            Object key = oldTable[j];
+            if (key != null) {
+                Object value = oldTable[j+1];
+                oldTable[j] = null;
+                oldTable[j+1] = null;
+                int i = hash(key, newLength);
+                while (newTable[i] != null)
+                    i = nextKeyIndex(i, newLength);
+                newTable[i] = key;
+                newTable[i + 1] = value;
+            }
+        }
+        table = newTable;
+        return true;
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for
+     * any of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        int n = m.size();
+        if (n == 0)
+            return;
+        if (n > size)
+            resize(capacity(n)); // conservatively pre-expand
+
+        for (Entry<? extends K, ? extends V> e : m.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * Removes the mapping for this key from this map if present.
+     *
+     * @param key key whose mapping is to be removed from the map
+     * @return the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
+     *         (A <tt>null</tt> return can also indicate that the map
+     *         previously associated <tt>null</tt> with <tt>key</tt>.)
+     */
+    public V remove(Object key) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+
+        while (true) {
+            Object item = tab[i];
+            if (item == k) {
+                modCount++;
+                size--;
+                @SuppressWarnings("unchecked")
+                    V oldValue = (V) tab[i + 1];
+                tab[i + 1] = null;
+                tab[i] = null;
+                closeDeletion(i);
+                return oldValue;
+            }
+            if (item == null)
+                return null;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Removes the specified key-value mapping from the map if it is present.
+     *
+     * @param   key   possible key
+     * @param   value possible value
+     * @return  <code>true</code> if and only if the specified key-value
+     *          mapping was in the map
+     */
+    private boolean removeMapping(Object key, Object value) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+
+        while (true) {
+            Object item = tab[i];
+            if (item == k) {
+                if (tab[i + 1] != value)
+                    return false;
+                modCount++;
+                size--;
+                tab[i] = null;
+                tab[i + 1] = null;
+                closeDeletion(i);
+                return true;
+            }
+            if (item == null)
+                return false;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Rehash all possibly-colliding entries following a
+     * deletion. This preserves the linear-probe
+     * collision properties required by get, put, etc.
+     *
+     * @param d the index of a newly empty deleted slot
+     */
+    private void closeDeletion(int d) {
+        // Adapted from Knuth Section 6.4 Algorithm R
+        Object[] tab = table;
+        int len = tab.length;
+
+        // Look for items to swap into newly vacated slot
+        // starting at index immediately following deletion,
+        // and continuing until a null slot is seen, indicating
+        // the end of a run of possibly-colliding keys.
+        Object item;
+        for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
+             i = nextKeyIndex(i, len) ) {
+            // The following test triggers if the item at slot i (which
+            // hashes to be at slot r) should take the spot vacated by d.
+            // If so, we swap it in, and then continue with d now at the
+            // newly vacated i.  This process will terminate when we hit
+            // the null slot at the end of this run.
+            // The test is messy because we are using a circular table.
+            int r = hash(item, len);
+            if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) {
+                tab[d] = item;
+                tab[d + 1] = tab[i + 1];
+                tab[i] = null;
+                tab[i + 1] = null;
+                d = i;
+            }
+        }
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+        Object[] tab = table;
+        for (int i = 0; i < tab.length; i++)
+            tab[i] = null;
+        size = 0;
+    }
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * <tt>true</tt> if the given object is also a map and the two maps
+     * represent identical object-reference mappings.  More formally, this
+     * map is equal to another map <tt>m</tt> if and only if
+     * <tt>this.entrySet().equals(m.entrySet())</tt>.
+     *
+     * <p><b>Owing to the reference-equality-based semantics of this map it is
+     * possible that the symmetry and transitivity requirements of the
+     * <tt>Object.equals</tt> contract may be violated if this map is compared
+     * to a normal map.  However, the <tt>Object.equals</tt> contract is
+     * guaranteed to hold among <tt>IdentityHashMap</tt> instances.</b>
+     *
+     * @param  o object to be compared for equality with this map
+     * @return <tt>true</tt> if the specified object is equal to this map
+     * @see Object#equals(Object)
+     */
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        } else if (o instanceof IdentityHashMap) {
+            IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) o;
+            if (m.size() != size)
+                return false;
+
+            Object[] tab = m.table;
+            for (int i = 0; i < tab.length; i+=2) {
+                Object k = tab[i];
+                if (k != null && !containsMapping(k, tab[i + 1]))
+                    return false;
+            }
+            return true;
+        } else if (o instanceof Map) {
+            Map<?,?> m = (Map<?,?>)o;
+            return entrySet().equals(m.entrySet());
+        } else {
+            return false;  // o is not a Map
+        }
+    }
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map's
+     * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
+     * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two
+     * <tt>IdentityHashMap</tt> instances <tt>m1</tt> and <tt>m2</tt>, as
+     * required by the general contract of {@link Object#hashCode}.
+     *
+     * <p><b>Owing to the reference-equality-based semantics of the
+     * <tt>Map.Entry</tt> instances in the set returned by this map's
+     * <tt>entrySet</tt> method, it is possible that the contractual
+     * requirement of <tt>Object.hashCode</tt> mentioned in the previous
+     * paragraph will be violated if one of the two objects being compared is
+     * an <tt>IdentityHashMap</tt> instance and the other is a normal map.</b>
+     *
+     * @return the hash code value for this map
+     * @see Object#equals(Object)
+     * @see #equals(Object)
+     */
+    public int hashCode() {
+        int result = 0;
+        Object[] tab = table;
+        for (int i = 0; i < tab.length; i +=2) {
+            Object key = tab[i];
+            if (key != null) {
+                Object k = unmaskNull(key);
+                result += System.identityHashCode(k) ^
+                          System.identityHashCode(tab[i + 1]);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns a shallow copy of this identity hash map: the keys and values
+     * themselves are not cloned.
+     *
+     * @return a shallow copy of this map
+     */
+    public Object clone() {
+        try {
+            IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) super.clone();
+            m.entrySet = null;
+            m.table = table.clone();
+            return m;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    private abstract class IdentityHashMapIterator<T> implements Iterator<T> {
+        int index = (size != 0 ? 0 : table.length); // current slot.
+        int expectedModCount = modCount; // to support fast-fail
+        int lastReturnedIndex = -1;      // to allow remove()
+        boolean indexValid; // To avoid unnecessary next computation
+        Object[] traversalTable = table; // reference to main table or copy
+
+        public boolean hasNext() {
+            Object[] tab = traversalTable;
+            for (int i = index; i < tab.length; i+=2) {
+                Object key = tab[i];
+                if (key != null) {
+                    index = i;
+                    return indexValid = true;
+                }
+            }
+            index = tab.length;
+            return false;
+        }
+
+        protected int nextIndex() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (!indexValid && !hasNext())
+                throw new NoSuchElementException();
+
+            indexValid = false;
+            lastReturnedIndex = index;
+            index += 2;
+            return lastReturnedIndex;
+        }
+
+        public void remove() {
+            if (lastReturnedIndex == -1)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            expectedModCount = ++modCount;
+            int deletedSlot = lastReturnedIndex;
+            lastReturnedIndex = -1;
+            // back up index to revisit new contents after deletion
+            index = deletedSlot;
+            indexValid = false;
+
+            // Removal code proceeds as in closeDeletion except that
+            // it must catch the rare case where an element already
+            // seen is swapped into a vacant slot that will be later
+            // traversed by this iterator. We cannot allow future
+            // next() calls to return it again.  The likelihood of
+            // this occurring under 2/3 load factor is very slim, but
+            // when it does happen, we must make a copy of the rest of
+            // the table to use for the rest of the traversal. Since
+            // this can only happen when we are near the end of the table,
+            // even in these rare cases, this is not very expensive in
+            // time or space.
+
+            Object[] tab = traversalTable;
+            int len = tab.length;
+
+            int d = deletedSlot;
+            Object key = tab[d];
+            tab[d] = null;        // vacate the slot
+            tab[d + 1] = null;
+
+            // If traversing a copy, remove in real table.
+            // We can skip gap-closure on copy.
+            if (tab != IdentityHashMap.this.table) {
+                IdentityHashMap.this.remove(key);
+                expectedModCount = modCount;
+                return;
+            }
+
+            size--;
+
+            Object item;
+            for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
+                 i = nextKeyIndex(i, len)) {
+                int r = hash(item, len);
+                // See closeDeletion for explanation of this conditional
+                if ((i < r && (r <= d || d <= i)) ||
+                    (r <= d && d <= i)) {
+
+                    // If we are about to swap an already-seen element
+                    // into a slot that may later be returned by next(),
+                    // then clone the rest of table for use in future
+                    // next() calls. It is OK that our copy will have
+                    // a gap in the "wrong" place, since it will never
+                    // be used for searching anyway.
+
+                    if (i < deletedSlot && d >= deletedSlot &&
+                        traversalTable == IdentityHashMap.this.table) {
+                        int remaining = len - deletedSlot;
+                        Object[] newTable = new Object[remaining];
+                        System.arraycopy(tab, deletedSlot,
+                                         newTable, 0, remaining);
+                        traversalTable = newTable;
+                        index = 0;
+                    }
+
+                    tab[d] = item;
+                    tab[d + 1] = tab[i + 1];
+                    tab[i] = null;
+                    tab[i + 1] = null;
+                    d = i;
+                }
+            }
+        }
+    }
+
+    private class KeyIterator extends IdentityHashMapIterator<K> {
+        @SuppressWarnings("unchecked")
+        public K next() {
+            return (K) unmaskNull(traversalTable[nextIndex()]);
+        }
+    }
+
+    private class ValueIterator extends IdentityHashMapIterator<V> {
+        @SuppressWarnings("unchecked")
+        public V next() {
+            return (V) traversalTable[nextIndex() + 1];
+        }
+    }
+
+    private class EntryIterator
+        extends IdentityHashMapIterator<Map.Entry<K,V>>
+    {
+        private Entry lastReturnedEntry;
+
+        public Map.Entry<K,V> next() {
+            lastReturnedEntry = new Entry(nextIndex());
+            return lastReturnedEntry;
+        }
+
+        public void remove() {
+            lastReturnedIndex =
+                ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
+            super.remove();
+            lastReturnedEntry.index = lastReturnedIndex;
+            lastReturnedEntry = null;
+        }
+
+        private class Entry implements Map.Entry<K,V> {
+            private int index;
+
+            private Entry(int index) {
+                this.index = index;
+            }
+
+            @SuppressWarnings("unchecked")
+            public K getKey() {
+                checkIndexForEntryUse();
+                return (K) unmaskNull(traversalTable[index]);
+            }
+
+            @SuppressWarnings("unchecked")
+            public V getValue() {
+                checkIndexForEntryUse();
+                return (V) traversalTable[index+1];
+            }
+
+            @SuppressWarnings("unchecked")
+            public V setValue(V value) {
+                checkIndexForEntryUse();
+                V oldValue = (V) traversalTable[index+1];
+                traversalTable[index+1] = value;
+                // if shadowing, force into main table
+                if (traversalTable != IdentityHashMap.this.table)
+                    put((K) traversalTable[index], value);
+                return oldValue;
+            }
+
+            public boolean equals(Object o) {
+                if (index < 0)
+                    return super.equals(o);
+
+                if (!(o instanceof Map.Entry))
+                    return false;
+                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+                return (e.getKey() == unmaskNull(traversalTable[index]) &&
+                       e.getValue() == traversalTable[index+1]);
+            }
+
+            public int hashCode() {
+                if (lastReturnedIndex < 0)
+                    return super.hashCode();
+
+                return (System.identityHashCode(unmaskNull(traversalTable[index])) ^
+                       System.identityHashCode(traversalTable[index+1]));
+            }
+
+            public String toString() {
+                if (index < 0)
+                    return super.toString();
+
+                return (unmaskNull(traversalTable[index]) + "="
+                        + traversalTable[index+1]);
+            }
+
+            private void checkIndexForEntryUse() {
+                if (index < 0)
+                    throw new IllegalStateException("Entry was removed");
+            }
+        }
+    }
+
+    // Views
+
+    /**
+     * This field is initialized to contain an instance of the entry set
+     * view the first time this view is requested.  The view is stateless,
+     * so there's no reason to create more than one.
+     */
+    private transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * Returns an identity-based set view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are reflected in
+     * the set, and vice-versa.  If the map is modified while an iteration
+     * over the set is in progress, the results of the iteration are
+     * undefined.  The set supports element removal, which removes the
+     * corresponding mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
+     * <tt>clear</tt> methods.  It does not support the <tt>add</tt> or
+     * <tt>addAll</tt> methods.
+     *
+     * <p><b>While the object returned by this method implements the
+     * <tt>Set</tt> interface, it does <i>not</i> obey <tt>Set's</tt> general
+     * contract.  Like its backing map, the set returned by this method
+     * defines element equality as reference-equality rather than
+     * object-equality.  This affects the behavior of its <tt>contains</tt>,
+     * <tt>remove</tt>, <tt>containsAll</tt>, <tt>equals</tt>, and
+     * <tt>hashCode</tt> methods.</b>
+     *
+     * <p><b>The <tt>equals</tt> method of the returned set returns <tt>true</tt>
+     * only if the specified object is a set containing exactly the same
+     * object references as the returned set.  The symmetry and transitivity
+     * requirements of the <tt>Object.equals</tt> contract may be violated if
+     * the set returned by this method is compared to a normal set.  However,
+     * the <tt>Object.equals</tt> contract is guaranteed to hold among sets
+     * returned by this method.</b>
+     *
+     * <p>The <tt>hashCode</tt> method of the returned set returns the sum of
+     * the <i>identity hashcodes</i> of the elements in the set, rather than
+     * the sum of their hashcodes.  This is mandated by the change in the
+     * semantics of the <tt>equals</tt> method, in order to enforce the
+     * general contract of the <tt>Object.hashCode</tt> method among sets
+     * returned by this method.
+     *
+     * @return an identity-based set view of the keys contained in this map
+     * @see Object#equals(Object)
+     * @see System#identityHashCode(Object)
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return new KeyIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+        public boolean remove(Object o) {
+            int oldSize = size;
+            IdentityHashMap.this.remove(o);
+            return size != oldSize;
+        }
+        /*
+         * Must revert from AbstractSet's impl to AbstractCollection's, as
+         * the former contains an optimization that results in incorrect
+         * behavior when c is a smaller "normal" (non-identity-based) Set.
+         */
+        public boolean removeAll(Collection<?> c) {
+            Objects.requireNonNull(c);
+            boolean modified = false;
+            for (Iterator<K> i = iterator(); i.hasNext(); ) {
+                if (c.contains(i.next())) {
+                    i.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+        public void clear() {
+            IdentityHashMap.this.clear();
+        }
+        public int hashCode() {
+            int result = 0;
+            for (K key : this)
+                result += System.identityHashCode(key);
+            return result;
+        }
+        public Object[] toArray() {
+            return toArray(new Object[0]);
+        }
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int expectedModCount = modCount;
+            int size = size();
+            if (a.length < size)
+                a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+            Object[] tab = table;
+            int ti = 0;
+            for (int si = 0; si < tab.length; si += 2) {
+                Object key;
+                if ((key = tab[si]) != null) { // key present ?
+                    // more elements than expected -> concurrent modification from other thread
+                    if (ti >= size) {
+                        throw new ConcurrentModificationException();
+                    }
+                    a[ti++] = (T) unmaskNull(key); // unmask key
+                }
+            }
+            // fewer elements than expected or concurrent modification from other thread detected
+            if (ti < size || expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+            // final null marker as per spec
+            if (ti < a.length) {
+                a[ti] = null;
+            }
+            return a;
+        }
+
+        public Spliterator<K> spliterator() {
+            return new KeySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress,
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+     * <tt>retainAll</tt> and <tt>clear</tt> methods.  It does not
+     * support the <tt>add</tt> or <tt>addAll</tt> methods.
+     *
+     * <p><b>While the object returned by this method implements the
+     * <tt>Collection</tt> interface, it does <i>not</i> obey
+     * <tt>Collection's</tt> general contract.  Like its backing map,
+     * the collection returned by this method defines element equality as
+     * reference-equality rather than object-equality.  This affects the
+     * behavior of its <tt>contains</tt>, <tt>remove</tt> and
+     * <tt>containsAll</tt> methods.</b>
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    private class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+        public boolean remove(Object o) {
+            for (Iterator<V> i = iterator(); i.hasNext(); ) {
+                if (i.next() == o) {
+                    i.remove();
+                    return true;
+                }
+            }
+            return false;
+        }
+        public void clear() {
+            IdentityHashMap.this.clear();
+        }
+        public Object[] toArray() {
+            return toArray(new Object[0]);
+        }
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int expectedModCount = modCount;
+            int size = size();
+            if (a.length < size)
+                a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+            Object[] tab = table;
+            int ti = 0;
+            for (int si = 0; si < tab.length; si += 2) {
+                if (tab[si] != null) { // key present ?
+                    // more elements than expected -> concurrent modification from other thread
+                    if (ti >= size) {
+                        throw new ConcurrentModificationException();
+                    }
+                    a[ti++] = (T) tab[si+1]; // copy value
+                }
+            }
+            // fewer elements than expected or concurrent modification from other thread detected
+            if (ti < size || expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+            // final null marker as per spec
+            if (ti < a.length) {
+                a[ti] = null;
+            }
+            return a;
+        }
+
+        public Spliterator<V> spliterator() {
+            return new ValueSpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * Each element in the returned set is a reference-equality-based
+     * <tt>Map.Entry</tt>.  The set is backed by the map, so changes
+     * to the map are reflected in the set, and vice-versa.  If the
+     * map is modified while an iteration over the set is in progress,
+     * the results of the iteration are undefined.  The set supports
+     * element removal, which removes the corresponding mapping from
+     * the map, via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt>
+     * methods.  It does not support the <tt>add</tt> or
+     * <tt>addAll</tt> methods.
+     *
+     * <p>Like the backing map, the <tt>Map.Entry</tt> objects in the set
+     * returned by this method define key and value equality as
+     * reference-equality rather than object-equality.  This affects the
+     * behavior of the <tt>equals</tt> and <tt>hashCode</tt> methods of these
+     * <tt>Map.Entry</tt> objects.  A reference-equality based <tt>Map.Entry
+     * e</tt> is equal to an object <tt>o</tt> if and only if <tt>o</tt> is a
+     * <tt>Map.Entry</tt> and <tt>e.getKey()==o.getKey() &amp;&amp;
+     * e.getValue()==o.getValue()</tt>.  To accommodate these equals
+     * semantics, the <tt>hashCode</tt> method returns
+     * <tt>System.identityHashCode(e.getKey()) ^
+     * System.identityHashCode(e.getValue())</tt>.
+     *
+     * <p><b>Owing to the reference-equality-based semantics of the
+     * <tt>Map.Entry</tt> instances in the set returned by this method,
+     * it is possible that the symmetry and transitivity requirements of
+     * the {@link Object#equals(Object)} contract may be violated if any of
+     * the entries in the set is compared to a normal map entry, or if
+     * the set returned by this method is compared to a set of normal map
+     * entries (such as would be returned by a call to this method on a normal
+     * map).  However, the <tt>Object.equals</tt> contract is guaranteed to
+     * hold among identity-based map entries, and among sets of such entries.
+     * </b>
+     *
+     * @return a set view of the identity-mappings contained in this map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es = entrySet;
+        if (es != null)
+            return es;
+        else
+            return entrySet = new EntrySet();
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+            return containsMapping(entry.getKey(), entry.getValue());
+        }
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+            return removeMapping(entry.getKey(), entry.getValue());
+        }
+        public int size() {
+            return size;
+        }
+        public void clear() {
+            IdentityHashMap.this.clear();
+        }
+        /*
+         * Must revert from AbstractSet's impl to AbstractCollection's, as
+         * the former contains an optimization that results in incorrect
+         * behavior when c is a smaller "normal" (non-identity-based) Set.
+         */
+        public boolean removeAll(Collection<?> c) {
+            Objects.requireNonNull(c);
+            boolean modified = false;
+            for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {
+                if (c.contains(i.next())) {
+                    i.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+        public Object[] toArray() {
+            return toArray(new Object[0]);
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int expectedModCount = modCount;
+            int size = size();
+            if (a.length < size)
+                a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+            Object[] tab = table;
+            int ti = 0;
+            for (int si = 0; si < tab.length; si += 2) {
+                Object key;
+                if ((key = tab[si]) != null) { // key present ?
+                    // more elements than expected -> concurrent modification from other thread
+                    if (ti >= size) {
+                        throw new ConcurrentModificationException();
+                    }
+                    a[ti++] = (T) new AbstractMap.SimpleEntry<>(unmaskNull(key), tab[si + 1]);
+                }
+            }
+            // fewer elements than expected or concurrent modification from other thread detected
+            if (ti < size || expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+            // final null marker as per spec
+            if (ti < a.length) {
+                a[ti] = null;
+            }
+            return a;
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+
+    private static final long serialVersionUID = 8188218128353913216L;
+
+    /**
+     * Saves the state of the <tt>IdentityHashMap</tt> instance to a stream
+     * (i.e., serializes it).
+     *
+     * @serialData The <i>size</i> of the HashMap (the number of key-value
+     *          mappings) (<tt>int</tt>), followed by the key (Object) and
+     *          value (Object) for each key-value mapping represented by the
+     *          IdentityHashMap.  The key-value mappings are emitted in no
+     *          particular order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException  {
+        // Write out and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out size (number of Mappings)
+        s.writeInt(size);
+
+        // Write out keys and values (alternating)
+        Object[] tab = table;
+        for (int i = 0; i < tab.length; i += 2) {
+            Object key = tab[i];
+            if (key != null) {
+                s.writeObject(unmaskNull(key));
+                s.writeObject(tab[i + 1]);
+            }
+        }
+    }
+
+    /**
+     * Reconstitutes the <tt>IdentityHashMap</tt> instance from a stream (i.e.,
+     * deserializes it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException  {
+        // Read in any hidden stuff
+        s.defaultReadObject();
+
+        // Read in size (number of Mappings)
+        int size = s.readInt();
+        if (size < 0)
+            throw new java.io.StreamCorruptedException
+                ("Illegal mappings count: " + size);
+        init(capacity(size));
+
+        // Read the keys and values, and put the mappings in the table
+        for (int i=0; i<size; i++) {
+            @SuppressWarnings("unchecked")
+                K key = (K) s.readObject();
+            @SuppressWarnings("unchecked")
+                V value = (V) s.readObject();
+            putForCreate(key, value);
+        }
+    }
+
+    /**
+     * The put method for readObject.  It does not resize the table,
+     * update modCount, etc.
+     */
+    private void putForCreate(K key, V value)
+        throws java.io.StreamCorruptedException
+    {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+
+        Object item;
+        while ( (item = tab[i]) != null) {
+            if (item == k)
+                throw new java.io.StreamCorruptedException();
+            i = nextKeyIndex(i, len);
+        }
+        tab[i] = k;
+        tab[i + 1] = value;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+
+        Object[] t = table;
+        for (int index = 0; index < t.length; index += 2) {
+            Object k = t[index];
+            if (k != null) {
+                action.accept((K) unmaskNull(k), (V) t[index + 1]);
+            }
+
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        int expectedModCount = modCount;
+
+        Object[] t = table;
+        for (int index = 0; index < t.length; index += 2) {
+            Object k = t[index];
+            if (k != null) {
+                t[index + 1] = function.apply((K) unmaskNull(k), (V) t[index + 1]);
+            }
+
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Similar form as array-based Spliterators, but skips blank elements,
+     * and guestimates size as decreasing by half per split.
+     */
+    static class IdentityHashMapSpliterator<K,V> {
+        final IdentityHashMap<K,V> map;
+        int index;             // current index, modified on advance/split
+        int fence;             // -1 until first use; then one past last index
+        int est;               // size estimate
+        int expectedModCount;  // initialized when fence set
+
+        IdentityHashMapSpliterator(IdentityHashMap<K,V> map, int origin,
+                                   int fence, int est, int expectedModCount) {
+            this.map = map;
+            this.index = origin;
+            this.fence = fence;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getFence() { // initialize fence and size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                est = map.size;
+                expectedModCount = map.modCount;
+                hi = fence = map.table.length;
+            }
+            return hi;
+        }
+
+        public final long estimateSize() {
+            getFence(); // force init
+            return (long) est;
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends IdentityHashMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(IdentityHashMap<K,V> map, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(map, origin, fence, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
+            return (lo >= mid) ? null :
+                new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                        expectedModCount);
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int i, hi, mc; Object key;
+            IdentityHashMap<K,V> m; Object[] a;
+            if ((m = map) != null && (a = m.table) != null &&
+                (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
+                for (; i < hi; i += 2) {
+                    if ((key = a[i]) != null)
+                        action.accept((K)unmaskNull(key));
+                }
+                if (m.modCount == expectedModCount)
+                    return;
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            Object[] a = map.table;
+            int hi = getFence();
+            while (index < hi) {
+                Object key = a[index];
+                index += 2;
+                if (key != null) {
+                    action.accept((K)unmaskNull(key));
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+        extends IdentityHashMapSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
+            return (lo >= mid) ? null :
+                new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int i, hi, mc;
+            IdentityHashMap<K,V> m; Object[] a;
+            if ((m = map) != null && (a = m.table) != null &&
+                (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
+                for (; i < hi; i += 2) {
+                    if (a[i] != null) {
+                        @SuppressWarnings("unchecked") V v = (V)a[i+1];
+                        action.accept(v);
+                    }
+                }
+                if (m.modCount == expectedModCount)
+                    return;
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            Object[] a = map.table;
+            int hi = getFence();
+            while (index < hi) {
+                Object key = a[index];
+                @SuppressWarnings("unchecked") V v = (V)a[index+1];
+                index += 2;
+                if (key != null) {
+                    action.accept(v);
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? SIZED : 0);
+        }
+
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends IdentityHashMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
+            return (lo >= mid) ? null :
+                new EntrySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int i, hi, mc;
+            IdentityHashMap<K,V> m; Object[] a;
+            if ((m = map) != null && (a = m.table) != null &&
+                (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
+                for (; i < hi; i += 2) {
+                    Object key = a[i];
+                    if (key != null) {
+                        @SuppressWarnings("unchecked") K k =
+                            (K)unmaskNull(key);
+                        @SuppressWarnings("unchecked") V v = (V)a[i+1];
+                        action.accept
+                            (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+
+                    }
+                }
+                if (m.modCount == expectedModCount)
+                    return;
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            Object[] a = map.table;
+            int hi = getFence();
+            while (index < hi) {
+                Object key = a[index];
+                @SuppressWarnings("unchecked") V v = (V)a[index+1];
+                index += 2;
+                if (key != null) {
+                    @SuppressWarnings("unchecked") K k =
+                        (K)unmaskNull(key);
+                    action.accept
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT;
+        }
+    }
+
+}
diff --git a/java/util/IllegalFormatCodePointException.java b/java/util/IllegalFormatCodePointException.java
new file mode 100644
index 0000000..02add44
--- /dev/null
+++ b/java/util/IllegalFormatCodePointException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when a character with an invalid Unicode code
+ * point as defined by {@link Character#isValidCodePoint} is passed to the
+ * {@link Formatter}.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatCodePointException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 19080630L;
+
+    private int c;
+
+    /**
+     * Constructs an instance of this class with the specified illegal code
+     * point as defined by {@link Character#isValidCodePoint}.
+     *
+     * @param  c
+     *         The illegal Unicode code point
+     */
+    public IllegalFormatCodePointException(int c) {
+        this.c = c;
+    }
+
+    /**
+     * Returns the illegal code point as defined by {@link
+     * Character#isValidCodePoint}.
+     *
+     * @return  The illegal Unicode code point
+     */
+    public int getCodePoint() {
+        return c;
+    }
+
+    public String getMessage() {
+        return String.format("Code point = %#x", c);
+    }
+}
diff --git a/java/util/IllegalFormatConversionException.java b/java/util/IllegalFormatConversionException.java
new file mode 100644
index 0000000..a9b006f
--- /dev/null
+++ b/java/util/IllegalFormatConversionException.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the argument corresponding to the format
+ * specifier is of an incompatible type.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatConversionException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 17000126L;
+
+    private char c;
+    private Class<?> arg;
+
+    /**
+     * Constructs an instance of this class with the mismatched conversion and
+     * the corresponding argument class.
+     *
+     * @param  c
+     *         Inapplicable conversion
+     *
+     * @param  arg
+     *         Class of the mismatched argument
+     */
+    public IllegalFormatConversionException(char c, Class<?> arg) {
+        if (arg == null)
+            throw new NullPointerException();
+        this.c = c;
+        this.arg = arg;
+    }
+
+    /**
+     * Returns the inapplicable conversion.
+     *
+     * @return  The inapplicable conversion
+     */
+    public char getConversion() {
+        return c;
+    }
+
+    /**
+     * Returns the class of the mismatched argument.
+     *
+     * @return   The class of the mismatched argument
+     */
+    public Class<?> getArgumentClass() {
+        return arg;
+    }
+
+    // javadoc inherited from Throwable.java
+    public String getMessage() {
+        return String.format("%c != %s", c, arg.getName());
+    }
+}
diff --git a/java/util/IllegalFormatException.java b/java/util/IllegalFormatException.java
new file mode 100644
index 0000000..8f1d926
--- /dev/null
+++ b/java/util/IllegalFormatException.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when a format string contains an illegal syntax
+ * or a format specifier that is incompatible with the given arguments.  Only
+ * explicit subtypes of this exception which correspond to specific errors
+ * should be instantiated.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatException extends IllegalArgumentException {
+
+    private static final long serialVersionUID = 18830826L;
+
+    // package-private to prevent explicit instantiation
+    IllegalFormatException() { }
+}
diff --git a/java/util/IllegalFormatFlagsException.java b/java/util/IllegalFormatFlagsException.java
new file mode 100644
index 0000000..6b8223a
--- /dev/null
+++ b/java/util/IllegalFormatFlagsException.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when an illegal combination flags is given.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatFlagsException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 790824L;
+
+    private String flags;
+
+    /**
+     * Constructs an instance of this class with the specified flags.
+     *
+     * @param  f
+     *         The set of format flags which contain an illegal combination
+     */
+    public IllegalFormatFlagsException(String f) {
+        if (f == null)
+            throw new NullPointerException();
+        this.flags = f;
+    }
+
+    /**
+     * Returns the set of flags which contains an illegal combination.
+     *
+     * @return  The flags
+     */
+    public String getFlags() {
+        return flags;
+    }
+
+    public String getMessage() {
+        return "Flags = '" + flags + "'";
+    }
+}
diff --git a/java/util/IllegalFormatPrecisionException.java b/java/util/IllegalFormatPrecisionException.java
new file mode 100644
index 0000000..41cbbb7
--- /dev/null
+++ b/java/util/IllegalFormatPrecisionException.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the precision is a negative value other than
+ * <tt>-1</tt>, the conversion does not support a precision, or the value is
+ * otherwise unsupported.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatPrecisionException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 18711008L;
+
+    private int p;
+
+    /**
+     * Constructs an instance of this class with the specified precision.
+     *
+     * @param  p
+     *         The precision
+     */
+    public IllegalFormatPrecisionException(int p) {
+        this.p = p;
+    }
+
+    /**
+     * Returns the precision
+     *
+     * @return  The precision
+     */
+    public int getPrecision() {
+        return p;
+    }
+
+    public String getMessage() {
+        return Integer.toString(p);
+    }
+}
diff --git a/java/util/IllegalFormatWidthException.java b/java/util/IllegalFormatWidthException.java
new file mode 100644
index 0000000..08ae47d
--- /dev/null
+++ b/java/util/IllegalFormatWidthException.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the format width is a negative value other
+ * than <tt>-1</tt> or is otherwise unsupported.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatWidthException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 16660902L;
+
+    private int w;
+
+    /**
+     * Constructs an instance of this class with the specified width.
+     *
+     * @param  w
+     *         The width
+     */
+    public IllegalFormatWidthException(int w) {
+        this.w = w;
+    }
+
+    /**
+     * Returns the width
+     *
+     * @return  The width
+     */
+    public int getWidth() {
+        return w;
+    }
+
+    public String getMessage() {
+        return Integer.toString(w);
+    }
+}
diff --git a/java/util/IllformedLocaleException.java b/java/util/IllformedLocaleException.java
new file mode 100644
index 0000000..5c0c4da
--- /dev/null
+++ b/java/util/IllformedLocaleException.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ *******************************************************************************
+ * Copyright (C) 2009-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+package java.util;
+
+/**
+ * Thrown by methods in {@link Locale} and {@link Locale.Builder} to
+ * indicate that an argument is not a well-formed BCP 47 tag.
+ *
+ * @see Locale
+ * @since 1.7
+ */
+public class IllformedLocaleException extends RuntimeException {
+
+    private static final long serialVersionUID = -5245986824925681401L;
+
+    private int _errIdx = -1;
+
+    /**
+     * Constructs a new <code>IllformedLocaleException</code> with no
+     * detail message and -1 as the error index.
+     */
+    public IllformedLocaleException() {
+        super();
+    }
+
+    /**
+     * Constructs a new <code>IllformedLocaleException</code> with the
+     * given message and -1 as the error index.
+     *
+     * @param message the message
+     */
+    public IllformedLocaleException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new <code>IllformedLocaleException</code> with the
+     * given message and the error index.  The error index is the approximate
+     * offset from the start of the ill-formed value to the point where the
+     * parse first detected an error.  A negative error index value indicates
+     * either the error index is not applicable or unknown.
+     *
+     * @param message the message
+     * @param errorIndex the index
+     */
+    public IllformedLocaleException(String message, int errorIndex) {
+        super(message + ((errorIndex < 0) ? "" : " [at index " + errorIndex + "]"));
+        _errIdx = errorIndex;
+    }
+
+    /**
+     * Returns the index where the error was found. A negative value indicates
+     * either the error index is not applicable or unknown.
+     *
+     * @return the error index
+     */
+    public int getErrorIndex() {
+        return _errIdx;
+    }
+}
diff --git a/java/util/ImmutableCollections.java b/java/util/ImmutableCollections.java
new file mode 100644
index 0000000..2bc0cc1
--- /dev/null
+++ b/java/util/ImmutableCollections.java
@@ -0,0 +1,964 @@
+/*
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import jdk.internal.vm.annotation.Stable;
+
+/**
+ * Container class for immutable collections. Not part of the public API.
+ * Mainly for namespace management and shared infrastructure.
+ *
+ * Serial warnings are suppressed throughout because all implementation
+ * classes use a serial proxy and thus have no need to declare serialVersionUID.
+ */
+@SuppressWarnings("serial")
+class ImmutableCollections {
+    /**
+     * A "salt" value used for randomizing iteration order. This is initialized once
+     * and stays constant for the lifetime of the JVM. It need not be truly random, but
+     * it needs to vary sufficiently from one run to the next so that iteration order
+     * will vary between JVM runs.
+     */
+    static final int SALT;
+    static {
+        long nt = System.nanoTime();
+        SALT = (int)((nt >>> 32) ^ nt);
+    }
+
+    /** No instances. */
+    private ImmutableCollections() { }
+
+    /**
+     * The reciprocal of load factor. Given a number of elements
+     * to store, multiply by this factor to get the table size.
+     */
+    static final int EXPAND_FACTOR = 2;
+
+    static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
+
+    // ---------- List Implementations ----------
+
+    abstract static class AbstractImmutableList<E> extends AbstractList<E>
+                                                implements RandomAccess, Serializable {
+        @Override public boolean add(E e) { throw uoe(); }
+        @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
+        @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
+        @Override public void    clear() { throw uoe(); }
+        @Override public boolean remove(Object o) { throw uoe(); }
+        @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
+        @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
+        @Override public void    replaceAll(UnaryOperator<E> operator) { throw uoe(); }
+        @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
+        @Override public void    sort(Comparator<? super E> c) { throw uoe(); }
+    }
+
+    static final class List0<E> extends AbstractImmutableList<E> {
+        private static final List0<?> INSTANCE = new List0<>();
+
+        @SuppressWarnings("unchecked")
+        static <T> List0<T> instance() {
+            return (List0<T>) INSTANCE;
+        }
+
+        private List0() { }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 0); // always throws IndexOutOfBoundsException
+            return null;                  // but the compiler doesn't know this
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.emptyIterator();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST);
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> o) {
+            return o.isEmpty(); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return 1;
+        }
+    }
+
+    static final class List1<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E e0;
+
+        List1(E e0) {
+            this.e0 = Objects.requireNonNull(e0);
+        }
+
+        @Override
+        public int size() {
+            return 1;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 1);
+            return e0;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, e0);
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 + e0.hashCode();
+        }
+    }
+
+    static final class List2<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E e0;
+        @Stable
+        private final E e1;
+
+        List2(E e0, E e1) {
+            this.e0 = Objects.requireNonNull(e0);
+            this.e1 = Objects.requireNonNull(e1);
+        }
+
+        @Override
+        public int size() {
+            return 2;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 2);
+            if (index == 0) {
+                return e0;
+            } else { // index == 1
+                return e1;
+            }
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 31 + e0.hashCode();
+            return 31 * hash + e1.hashCode();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, e0, e1);
+        }
+    }
+
+    static final class ListN<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E[] elements;
+
+        @SafeVarargs
+        ListN(E... input) {
+            // copy and check manually to avoid TOCTOU
+            @SuppressWarnings("unchecked")
+            E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
+            for (int i = 0; i < input.length; i++) {
+                tmp[i] = Objects.requireNonNull(input[i]);
+            }
+            this.elements = tmp;
+        }
+
+        @Override
+        public int size() {
+            return elements.length;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, elements.length);
+            return elements[index];
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            for (E e : elements) {
+                if (o.equals(e)) { // implicit nullcheck of o
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 1;
+            for (E e : elements) {
+                hash = 31 * hash + e.hashCode();
+            }
+            return hash;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, elements);
+        }
+    }
+
+    // ---------- Set Implementations ----------
+
+    abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
+        @Override public boolean add(E e) { throw uoe(); }
+        @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
+        @Override public void    clear() { throw uoe(); }
+        @Override public boolean remove(Object o) { throw uoe(); }
+        @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
+        @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
+        @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
+    }
+
+    static final class Set0<E> extends AbstractImmutableSet<E> {
+        private static final Set0<?> INSTANCE = new Set0<>();
+
+        @SuppressWarnings("unchecked")
+        static <T> Set0<T> instance() {
+            return (Set0<T>) INSTANCE;
+        }
+
+        private Set0() { }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> o) {
+            return o.isEmpty(); // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.emptyIterator();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET);
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+    }
+
+    static final class Set1<E> extends AbstractImmutableSet<E> {
+        @Stable
+        private final E e0;
+
+        Set1(E e0) {
+            this.e0 = Objects.requireNonNull(e0);
+        }
+
+        @Override
+        public int size() {
+            return 1;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0); // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.singletonIterator(e0);
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET, e0);
+        }
+
+        @Override
+        public int hashCode() {
+            return e0.hashCode();
+        }
+    }
+
+    static final class Set2<E> extends AbstractImmutableSet<E> {
+        @Stable
+        final E e0;
+        @Stable
+        final E e1;
+
+        Set2(E e0, E e1) {
+            if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
+                throw new IllegalArgumentException("duplicate element: " + e0);
+            }
+
+            if (SALT >= 0) {
+                this.e0 = e0;
+                this.e1 = e1;
+            } else {
+                this.e0 = e1;
+                this.e1 = e0;
+            }
+        }
+
+        @Override
+        public int size() {
+            return 2;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return e0.hashCode() + e1.hashCode();
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new Iterator<E>() {
+                private int idx = 0;
+
+                @Override
+                public boolean hasNext() {
+                    return idx < 2;
+                }
+
+                @Override
+                public E next() {
+                    if (idx == 0) {
+                        idx = 1;
+                        return e0;
+                    } else if (idx == 1) {
+                        idx = 2;
+                        return e1;
+                    } else {
+                        throw new NoSuchElementException();
+                    }
+                }
+            };
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET, e0, e1);
+        }
+    }
+
+    /**
+     * An array-based Set implementation. The element array must be strictly
+     * larger than the size (the number of contained elements) so that at
+     * least one null is always present.
+     * @param <E> the element type
+     */
+    static final class SetN<E> extends AbstractImmutableSet<E> {
+        @Stable
+        final E[] elements;
+        @Stable
+        final int size;
+
+        @SafeVarargs
+        @SuppressWarnings("unchecked")
+        SetN(E... input) {
+            size = input.length; // implicit nullcheck of input
+
+            elements = (E[])new Object[EXPAND_FACTOR * input.length];
+            for (int i = 0; i < input.length; i++) {
+                E e = input[i];
+                int idx = probe(e); // implicit nullcheck of e
+                if (idx >= 0) {
+                    throw new IllegalArgumentException("duplicate element: " + e);
+                } else {
+                    elements[-(idx + 1)] = e;
+                }
+            }
+        }
+
+        @Override
+        public int size() {
+            return size;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return probe(o) >= 0; // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new Iterator<E>() {
+                private int idx = 0;
+
+                @Override
+                public boolean hasNext() {
+                    while (idx < elements.length) {
+                        if (elements[idx] != null)
+                            return true;
+                        idx++;
+                    }
+                    return false;
+                }
+
+                @Override
+                public E next() {
+                    if (! hasNext()) {
+                        throw new NoSuchElementException();
+                    }
+                    return elements[idx++];
+                }
+            };
+        }
+
+        @Override
+        public int hashCode() {
+            int h = 0;
+            for (E e : elements) {
+                if (e != null) {
+                    h += e.hashCode();
+                }
+            }
+            return h;
+        }
+
+        // returns index at which element is present; or if absent,
+        // (-i - 1) where i is location where element should be inserted.
+        // Callers are relying on this method to perform an implicit nullcheck
+        // of pe
+        private int probe(Object pe) {
+            int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length);
+            while (true) {
+                E ee = elements[idx];
+                if (ee == null) {
+                    return -idx - 1;
+                } else if (pe.equals(ee)) {
+                    return idx;
+                } else if (++idx == elements.length) {
+                    idx = 0;
+                }
+            }
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            Object[] array = new Object[size];
+            int dest = 0;
+            for (Object o : elements) {
+                if (o != null) {
+                    array[dest++] = o;
+                }
+            }
+            return new CollSer(CollSer.IMM_SET, array);
+        }
+    }
+
+    // ---------- Map Implementations ----------
+
+    abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
+        @Override public void clear() { throw uoe(); }
+        @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
+        @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V put(K key, V value) { throw uoe(); }
+        @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
+        @Override public V putIfAbsent(K key, V value) { throw uoe(); }
+        @Override public V remove(Object key) { throw uoe(); }
+        @Override public boolean remove(Object key, Object value) { throw uoe(); }
+        @Override public V replace(K key, V value) { throw uoe(); }
+        @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
+        @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
+    }
+
+    static final class Map0<K,V> extends AbstractImmutableMap<K,V> {
+        private static final Map0<?,?> INSTANCE = new Map0<>();
+
+        @SuppressWarnings("unchecked")
+        static <K,V> Map0<K,V> instance() {
+            return (Map0<K,V>) INSTANCE;
+        }
+
+        private Map0() { }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return Set.of();
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_MAP);
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+    }
+
+    static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
+        @Stable
+        private final K k0;
+        @Stable
+        private final V v0;
+
+        Map1(K k0, V v0) {
+            this.k0 = Objects.requireNonNull(k0);
+            this.v0 = Objects.requireNonNull(v0);
+        }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return Set.of(new KeyValueHolder<>(k0, v0));
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            return o.equals(k0); // implicit nullcheck of o
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            return o.equals(v0); // implicit nullcheck of o
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_MAP, k0, v0);
+        }
+
+        @Override
+        public int hashCode() {
+            return k0.hashCode() ^ v0.hashCode();
+        }
+    }
+
+    /**
+     * An array-based Map implementation. There is a single array "table" that
+     * contains keys and values interleaved: table[0] is kA, table[1] is vA,
+     * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
+     * also be strictly larger than the size (the number of key-value pairs contained
+     * in the map) so that at least one null key is always present.
+     * @param <K> the key type
+     * @param <V> the value type
+     */
+    static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
+        @Stable
+        final Object[] table; // pairs of key, value
+        @Stable
+        final int size; // number of pairs
+
+        MapN(Object... input) {
+            if ((input.length & 1) != 0) { // implicit nullcheck of input
+                throw new InternalError("length is odd");
+            }
+            size = input.length >> 1;
+
+            int len = EXPAND_FACTOR * input.length;
+            len = (len + 1) & ~1; // ensure table is even length
+            table = new Object[len];
+
+            for (int i = 0; i < input.length; i += 2) {
+                @SuppressWarnings("unchecked")
+                    K k = Objects.requireNonNull((K)input[i]);
+                @SuppressWarnings("unchecked")
+                    V v = Objects.requireNonNull((V)input[i+1]);
+                int idx = probe(k);
+                if (idx >= 0) {
+                    throw new IllegalArgumentException("duplicate key: " + k);
+                } else {
+                    int dest = -(idx + 1);
+                    table[dest] = k;
+                    table[dest+1] = v;
+                }
+            }
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            return probe(o) >= 0; // implicit nullcheck of o
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            for (int i = 1; i < table.length; i += 2) {
+                Object v = table[i];
+                if (v != null && o.equals(v)) { // implicit nullcheck of o
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 0;
+            for (int i = 0; i < table.length; i += 2) {
+                Object k = table[i];
+                if (k != null) {
+                    hash += k.hashCode() ^ table[i + 1].hashCode();
+                }
+            }
+            return hash;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public V get(Object o) {
+            int i = probe(o);
+            if (i >= 0) {
+                return (V)table[i+1];
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public int size() {
+            return size;
+        }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return new AbstractSet<Map.Entry<K,V>>() {
+                @Override
+                public int size() {
+                    return MapN.this.size;
+                }
+
+                @Override
+                public Iterator<Map.Entry<K,V>> iterator() {
+                    return new Iterator<Map.Entry<K,V>>() {
+                        int idx = 0;
+
+                        @Override
+                        public boolean hasNext() {
+                            while (idx < table.length) {
+                                if (table[idx] != null)
+                                    return true;
+                                idx += 2;
+                            }
+                            return false;
+                        }
+
+                        @Override
+                        public Map.Entry<K,V> next() {
+                            if (hasNext()) {
+                                @SuppressWarnings("unchecked")
+                                Map.Entry<K,V> e =
+                                    new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
+                                idx += 2;
+                                return e;
+                            } else {
+                                throw new NoSuchElementException();
+                            }
+                        }
+                    };
+                }
+            };
+        }
+
+        // returns index at which the probe key is present; or if absent,
+        // (-i - 1) where i is location where element should be inserted.
+        // Callers are relying on this method to perform an implicit nullcheck
+        // of pk.
+        private int probe(Object pk) {
+            int idx = Math.floorMod(pk.hashCode() ^ SALT, table.length >> 1) << 1;
+            while (true) {
+                @SuppressWarnings("unchecked")
+                K ek = (K)table[idx];
+                if (ek == null) {
+                    return -idx - 1;
+                } else if (pk.equals(ek)) {
+                    return idx;
+                } else if ((idx += 2) == table.length) {
+                    idx = 0;
+                }
+            }
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            Object[] array = new Object[2 * size];
+            int len = table.length;
+            int dest = 0;
+            for (int i = 0; i < len; i += 2) {
+                if (table[i] != null) {
+                    array[dest++] = table[i];
+                    array[dest++] = table[i+1];
+                }
+            }
+            return new CollSer(CollSer.IMM_MAP, array);
+        }
+    }
+}
+
+// ---------- Serialization Proxy ----------
+
+/**
+ * A unified serialization proxy class for the immutable collections.
+ *
+ * @serial
+ * @since 9
+ */
+final class CollSer implements Serializable {
+    private static final long serialVersionUID = 6309168927139932177L;
+
+    static final int IMM_LIST = 1;
+    static final int IMM_SET = 2;
+    static final int IMM_MAP = 3;
+
+    /**
+     * Indicates the type of collection that is serialized.
+     * The low order 8 bits have the value 1 for an immutable
+     * {@code List}, 2 for an immutable {@code Set}, and 3 for
+     * an immutable {@code Map}. Any other value causes an
+     * {@link InvalidObjectException} to be thrown. The high
+     * order 24 bits are zero when an instance is serialized,
+     * and they are ignored when an instance is deserialized.
+     * They can thus be used by future implementations without
+     * causing compatibility issues.
+     *
+     * <p>The tag value also determines the interpretation of the
+     * transient {@code Object[] array} field.
+     * For {@code List} and {@code Set}, the array's length is the size
+     * of the collection, and the array contains the elements of the collection.
+     * Null elements are not allowed. For {@code Set}, duplicate elements
+     * are not allowed.
+     *
+     * <p>For {@code Map}, the array's length is twice the number of mappings
+     * present in the map. The array length is necessarily even.
+     * The array contains a succession of key and value pairs:
+     * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed,
+     * and duplicate keys are not allowed.
+     *
+     * @serial
+     * @since 9
+     */
+    private final int tag;
+
+    /**
+     * @serial
+     * @since 9
+     */
+    private transient Object[] array;
+
+    CollSer(int t, Object... a) {
+        tag = t;
+        array = a;
+    }
+
+    /**
+     * Reads objects from the stream and stores them
+     * in the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param ois the ObjectInputStream from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     * @throws InvalidObjectException if the count is negative
+     * @since 9
+     */
+    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+        ois.defaultReadObject();
+        int len = ois.readInt();
+
+        if (len < 0) {
+            throw new InvalidObjectException("negative length " + len);
+        }
+
+        Object[] a = new Object[len];
+        for (int i = 0; i < len; i++) {
+            a[i] = ois.readObject();
+        }
+
+        array = a;
+    }
+
+    /**
+     * Writes objects to the stream from
+     * the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param oos the ObjectOutputStream to which data is written
+     * @throws IOException if an I/O error occurs
+     * @since 9
+     */
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        oos.defaultWriteObject();
+        oos.writeInt(array.length);
+        for (int i = 0; i < array.length; i++) {
+            oos.writeObject(array[i]);
+        }
+    }
+
+    /**
+     * Creates and returns an immutable collection from this proxy class.
+     * The instance returned is created as if by calling one of the
+     * static factory methods for
+     * <a href="List.html#immutable">List</a>,
+     * <a href="Map.html#immutable">Map</a>, or
+     * <a href="Set.html#immutable">Set</a>.
+     * This proxy class is the serial form for all immutable collection instances,
+     * regardless of implementation type. This is necessary to ensure that the
+     * existence of any particular implementation type is kept out of the
+     * serialized form.
+     *
+     * @return a collection created from this proxy object
+     * @throws InvalidObjectException if the tag value is illegal or if an exception
+     *         is thrown during creation of the collection
+     * @throws ObjectStreamException if another serialization error has occurred
+     * @since 9
+     */
+    private Object readResolve() throws ObjectStreamException {
+        try {
+            if (array == null) {
+                throw new InvalidObjectException("null array");
+            }
+
+            // use low order 8 bits to indicate "kind"
+            // ignore high order 24 bits
+            switch (tag & 0xff) {
+                case IMM_LIST:
+                    return List.of(array);
+                case IMM_SET:
+                    return Set.of(array);
+                case IMM_MAP:
+                    if (array.length == 0) {
+                        return ImmutableCollections.Map0.instance();
+                    } else if (array.length == 2) {
+                        return new ImmutableCollections.Map1<>(array[0], array[1]);
+                    } else {
+                        return new ImmutableCollections.MapN<>(array);
+                    }
+                default:
+                    throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
+            }
+        } catch (NullPointerException|IllegalArgumentException ex) {
+            InvalidObjectException ioe = new InvalidObjectException("invalid object");
+            ioe.initCause(ex);
+            throw ioe;
+        }
+    }
+}
diff --git a/java/util/InputMismatchException.java b/java/util/InputMismatchException.java
new file mode 100644
index 0000000..e4d1ce3
--- /dev/null
+++ b/java/util/InputMismatchException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Thrown by a <code>Scanner</code> to indicate that the token
+ * retrieved does not match the pattern for the expected type, or
+ * that the token is out of range for the expected type.
+ *
+ * @author  unascribed
+ * @see     java.util.Scanner
+ * @since   1.5
+ */
+public
+class InputMismatchException extends NoSuchElementException {
+    private static final long serialVersionUID = 8811230760997066428L;
+
+    /**
+     * Constructs an <code>InputMismatchException</code> with <tt>null</tt>
+     * as its error message string.
+     */
+    public InputMismatchException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>InputMismatchException</code>, saving a reference
+     * to the error message string <tt>s</tt> for later retrieval by the
+     * <tt>getMessage</tt> method.
+     *
+     * @param   s   the detail message.
+     */
+    public InputMismatchException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/IntSummaryStatistics.java b/java/util/IntSummaryStatistics.java
new file mode 100644
index 0000000..f93436e
--- /dev/null
+++ b/java/util/IntSummaryStatistics.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.IntConsumer;
+import java.util.stream.Collector;
+
+/**
+ * A state object for collecting statistics such as count, min, max, sum, and
+ * average.
+ *
+ * <p>This class is designed to work with (though does not require)
+ * {@linkplain java.util.stream streams}. For example, you can compute
+ * summary statistics on a stream of ints with:
+ * <pre> {@code
+ * IntSummaryStatistics stats = intStream.collect(IntSummaryStatistics::new,
+ *                                                IntSummaryStatistics::accept,
+ *                                                IntSummaryStatistics::combine);
+ * }</pre>
+ *
+ * <p>{@code IntSummaryStatistics} can be used as a
+ * {@linkplain java.util.stream.Stream#collect(Collector) reduction}
+ * target for a {@linkplain java.util.stream.Stream stream}. For example:
+ *
+ * <pre> {@code
+ * IntSummaryStatistics stats = people.stream()
+ *                                    .collect(Collectors.summarizingInt(Person::getDependents));
+ *}</pre>
+ *
+ * This computes, in a single pass, the count of people, as well as the minimum,
+ * maximum, sum, and average of their number of dependents.
+ *
+ * @implNote This implementation is not thread safe. However, it is safe to use
+ * {@link java.util.stream.Collectors#summarizingInt(java.util.function.ToIntFunction)
+ * Collectors.toIntStatistics()} on a parallel stream, because the parallel
+ * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
+ * provides the necessary partitioning, isolation, and merging of results for
+ * safe and efficient parallel execution.
+ *
+ * <p>This implementation does not check for overflow of the sum.
+ * @since 1.8
+ */
+public class IntSummaryStatistics implements IntConsumer {
+    private long count;
+    private long sum;
+    private int min = Integer.MAX_VALUE;
+    private int max = Integer.MIN_VALUE;
+
+    /**
+     * Construct an empty instance with zero count, zero sum,
+     * {@code Integer.MAX_VALUE} min, {@code Integer.MIN_VALUE} max and zero
+     * average.
+     */
+    public IntSummaryStatistics() { }
+
+    /**
+     * Records a new value into the summary information
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(int value) {
+        ++count;
+        sum += value;
+        min = Math.min(min, value);
+        max = Math.max(max, value);
+    }
+
+    /**
+     * Combines the state of another {@code IntSummaryStatistics} into this one.
+     *
+     * @param other another {@code IntSummaryStatistics}
+     * @throws NullPointerException if {@code other} is null
+     */
+    public void combine(IntSummaryStatistics other) {
+        count += other.count;
+        sum += other.sum;
+        min = Math.min(min, other.min);
+        max = Math.max(max, other.max);
+    }
+
+    /**
+     * Returns the count of values recorded.
+     *
+     * @return the count of values
+     */
+    public final long getCount() {
+        return count;
+    }
+
+    /**
+     * Returns the sum of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return the sum of values, or zero if none
+     */
+    public final long getSum() {
+        return sum;
+    }
+
+    /**
+     * Returns the minimum value recorded, or {@code Integer.MAX_VALUE} if no
+     * values have been recorded.
+     *
+     * @return the minimum value, or {@code Integer.MAX_VALUE} if none
+     */
+    public final int getMin() {
+        return min;
+    }
+
+    /**
+     * Returns the maximum value recorded, or {@code Integer.MIN_VALUE} if no
+     * values have been recorded.
+     *
+     * @return the maximum value, or {@code Integer.MIN_VALUE} if none
+     */
+    public final int getMax() {
+        return max;
+    }
+
+    /**
+     * Returns the arithmetic mean of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return the arithmetic mean of values, or zero if none
+     */
+    public final double getAverage() {
+        return getCount() > 0 ? (double) getSum() / getCount() : 0.0d;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     */
+    public String toString() {
+        return String.format(
+            "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}",
+            this.getClass().getSimpleName(),
+            getCount(),
+            getSum(),
+            getMin(),
+            getAverage(),
+            getMax());
+    }
+}
diff --git a/java/util/InvalidPropertiesFormatException.java b/java/util/InvalidPropertiesFormatException.java
new file mode 100644
index 0000000..bacab3d
--- /dev/null
+++ b/java/util/InvalidPropertiesFormatException.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.NotSerializableException;
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that an operation could not complete because
+ * the input did not conform to the appropriate XML document type
+ * for a collection of properties, as per the {@link Properties}
+ * specification.<p>
+ *
+ * Note, that although InvalidPropertiesFormatException inherits Serializable
+ * interface from Exception, it is not intended to be Serializable. Appropriate
+ * serialization methods are implemented to throw NotSerializableException.
+ *
+ * @see     Properties
+ * @since   1.5
+ * @serial exclude
+ */
+
+public class InvalidPropertiesFormatException extends IOException {
+
+    private static final long serialVersionUID = 7763056076009360219L;
+
+    /**
+     * Constructs an InvalidPropertiesFormatException with the specified
+     * cause.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).
+     */
+    public InvalidPropertiesFormatException(Throwable cause) {
+        super(cause==null ? null : cause.toString());
+        this.initCause(cause);
+    }
+
+   /**
+    * Constructs an InvalidPropertiesFormatException with the specified
+    * detail message.
+    *
+    * @param   message   the detail message. The detail message is saved for
+    *          later retrieval by the {@link Throwable#getMessage()} method.
+    */
+    public InvalidPropertiesFormatException(String message) {
+        super(message);
+    }
+
+    /**
+     * Throws NotSerializableException, since InvalidPropertiesFormatException
+     * objects are not intended to be serializable.
+     */
+    private void writeObject(java.io.ObjectOutputStream out)
+        throws NotSerializableException
+    {
+        throw new NotSerializableException("Not serializable.");
+    }
+
+    /**
+     * Throws NotSerializableException, since InvalidPropertiesFormatException
+     * objects are not intended to be serializable.
+     */
+    private void readObject(java.io.ObjectInputStream in)
+        throws NotSerializableException
+    {
+        throw new NotSerializableException("Not serializable.");
+    }
+
+}
diff --git a/java/util/Iterator.annotated.java b/java/util/Iterator.annotated.java
new file mode 100644
index 0000000..b4f4522
--- /dev/null
+++ b/java/util/Iterator.annotated.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+public interface Iterator<E> {
+
+  public boolean hasNext();
+  public @libcore.util.NullFromTypeParam E next();
+  public default void remove() { throw new RuntimeException("Stub!"); }
+  public default void forEachRemaining(@libcore.util.NonNull Consumer<? super @libcore.util.NullFromTypeParam E> action) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/Iterator.java b/java/util/Iterator.java
new file mode 100644
index 0000000..7d2daf8
--- /dev/null
+++ b/java/util/Iterator.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * An iterator over a collection.  {@code Iterator} takes the place of
+ * {@link Enumeration} in the Java Collections Framework.  Iterators
+ * differ from enumerations in two ways:
+ *
+ * <ul>
+ *      <li> Iterators allow the caller to remove elements from the
+ *           underlying collection during the iteration with well-defined
+ *           semantics.
+ *      <li> Method names have been improved.
+ * </ul>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements returned by this iterator
+ *
+ * @author  Josh Bloch
+ * @see Collection
+ * @see ListIterator
+ * @see Iterable
+ * @since 1.2
+ */
+public interface Iterator<E> {
+    /**
+     * Returns {@code true} if the iteration has more elements.
+     * (In other words, returns {@code true} if {@link #next} would
+     * return an element rather than throwing an exception.)
+     *
+     * @return {@code true} if the iteration has more elements
+     */
+    boolean hasNext();
+
+    /**
+     * Returns the next element in the iteration.
+     *
+     * @return the next element in the iteration
+     * @throws NoSuchElementException if the iteration has no more elements
+     */
+    E next();
+
+    /**
+     * Removes from the underlying collection the last element returned
+     * by this iterator (optional operation).  This method can be called
+     * only once per call to {@link #next}.  The behavior of an iterator
+     * is unspecified if the underlying collection is modified while the
+     * iteration is in progress in any way other than by calling this
+     * method.
+     *
+     * @implSpec
+     * The default implementation throws an instance of
+     * {@link UnsupportedOperationException} and performs no other action.
+     *
+     * @throws UnsupportedOperationException if the {@code remove}
+     *         operation is not supported by this iterator
+     *
+     * @throws IllegalStateException if the {@code next} method has not
+     *         yet been called, or the {@code remove} method has already
+     *         been called after the last call to the {@code next}
+     *         method
+     */
+    default void remove() {
+        throw new UnsupportedOperationException("remove");
+    }
+
+    /**
+     * Performs the given action for each remaining element until all elements
+     * have been processed or the action throws an exception.  Actions are
+     * performed in the order of iteration, if that order is specified.
+     * Exceptions thrown by the action are relayed to the caller.
+     *
+     * @implSpec
+     * <p>The default implementation behaves as if:
+     * <pre>{@code
+     *     while (hasNext())
+     *         action.accept(next());
+     * }</pre>
+     *
+     * @param action The action to be performed for each element
+     * @throws NullPointerException if the specified action is null
+     * @since 1.8
+     */
+    default void forEachRemaining(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        while (hasNext())
+            action.accept(next());
+    }
+}
diff --git a/java/util/JapaneseImperialCalendar.java b/java/util/JapaneseImperialCalendar.java
new file mode 100644
index 0000000..f0512c5
--- /dev/null
+++ b/java/util/JapaneseImperialCalendar.java
@@ -0,0 +1,2380 @@
+/*
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import sun.util.locale.provider.CalendarDataUtility;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.CalendarDate;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.Era;
+import sun.util.calendar.Gregorian;
+import sun.util.calendar.LocalGregorianCalendar;
+
+/**
+ * <code>JapaneseImperialCalendar</code> implements a Japanese
+ * calendar system in which the imperial era-based year numbering is
+ * supported from the Meiji era. The following are the eras supported
+ * by this calendar system.
+ * <pre><tt>
+ * ERA value   Era name    Since (in Gregorian)
+ * ------------------------------------------------------
+ *     0       N/A         N/A
+ *     1       Meiji       1868-01-01 midnight local time
+ *     2       Taisho      1912-07-30 midnight local time
+ *     3       Showa       1926-12-25 midnight local time
+ *     4       Heisei      1989-01-08 midnight local time
+ *     5       Reiwa       2019-05-01 midnight local time
+ * ------------------------------------------------------
+ * </tt></pre>
+ *
+ * <p><code>ERA</code> value 0 specifies the years before Meiji and
+ * the Gregorian year values are used. Unlike {@link
+ * GregorianCalendar}, the Julian to Gregorian transition is not
+ * supported because it doesn't make any sense to the Japanese
+ * calendar systems used before Meiji. To represent the years before
+ * Gregorian year 1, 0 and negative values are used. The Japanese
+ * Imperial rescripts and government decrees don't specify how to deal
+ * with time differences for applying the era transitions. This
+ * calendar implementation assumes local time for all transitions.
+ *
+ * @author Masayoshi Okutsu
+ * @since 1.6
+ */
+class JapaneseImperialCalendar extends Calendar {
+    /*
+     * Implementation Notes
+     *
+     * This implementation uses
+     * sun.util.calendar.LocalGregorianCalendar to perform most of the
+     * calendar calculations. LocalGregorianCalendar is configurable
+     * and reads <JRE_HOME>/lib/calendars.properties at the start-up.
+     */
+
+    /**
+     * The ERA constant designating the era before Meiji.
+     */
+    public static final int BEFORE_MEIJI = 0;
+
+    /**
+     * The ERA constant designating the Meiji era.
+     */
+    public static final int MEIJI = 1;
+
+    /**
+     * The ERA constant designating the Taisho era.
+     */
+    public static final int TAISHO = 2;
+
+    /**
+     * The ERA constant designating the Showa era.
+     */
+    public static final int SHOWA = 3;
+
+    /**
+     * The ERA constant designating the Heisei era.
+     */
+    public static final int HEISEI = 4;
+
+    // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+    /**
+     * The ERA constant designating the Reiwa era.
+     */
+    public static final int REIWA = 5;
+
+    private static final int EPOCH_OFFSET   = 719163; // Fixed date of January 1, 1970 (Gregorian)
+    private static final int EPOCH_YEAR     = 1970;
+
+    // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
+    // into ints, they must be longs in order to prevent arithmetic overflow
+    // when performing (bug 4173516).
+    private static final int  ONE_SECOND = 1000;
+    private static final int  ONE_MINUTE = 60*ONE_SECOND;
+    private static final int  ONE_HOUR   = 60*ONE_MINUTE;
+    private static final long ONE_DAY    = 24*ONE_HOUR;
+    private static final long ONE_WEEK   = 7*ONE_DAY;
+
+    // Reference to the sun.util.calendar.LocalGregorianCalendar instance (singleton).
+    private static final LocalGregorianCalendar jcal
+        = (LocalGregorianCalendar) CalendarSystem.forName("japanese");
+
+    // Gregorian calendar instance. This is required because era
+    // transition dates are given in Gregorian dates.
+    private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
+
+    // The Era instance representing "before Meiji".
+    private static final Era BEFORE_MEIJI_ERA = new Era("BeforeMeiji", "BM", Long.MIN_VALUE, false);
+
+    // Imperial eras. The sun.util.calendar.LocalGregorianCalendar
+    // doesn't have an Era representing before Meiji, which is
+    // inconvenient for a Calendar. So, era[0] is a reference to
+    // BEFORE_MEIJI_ERA.
+    private static final Era[] eras;
+
+    // Fixed date of the first date of each era.
+    private static final long[] sinceFixedDates;
+
+    // The current era
+    private static final int currentEra;
+
+    /*
+     * <pre>
+     *                                 Greatest       Least
+     * Field name             Minimum   Minimum     Maximum     Maximum
+     * ----------             -------   -------     -------     -------
+     * ERA                          0         0           1           1
+     * YEAR                -292275055         1           ?           ?
+     * MONTH                        0         0          11          11
+     * WEEK_OF_YEAR                 1         1          52*         53
+     * WEEK_OF_MONTH                0         0           4*          6
+     * DAY_OF_MONTH                 1         1          28*         31
+     * DAY_OF_YEAR                  1         1         365*        366
+     * DAY_OF_WEEK                  1         1           7           7
+     * DAY_OF_WEEK_IN_MONTH        -1        -1           4*          6
+     * AM_PM                        0         0           1           1
+     * HOUR                         0         0          11          11
+     * HOUR_OF_DAY                  0         0          23          23
+     * MINUTE                       0         0          59          59
+     * SECOND                       0         0          59          59
+     * MILLISECOND                  0         0         999         999
+     * ZONE_OFFSET             -13:00    -13:00       14:00       14:00
+     * DST_OFFSET                0:00      0:00        0:20        2:00
+     * </pre>
+     * *: depends on eras
+     */
+    static final int MIN_VALUES[] = {
+        0,              // ERA
+        -292275055,     // YEAR
+        JANUARY,        // MONTH
+        1,              // WEEK_OF_YEAR
+        0,              // WEEK_OF_MONTH
+        1,              // DAY_OF_MONTH
+        1,              // DAY_OF_YEAR
+        SUNDAY,         // DAY_OF_WEEK
+        1,              // DAY_OF_WEEK_IN_MONTH
+        AM,             // AM_PM
+        0,              // HOUR
+        0,              // HOUR_OF_DAY
+        0,              // MINUTE
+        0,              // SECOND
+        0,              // MILLISECOND
+        -13*ONE_HOUR,   // ZONE_OFFSET (UNIX compatibility)
+        0               // DST_OFFSET
+    };
+    static final int LEAST_MAX_VALUES[] = {
+        0,              // ERA (initialized later)
+        0,              // YEAR (initialized later)
+        JANUARY,        // MONTH (Showa 64 ended in January.)
+        0,              // WEEK_OF_YEAR (Showa 1 has only 6 days which could be 0 weeks.)
+        4,              // WEEK_OF_MONTH
+        28,             // DAY_OF_MONTH
+        0,              // DAY_OF_YEAR (initialized later)
+        SATURDAY,       // DAY_OF_WEEK
+        4,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        20*ONE_MINUTE   // DST_OFFSET (historical least maximum)
+    };
+    static final int MAX_VALUES[] = {
+        0,              // ERA
+        292278994,      // YEAR
+        DECEMBER,       // MONTH
+        53,             // WEEK_OF_YEAR
+        6,              // WEEK_OF_MONTH
+        31,             // DAY_OF_MONTH
+        366,            // DAY_OF_YEAR
+        SATURDAY,       // DAY_OF_WEEK
+        6,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        2*ONE_HOUR      // DST_OFFSET (double summer time)
+    };
+
+    // Proclaim serialization compatibility with JDK 1.6
+    private static final long serialVersionUID = -3364572813905467929L;
+
+    static {
+        Era[] es = jcal.getEras();
+        int length = es.length + 1;
+        eras = new Era[length];
+        sinceFixedDates = new long[length];
+
+        // eras[BEFORE_MEIJI] and sinceFixedDate[BEFORE_MEIJI] are the
+        // same as Gregorian.
+        int index = BEFORE_MEIJI;
+        // Android-removed: Zygote could initialize this class when system has outdated time.
+        // int current = index;
+        sinceFixedDates[index] = gcal.getFixedDate(BEFORE_MEIJI_ERA.getSinceDate());
+        eras[index++] = BEFORE_MEIJI_ERA;
+        for (Era e : es) {
+            // Android-removed: Zygote could initialize this class when system has outdated time.
+            // Android hard-code the current era. Unlike upstream, Android does not add the new era
+            // in the code until the new era arrives. Thus, Android can't have newer era than the
+            // real world. currentEra is the latest Era that Android knows about.
+            // if(e.getSince(TimeZone.NO_TIMEZONE) < System.currentTimeMillis()) {
+            //     current = index;
+            // }
+            CalendarDate d = e.getSinceDate();
+            sinceFixedDates[index] = gcal.getFixedDate(d);
+            eras[index++] = e;
+        }
+        // Android-changed: Zygote could initialize this class when system has outdated time.
+        // currentEra = current;
+        currentEra = REIWA;
+
+        LEAST_MAX_VALUES[ERA] = MAX_VALUES[ERA] = eras.length - 1;
+
+        // Calculate the least maximum year and least day of Year
+        // values. The following code assumes that there's at most one
+        // era transition in a Gregorian year.
+        int year = Integer.MAX_VALUE;
+        int dayOfYear = Integer.MAX_VALUE;
+        CalendarDate date = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        for (int i = 1; i < eras.length; i++) {
+            long fd = sinceFixedDates[i];
+            CalendarDate transitionDate = eras[i].getSinceDate();
+            date.setDate(transitionDate.getYear(), BaseCalendar.JANUARY, 1);
+            long fdd = gcal.getFixedDate(date);
+            if (fd != fdd) {
+                dayOfYear = Math.min((int)(fd - fdd) + 1, dayOfYear);
+            }
+            date.setDate(transitionDate.getYear(), BaseCalendar.DECEMBER, 31);
+            fdd = gcal.getFixedDate(date);
+            if (fd != fdd) {
+                dayOfYear = Math.min((int)(fdd - fd) + 1, dayOfYear);
+            }
+            LocalGregorianCalendar.Date lgd = getCalendarDate(fd - 1);
+            int y = lgd.getYear();
+            // Unless the first year starts from January 1, the actual
+            // max value could be one year short. For example, if it's
+            // Showa 63 January 8, 63 is the actual max value since
+            // Showa 64 January 8 doesn't exist.
+            if (!(lgd.getMonth() == BaseCalendar.JANUARY && lgd.getDayOfMonth() == 1)) {
+                y--;
+            }
+            year = Math.min(y, year);
+        }
+        LEAST_MAX_VALUES[YEAR] = year; // Max year could be smaller than this value.
+        LEAST_MAX_VALUES[DAY_OF_YEAR] = dayOfYear;
+    }
+
+    /**
+     * jdate always has a sun.util.calendar.LocalGregorianCalendar.Date instance to
+     * avoid overhead of creating it for each calculation.
+     */
+    private transient LocalGregorianCalendar.Date jdate;
+
+    /**
+     * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
+     * the GMT offset value and zoneOffsets[1] gets the daylight saving
+     * value.
+     */
+    private transient int[] zoneOffsets;
+
+    /**
+     * Temporary storage for saving original fields[] values in
+     * non-lenient mode.
+     */
+    private transient int[] originalFields;
+
+    /**
+     * Constructs a <code>JapaneseImperialCalendar</code> based on the current time
+     * in the given time zone with the given locale.
+     *
+     * @param zone the given time zone.
+     * @param aLocale the given locale.
+     */
+    JapaneseImperialCalendar(TimeZone zone, Locale aLocale) {
+        super(zone, aLocale);
+        jdate = jcal.newCalendarDate(zone);
+        setTimeInMillis(System.currentTimeMillis());
+    }
+
+    /**
+     * Constructs an "empty" {@code JapaneseImperialCalendar}.
+     *
+     * @param zone    the given time zone
+     * @param aLocale the given locale
+     * @param flag    the flag requesting an empty instance
+     */
+    JapaneseImperialCalendar(TimeZone zone, Locale aLocale, boolean flag) {
+        super(zone, aLocale);
+        jdate = jcal.newCalendarDate(zone);
+    }
+
+    /**
+     * Returns {@code "japanese"} as the calendar type of this {@code
+     * JapaneseImperialCalendar}.
+     *
+     * @return {@code "japanese"}
+     */
+    @Override
+    public String getCalendarType() {
+        return "japanese";
+    }
+
+    /**
+     * Compares this <code>JapaneseImperialCalendar</code> to the specified
+     * <code>Object</code>. The result is <code>true</code> if and
+     * only if the argument is a <code>JapaneseImperialCalendar</code> object
+     * that represents the same time value (millisecond offset from
+     * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
+     * <code>Calendar</code> parameters.
+     *
+     * @param obj the object to compare with.
+     * @return <code>true</code> if this object is equal to <code>obj</code>;
+     * <code>false</code> otherwise.
+     * @see Calendar#compareTo(Calendar)
+     */
+    public boolean equals(Object obj) {
+        return obj instanceof JapaneseImperialCalendar &&
+            super.equals(obj);
+    }
+
+    /**
+     * Generates the hash code for this
+     * <code>JapaneseImperialCalendar</code> object.
+     */
+    public int hashCode() {
+        return super.hashCode() ^ jdate.hashCode();
+    }
+
+    /**
+     * Adds the specified (signed) amount of time to the given calendar field,
+     * based on the calendar's rules.
+     *
+     * <p><em>Add rule 1</em>. The value of <code>field</code>
+     * after the call minus the value of <code>field</code> before the
+     * call is <code>amount</code>, modulo any overflow that has occurred in
+     * <code>field</code>. Overflow occurs when a field value exceeds its
+     * range and, as a result, the next larger field is incremented or
+     * decremented and the field value is adjusted back into its range.</p>
+     *
+     * <p><em>Add rule 2</em>. If a smaller field is expected to be
+     * invariant, but it is impossible for it to be equal to its
+     * prior value because of changes in its minimum or maximum after
+     * <code>field</code> is changed, then its value is adjusted to be as close
+     * as possible to its expected value. A smaller field represents a
+     * smaller unit of time. <code>HOUR</code> is a smaller field than
+     * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
+     * that are not expected to be invariant. The calendar system
+     * determines what fields are expected to be invariant.</p>
+     *
+     * @param field the calendar field.
+     * @param amount the amount of date or time to be added to the field.
+     * @exception IllegalArgumentException if <code>field</code> is
+     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     */
+    public void add(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;   // Do nothing!
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        if (field == YEAR) {
+            LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
+            d.addYear(amount);
+            pinDayOfMonth(d);
+            set(ERA, getEraIndex(d));
+            set(YEAR, d.getYear());
+            set(MONTH, d.getMonth() - 1);
+            set(DAY_OF_MONTH, d.getDayOfMonth());
+        } else if (field == MONTH) {
+            LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
+            d.addMonth(amount);
+            pinDayOfMonth(d);
+            set(ERA, getEraIndex(d));
+            set(YEAR, d.getYear());
+            set(MONTH, d.getMonth() - 1);
+            set(DAY_OF_MONTH, d.getDayOfMonth());
+        } else if (field == ERA) {
+            int era = internalGet(ERA) + amount;
+            if (era < 0) {
+                era = 0;
+            } else if (era > eras.length - 1) {
+                era = eras.length - 1;
+            }
+            set(ERA, era);
+        } else {
+            long delta = amount;
+            long timeOfDay = 0;
+            switch (field) {
+            // Handle the time fields here. Convert the given
+            // amount to milliseconds and call setTimeInMillis.
+            case HOUR:
+            case HOUR_OF_DAY:
+                delta *= 60 * 60 * 1000;        // hours to milliseconds
+                break;
+
+            case MINUTE:
+                delta *= 60 * 1000;             // minutes to milliseconds
+                break;
+
+            case SECOND:
+                delta *= 1000;                  // seconds to milliseconds
+                break;
+
+            case MILLISECOND:
+                break;
+
+            // Handle week, day and AM_PM fields which involves
+            // time zone offset change adjustment. Convert the
+            // given amount to the number of days.
+            case WEEK_OF_YEAR:
+            case WEEK_OF_MONTH:
+            case DAY_OF_WEEK_IN_MONTH:
+                delta *= 7;
+                break;
+
+            case DAY_OF_MONTH: // synonym of DATE
+            case DAY_OF_YEAR:
+            case DAY_OF_WEEK:
+                break;
+
+            case AM_PM:
+                // Convert the amount to the number of days (delta)
+                // and +12 or -12 hours (timeOfDay).
+                delta = amount / 2;
+                timeOfDay = 12 * (amount % 2);
+                break;
+            }
+
+            // The time fields don't require time zone offset change
+            // adjustment.
+            if (field >= HOUR) {
+                setTimeInMillis(time + delta);
+                return;
+            }
+
+            // The rest of the fields (week, day or AM_PM fields)
+            // require time zone offset (both GMT and DST) change
+            // adjustment.
+
+            // Translate the current time to the fixed date and time
+            // of the day.
+            long fd = cachedFixedDate;
+            timeOfDay += internalGet(HOUR_OF_DAY);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(MINUTE);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(SECOND);
+            timeOfDay *= 1000;
+            timeOfDay += internalGet(MILLISECOND);
+            if (timeOfDay >= ONE_DAY) {
+                fd++;
+                timeOfDay -= ONE_DAY;
+            } else if (timeOfDay < 0) {
+                fd--;
+                timeOfDay += ONE_DAY;
+            }
+
+            fd += delta; // fd is the expected fixed date after the calculation
+            int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
+            setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset);
+            zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
+            // If the time zone offset has changed, then adjust the difference.
+            if (zoneOffset != 0) {
+                setTimeInMillis(time + zoneOffset);
+                long fd2 = cachedFixedDate;
+                // If the adjustment has changed the date, then take
+                // the previous one.
+                if (fd2 != fd) {
+                    setTimeInMillis(time - zoneOffset);
+                }
+            }
+        }
+    }
+
+    public void roll(int field, boolean up) {
+        roll(field, up ? +1 : -1);
+    }
+
+    /**
+     * Adds a signed amount to the specified calendar field without changing larger fields.
+     * A negative roll amount means to subtract from field without changing
+     * larger fields. If the specified amount is 0, this method performs nothing.
+     *
+     * <p>This method calls {@link #complete()} before adding the
+     * amount so that all the calendar fields are normalized. If there
+     * is any calendar field having an out-of-range value in non-lenient mode, then an
+     * <code>IllegalArgumentException</code> is thrown.
+     *
+     * @param field the calendar field.
+     * @param amount the signed amount to add to <code>field</code>.
+     * @exception IllegalArgumentException if <code>field</code> is
+     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     * @see #roll(int,boolean)
+     * @see #add(int,int)
+     * @see #set(int,int)
+     */
+    public void roll(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        int min = getMinimum(field);
+        int max = getMaximum(field);
+
+        switch (field) {
+        case ERA:
+        case AM_PM:
+        case MINUTE:
+        case SECOND:
+        case MILLISECOND:
+            // These fields are handled simply, since they have fixed
+            // minima and maxima. Other fields are complicated, since
+            // the range within they must roll varies depending on the
+            // date, a time zone and the era transitions.
+            break;
+
+        case HOUR:
+        case HOUR_OF_DAY:
+            {
+                int unit = max + 1; // 12 or 24 hours
+                int h = internalGet(field);
+                int nh = (h + amount) % unit;
+                if (nh < 0) {
+                    nh += unit;
+                }
+                time += ONE_HOUR * (nh - h);
+
+                // The day might have changed, which could happen if
+                // the daylight saving time transition brings it to
+                // the next day, although it's very unlikely. But we
+                // have to make sure not to change the larger fields.
+                CalendarDate d = jcal.getCalendarDate(time, getZone());
+                if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
+                    d.setEra(jdate.getEra());
+                    d.setDate(internalGet(YEAR),
+                              internalGet(MONTH) + 1,
+                              internalGet(DAY_OF_MONTH));
+                    if (field == HOUR) {
+                        assert (internalGet(AM_PM) == PM);
+                        d.addHours(+12); // restore PM
+                    }
+                    time = jcal.getTime(d);
+                }
+                int hourOfDay = d.getHours();
+                internalSet(field, hourOfDay % unit);
+                if (field == HOUR) {
+                    internalSet(HOUR_OF_DAY, hourOfDay);
+                } else {
+                    internalSet(AM_PM, hourOfDay / 12);
+                    internalSet(HOUR, hourOfDay % 12);
+                }
+
+                // Time zone offset and/or daylight saving might have changed.
+                int zoneOffset = d.getZoneOffset();
+                int saving = d.getDaylightSaving();
+                internalSet(ZONE_OFFSET, zoneOffset - saving);
+                internalSet(DST_OFFSET, saving);
+                return;
+            }
+
+        case YEAR:
+            min = getActualMinimum(field);
+            max = getActualMaximum(field);
+            break;
+
+        case MONTH:
+            // Rolling the month involves both pinning the final value to [0, 11]
+            // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
+            // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
+            // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
+            {
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    int year = jdate.getYear();
+                    if (year == getMaximum(YEAR)) {
+                        CalendarDate jd = jcal.getCalendarDate(time, getZone());
+                        CalendarDate d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
+                        max = d.getMonth() - 1;
+                        int n = getRolledValue(internalGet(field), amount, min, max);
+                        if (n == max) {
+                            // To avoid overflow, use an equivalent year.
+                            jd.addYear(-400);
+                            jd.setMonth(n + 1);
+                            if (jd.getDayOfMonth() > d.getDayOfMonth()) {
+                                jd.setDayOfMonth(d.getDayOfMonth());
+                                jcal.normalize(jd);
+                            }
+                            if (jd.getDayOfMonth() == d.getDayOfMonth()
+                                && jd.getTimeOfDay() > d.getTimeOfDay()) {
+                                jd.setMonth(n + 1);
+                                jd.setDayOfMonth(d.getDayOfMonth() - 1);
+                                jcal.normalize(jd);
+                                // Month may have changed by the normalization.
+                                n = jd.getMonth() - 1;
+                            }
+                            set(DAY_OF_MONTH, jd.getDayOfMonth());
+                        }
+                        set(MONTH, n);
+                    } else if (year == getMinimum(YEAR)) {
+                        CalendarDate jd = jcal.getCalendarDate(time, getZone());
+                        CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                        min = d.getMonth() - 1;
+                        int n = getRolledValue(internalGet(field), amount, min, max);
+                        if (n == min) {
+                            // To avoid underflow, use an equivalent year.
+                            jd.addYear(+400);
+                            jd.setMonth(n + 1);
+                            if (jd.getDayOfMonth() < d.getDayOfMonth()) {
+                                jd.setDayOfMonth(d.getDayOfMonth());
+                                jcal.normalize(jd);
+                            }
+                            if (jd.getDayOfMonth() == d.getDayOfMonth()
+                                && jd.getTimeOfDay() < d.getTimeOfDay()) {
+                                jd.setMonth(n + 1);
+                                jd.setDayOfMonth(d.getDayOfMonth() + 1);
+                                jcal.normalize(jd);
+                                // Month may have changed by the normalization.
+                                n = jd.getMonth() - 1;
+                            }
+                            set(DAY_OF_MONTH, jd.getDayOfMonth());
+                        }
+                        set(MONTH, n);
+                    } else {
+                        int mon = (internalGet(MONTH) + amount) % 12;
+                        if (mon < 0) {
+                            mon += 12;
+                        }
+                        set(MONTH, mon);
+
+                        // Keep the day of month in the range.  We
+                        // don't want to spill over into the next
+                        // month; e.g., we don't want jan31 + 1 mo ->
+                        // feb31 -> mar3.
+                        int monthLen = monthLength(mon);
+                        if (internalGet(DAY_OF_MONTH) > monthLen) {
+                            set(DAY_OF_MONTH, monthLen);
+                        }
+                    }
+                } else {
+                    int eraIndex = getEraIndex(jdate);
+                    CalendarDate transition = null;
+                    if (jdate.getYear() == 1) {
+                        transition = eras[eraIndex].getSinceDate();
+                        min = transition.getMonth() - 1;
+                    } else {
+                        if (eraIndex < eras.length - 1) {
+                            transition = eras[eraIndex + 1].getSinceDate();
+                            if (transition.getYear() == jdate.getNormalizedYear()) {
+                                max = transition.getMonth() - 1;
+                                if (transition.getDayOfMonth() == 1) {
+                                    max--;
+                                }
+                            }
+                        }
+                    }
+
+                    if (min == max) {
+                        // The year has only one month. No need to
+                        // process further. (Showa Gan-nen (year 1)
+                        // and the last year have only one month.)
+                        return;
+                    }
+                    int n = getRolledValue(internalGet(field), amount, min, max);
+                    set(MONTH, n);
+                    if (n == min) {
+                        if (!(transition.getMonth() == BaseCalendar.JANUARY
+                              && transition.getDayOfMonth() == 1)) {
+                            if (jdate.getDayOfMonth() < transition.getDayOfMonth()) {
+                                set(DAY_OF_MONTH, transition.getDayOfMonth());
+                            }
+                        }
+                    } else if (n == max && (transition.getMonth() - 1 == n)) {
+                        int dom = transition.getDayOfMonth();
+                        if (jdate.getDayOfMonth() >= dom) {
+                            set(DAY_OF_MONTH, dom - 1);
+                        }
+                    }
+                }
+                return;
+            }
+
+        case WEEK_OF_YEAR:
+            {
+                int y = jdate.getNormalizedYear();
+                max = getActualMaximum(WEEK_OF_YEAR);
+                set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK)); // update stamp[field]
+                int woy = internalGet(WEEK_OF_YEAR);
+                int value = woy + amount;
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    int year = jdate.getYear();
+                    if (year == getMaximum(YEAR)) {
+                        max = getActualMaximum(WEEK_OF_YEAR);
+                    } else if (year == getMinimum(YEAR)) {
+                        min = getActualMinimum(WEEK_OF_YEAR);
+                        max = getActualMaximum(WEEK_OF_YEAR);
+                        if (value > min && value < max) {
+                            set(WEEK_OF_YEAR, value);
+                            return;
+                        }
+
+                    }
+                    // If the new value is in between min and max
+                    // (exclusive), then we can use the value.
+                    if (value > min && value < max) {
+                        set(WEEK_OF_YEAR, value);
+                        return;
+                    }
+                    long fd = cachedFixedDate;
+                    // Make sure that the min week has the current DAY_OF_WEEK
+                    long day1 = fd - (7 * (woy - min));
+                    if (year != getMinimum(YEAR)) {
+                        if (gcal.getYearFromFixedDate(day1) != y) {
+                            min++;
+                        }
+                    } else {
+                        CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                        if (day1 < jcal.getFixedDate(d)) {
+                            min++;
+                        }
+                    }
+
+                    // Make sure the same thing for the max week
+                    fd += 7 * (max - internalGet(WEEK_OF_YEAR));
+                    if (gcal.getYearFromFixedDate(fd) != y) {
+                        max--;
+                    }
+                    break;
+                }
+
+                // Handle transition here.
+                long fd = cachedFixedDate;
+                long day1 = fd - (7 * (woy - min));
+                // Make sure that the min week has the current DAY_OF_WEEK
+                LocalGregorianCalendar.Date d = getCalendarDate(day1);
+                if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate.getYear())) {
+                    min++;
+                }
+
+                // Make sure the same thing for the max week
+                fd += 7 * (max - woy);
+                jcal.getCalendarDateFromFixedDate(d, fd);
+                if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate.getYear())) {
+                    max--;
+                }
+                // value: the new WEEK_OF_YEAR which must be converted
+                // to month and day of month.
+                value = getRolledValue(woy, amount, min, max) - 1;
+                d = getCalendarDate(day1 + value * 7);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case WEEK_OF_MONTH:
+            {
+                boolean isTransitionYear = isTransitionYear(jdate.getNormalizedYear());
+                // dow: relative day of week from the first day of week
+                int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
+                if (dow < 0) {
+                    dow += 7;
+                }
+
+                long fd = cachedFixedDate;
+                long month1;     // fixed date of the first day (usually 1) of the month
+                int monthLength; // actual month length
+                if (isTransitionYear) {
+                    month1 = getFixedDateMonth1(jdate, fd);
+                    monthLength = actualMonthLength();
+                } else {
+                    month1 = fd - internalGet(DAY_OF_MONTH) + 1;
+                    monthLength = jcal.getMonthLength(jdate);
+                }
+
+                // the first day of week of the month.
+                long monthDay1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(month1 + 6,
+                                                                                     getFirstDayOfWeek());
+                // if the week has enough days to form a week, the
+                // week starts from the previous month.
+                if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
+                    monthDay1st -= 7;
+                }
+                max = getActualMaximum(field);
+
+                // value: the new WEEK_OF_MONTH value
+                int value = getRolledValue(internalGet(field), amount, 1, max) - 1;
+
+                // nfd: fixed date of the rolled date
+                long nfd = monthDay1st + value * 7 + dow;
+
+                // Unlike WEEK_OF_YEAR, we need to change day of week if the
+                // nfd is out of the month.
+                if (nfd < month1) {
+                    nfd = month1;
+                } else if (nfd >= (month1 + monthLength)) {
+                    nfd = month1 + monthLength - 1;
+                }
+                set(DAY_OF_MONTH, (int)(nfd - month1) + 1);
+                return;
+            }
+
+        case DAY_OF_MONTH:
+            {
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    max = jcal.getMonthLength(jdate);
+                    break;
+                }
+
+                // TODO: Need to change the spec to be usable DAY_OF_MONTH rolling...
+
+                // Transition handling. We can't change year and era
+                // values here due to the Calendar roll spec!
+                long month1 = getFixedDateMonth1(jdate, cachedFixedDate);
+
+                // It may not be a regular month. Convert the date and range to
+                // the relative values, perform the roll, and
+                // convert the result back to the rolled date.
+                int value = getRolledValue((int)(cachedFixedDate - month1), amount,
+                                           0, actualMonthLength() - 1);
+                LocalGregorianCalendar.Date d = getCalendarDate(month1 + value);
+                assert getEraIndex(d) == internalGetEra()
+                    && d.getYear() == internalGet(YEAR) && d.getMonth()-1 == internalGet(MONTH);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_YEAR:
+            {
+                max = getActualMaximum(field);
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    break;
+                }
+
+                // Handle transition. We can't change year and era values
+                // here due to the Calendar roll spec.
+                int value = getRolledValue(internalGet(DAY_OF_YEAR), amount, min, max);
+                long jan0 = cachedFixedDate - internalGet(DAY_OF_YEAR);
+                LocalGregorianCalendar.Date d = getCalendarDate(jan0 + value);
+                assert getEraIndex(d) == internalGetEra() && d.getYear() == internalGet(YEAR);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK:
+            {
+                int normalizedYear = jdate.getNormalizedYear();
+                if (!isTransitionYear(normalizedYear) && !isTransitionYear(normalizedYear - 1)) {
+                    // If the week of year is in the same year, we can
+                    // just change DAY_OF_WEEK.
+                    int weekOfYear = internalGet(WEEK_OF_YEAR);
+                    if (weekOfYear > 1 && weekOfYear < 52) {
+                        set(WEEK_OF_YEAR, internalGet(WEEK_OF_YEAR));
+                        max = SATURDAY;
+                        break;
+                    }
+                }
+
+                // We need to handle it in a different way around year
+                // boundaries and in the transition year. Note that
+                // changing era and year values violates the roll
+                // rule: not changing larger calendar fields...
+                amount %= 7;
+                if (amount == 0) {
+                    return;
+                }
+                long fd = cachedFixedDate;
+                long dowFirst = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
+                fd += amount;
+                if (fd < dowFirst) {
+                    fd += 7;
+                } else if (fd >= dowFirst + 7) {
+                    fd -= 7;
+                }
+                LocalGregorianCalendar.Date d = getCalendarDate(fd);
+                set(ERA, getEraIndex(d));
+                set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK_IN_MONTH:
+            {
+                min = 1; // after having normalized, min should be 1.
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    int dom = internalGet(DAY_OF_MONTH);
+                    int monthLength = jcal.getMonthLength(jdate);
+                    int lastDays = monthLength % 7;
+                    max = monthLength / 7;
+                    int x = (dom - 1) % 7;
+                    if (x < lastDays) {
+                        max++;
+                    }
+                    set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
+                    break;
+                }
+
+                // Transition year handling.
+                long fd = cachedFixedDate;
+                long month1 = getFixedDateMonth1(jdate, fd);
+                int monthLength = actualMonthLength();
+                int lastDays = monthLength % 7;
+                max = monthLength / 7;
+                int x = (int)(fd - month1) % 7;
+                if (x < lastDays) {
+                    max++;
+                }
+                int value = getRolledValue(internalGet(field), amount, min, max) - 1;
+                fd = month1 + value * 7 + x;
+                LocalGregorianCalendar.Date d = getCalendarDate(fd);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+        }
+
+        set(field, getRolledValue(internalGet(field), amount, min, max));
+    }
+
+    @Override
+    public String getDisplayName(int field, int style, Locale locale) {
+        if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
+                                    ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+
+        int fieldValue = get(field);
+
+        // "GanNen" is supported only in the LONG style.
+        if (field == YEAR
+            && (getBaseStyle(style) != LONG || fieldValue != 1 || get(ERA) == 0)) {
+            return null;
+        }
+
+        String name = CalendarDataUtility.retrieveFieldValueName(getCalendarType(), field,
+                                                                 fieldValue, style, locale);
+        // If the ERA value is null, then
+        // try to get its name or abbreviation from the Era instance.
+        if (name == null && field == ERA && fieldValue < eras.length) {
+            Era era = eras[fieldValue];
+            name = (style == SHORT) ? era.getAbbreviation() : era.getName();
+        }
+        return name;
+    }
+
+    @Override
+    public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) {
+        if (!checkDisplayNameParams(field, style, ALL_STYLES, NARROW_FORMAT, locale,
+                                    ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+        Map<String, Integer> names;
+        names = CalendarDataUtility.retrieveFieldValueNames(getCalendarType(), field, style, locale);
+        // If strings[] has fewer than eras[], get more names from eras[].
+        if (names != null) {
+            if (field == ERA) {
+                int size = names.size();
+                if (style == ALL_STYLES) {
+                    Set<Integer> values = new HashSet<>();
+                    // count unique era values
+                    for (String key : names.keySet()) {
+                        values.add(names.get(key));
+                    }
+                    size = values.size();
+                }
+                if (size < eras.length) {
+                    int baseStyle = getBaseStyle(style);
+                    for (int i = size; i < eras.length; i++) {
+                        Era era = eras[i];
+                        if (baseStyle == ALL_STYLES || baseStyle == SHORT
+                                || baseStyle == NARROW_FORMAT) {
+                            names.put(era.getAbbreviation(), i);
+                        }
+                        if (baseStyle == ALL_STYLES || baseStyle == LONG) {
+                            names.put(era.getName(), i);
+                        }
+                    }
+                }
+            }
+        }
+        return names;
+    }
+
+    /**
+     * Returns the minimum value for the given calendar field of this
+     * <code>Calendar</code> instance. The minimum value is
+     * defined as the smallest value returned by the {@link
+     * Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the minimum value for the given calendar field.
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getMinimum(int field) {
+        return MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the maximum value for the given calendar field of this
+     * <code>GregorianCalendar</code> instance. The maximum value is
+     * defined as the largest value returned by the {@link
+     * Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getMaximum(int field) {
+        switch (field) {
+        case YEAR:
+            {
+                // The value should depend on the time zone of this calendar.
+                LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
+                                                                     getZone());
+                return Math.max(LEAST_MAX_VALUES[YEAR], d.getYear());
+            }
+        }
+        return MAX_VALUES[field];
+    }
+
+    /**
+     * Returns the highest minimum value for the given calendar field
+     * of this <code>GregorianCalendar</code> instance. The highest
+     * minimum value is defined as the largest value returned by
+     * {@link #getActualMinimum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the highest minimum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getGreatestMinimum(int field) {
+        return field == YEAR ? 1 : MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the lowest maximum value for the given calendar field
+     * of this <code>GregorianCalendar</code> instance. The lowest
+     * maximum value is defined as the smallest value returned by
+     * {@link #getActualMaximum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field
+     * @return the lowest maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getLeastMaximum(int field) {
+        switch (field) {
+        case YEAR:
+            {
+                return Math.min(LEAST_MAX_VALUES[YEAR], getMaximum(YEAR));
+            }
+        }
+        return LEAST_MAX_VALUES[field];
+    }
+
+    /**
+     * Returns the minimum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field
+     * @return the minimum of the given field for the time value of
+     * this <code>JapaneseImperialCalendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getActualMinimum(int field) {
+        if (!isFieldSet(YEAR_MASK|MONTH_MASK|WEEK_OF_YEAR_MASK, field)) {
+            return getMinimum(field);
+        }
+
+        int value = 0;
+        JapaneseImperialCalendar jc = getNormalizedCalendar();
+        // Get a local date which includes time of day and time zone,
+        // which are missing in jc.jdate.
+        LocalGregorianCalendar.Date jd = jcal.getCalendarDate(jc.getTimeInMillis(),
+                                                              getZone());
+        int eraIndex = getEraIndex(jd);
+        switch (field) {
+        case YEAR:
+            {
+                if (eraIndex > BEFORE_MEIJI) {
+                    value = 1;
+                    long since = eras[eraIndex].getSince(getZone());
+                    CalendarDate d = jcal.getCalendarDate(since, getZone());
+                    // Use the same year in jd to take care of leap
+                    // years. i.e., both jd and d must agree on leap
+                    // or common years.
+                    jd.setYear(d.getYear());
+                    jcal.normalize(jd);
+                    assert jd.isLeapYear() == d.isLeapYear();
+                    if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
+                        value++;
+                    }
+                } else {
+                    value = getMinimum(field);
+                    CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                    // Use an equvalent year of d.getYear() if
+                    // possible. Otherwise, ignore the leap year and
+                    // common year difference.
+                    int y = d.getYear();
+                    if (y > 400) {
+                        y -= 400;
+                    }
+                    jd.setYear(y);
+                    jcal.normalize(jd);
+                    if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
+                        value++;
+                    }
+                }
+            }
+            break;
+
+        case MONTH:
+            {
+                // In Before Meiji and Meiji, January is the first month.
+                if (eraIndex > MEIJI && jd.getYear() == 1) {
+                    long since = eras[eraIndex].getSince(getZone());
+                    CalendarDate d = jcal.getCalendarDate(since, getZone());
+                    value = d.getMonth() - 1;
+                    if (jd.getDayOfMonth() < d.getDayOfMonth()) {
+                        value++;
+                    }
+                }
+            }
+            break;
+
+        case WEEK_OF_YEAR:
+            {
+                value = 1;
+                CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                // shift 400 years to avoid underflow
+                d.addYear(+400);
+                jcal.normalize(d);
+                jd.setEra(d.getEra());
+                jd.setYear(d.getYear());
+                jcal.normalize(jd);
+
+                long jan1 = jcal.getFixedDate(d);
+                long fd = jcal.getFixedDate(jd);
+                int woy = getWeekNumber(jan1, fd);
+                long day1 = fd - (7 * (woy - 1));
+                if ((day1 < jan1) ||
+                    (day1 == jan1 &&
+                     jd.getTimeOfDay() < d.getTimeOfDay())) {
+                    value++;
+                }
+            }
+            break;
+        }
+        return value;
+    }
+
+    /**
+     * Returns the maximum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     * For example, if the date of this instance is Heisei 16February 1,
+     * the actual maximum value of the <code>DAY_OF_MONTH</code> field
+     * is 29 because Heisei 16 is a leap year, and if the date of this
+     * instance is Heisei 17 February 1, it's 28.
+     *
+     * @param field the calendar field
+     * @return the maximum of the given field for the time value of
+     * this <code>JapaneseImperialCalendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     */
+    public int getActualMaximum(int field) {
+        final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
+            HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
+            ZONE_OFFSET_MASK|DST_OFFSET_MASK;
+        if ((fieldsForFixedMax & (1<<field)) != 0) {
+            return getMaximum(field);
+        }
+
+        JapaneseImperialCalendar jc = getNormalizedCalendar();
+        LocalGregorianCalendar.Date date = jc.jdate;
+        int normalizedYear = date.getNormalizedYear();
+
+        int value = -1;
+        switch (field) {
+        case MONTH:
+            {
+                value = DECEMBER;
+                if (isTransitionYear(date.getNormalizedYear())) {
+                    // TODO: there may be multiple transitions in a year.
+                    int eraIndex = getEraIndex(date);
+                    if (date.getYear() != 1) {
+                        eraIndex++;
+                        assert eraIndex < eras.length;
+                    }
+                    long transition = sinceFixedDates[eraIndex];
+                    long fd = jc.cachedFixedDate;
+                    if (fd < transition) {
+                        LocalGregorianCalendar.Date ldate
+                            = (LocalGregorianCalendar.Date) date.clone();
+                        jcal.getCalendarDateFromFixedDate(ldate, transition - 1);
+                        value = ldate.getMonth() - 1;
+                    }
+                } else {
+                    LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
+                                                                         getZone());
+                    if (date.getEra() == d.getEra() && date.getYear() == d.getYear()) {
+                        value = d.getMonth() - 1;
+                    }
+                }
+            }
+            break;
+
+        case DAY_OF_MONTH:
+            value = jcal.getMonthLength(date);
+            break;
+
+        case DAY_OF_YEAR:
+            {
+                if (isTransitionYear(date.getNormalizedYear())) {
+                    // Handle transition year.
+                    // TODO: there may be multiple transitions in a year.
+                    int eraIndex = getEraIndex(date);
+                    if (date.getYear() != 1) {
+                        eraIndex++;
+                        assert eraIndex < eras.length;
+                    }
+                    long transition = sinceFixedDates[eraIndex];
+                    long fd = jc.cachedFixedDate;
+                    CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                    d.setDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1);
+                    if (fd < transition) {
+                        value = (int)(transition - gcal.getFixedDate(d));
+                    } else {
+                        d.addYear(+1);
+                        value = (int)(gcal.getFixedDate(d) - transition);
+                    }
+                } else {
+                    LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
+                                                                         getZone());
+                    if (date.getEra() == d.getEra() && date.getYear() == d.getYear()) {
+                        long fd = jcal.getFixedDate(d);
+                        long jan1 = getFixedDateJan1(d, fd);
+                        value = (int)(fd - jan1) + 1;
+                    } else if (date.getYear() == getMinimum(YEAR)) {
+                        CalendarDate d1 = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                        long fd1 = jcal.getFixedDate(d1);
+                        d1.addYear(1);
+                        d1.setMonth(BaseCalendar.JANUARY).setDayOfMonth(1);
+                        jcal.normalize(d1);
+                        long fd2 = jcal.getFixedDate(d1);
+                        value = (int)(fd2 - fd1);
+                    } else {
+                        value = jcal.getYearLength(date);
+                    }
+                }
+            }
+            break;
+
+        case WEEK_OF_YEAR:
+            {
+                if (!isTransitionYear(date.getNormalizedYear())) {
+                    LocalGregorianCalendar.Date jd = jcal.getCalendarDate(Long.MAX_VALUE,
+                                                                          getZone());
+                    if (date.getEra() == jd.getEra() && date.getYear() == jd.getYear()) {
+                        long fd = jcal.getFixedDate(jd);
+                        long jan1 = getFixedDateJan1(jd, fd);
+                        value = getWeekNumber(jan1, fd);
+                    } else if (date.getEra() == null && date.getYear() == getMinimum(YEAR)) {
+                        CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                        // shift 400 years to avoid underflow
+                        d.addYear(+400);
+                        jcal.normalize(d);
+                        jd.setEra(d.getEra());
+                        jd.setDate(d.getYear() + 1, BaseCalendar.JANUARY, 1);
+                        jcal.normalize(jd);
+                        long jan1 = jcal.getFixedDate(d);
+                        long nextJan1 = jcal.getFixedDate(jd);
+                        long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                            getFirstDayOfWeek());
+                        int ndays = (int)(nextJan1st - nextJan1);
+                        if (ndays >= getMinimalDaysInFirstWeek()) {
+                            nextJan1st -= 7;
+                        }
+                        value = getWeekNumber(jan1, nextJan1st);
+                    } else {
+                        // Get the day of week of January 1 of the year
+                        CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                        d.setDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1);
+                        int dayOfWeek = gcal.getDayOfWeek(d);
+                        // Normalize the day of week with the firstDayOfWeek value
+                        dayOfWeek -= getFirstDayOfWeek();
+                        if (dayOfWeek < 0) {
+                            dayOfWeek += 7;
+                        }
+                        value = 52;
+                        int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
+                        if ((magic == 6) ||
+                            (date.isLeapYear() && (magic == 5 || magic == 12))) {
+                            value++;
+                        }
+                    }
+                    break;
+                }
+
+                if (jc == this) {
+                    jc = (JapaneseImperialCalendar) jc.clone();
+                }
+                int max = getActualMaximum(DAY_OF_YEAR);
+                jc.set(DAY_OF_YEAR, max);
+                value = jc.get(WEEK_OF_YEAR);
+                if (value == 1 && max > 7) {
+                    jc.add(WEEK_OF_YEAR, -1);
+                    value = jc.get(WEEK_OF_YEAR);
+                }
+            }
+            break;
+
+        case WEEK_OF_MONTH:
+            {
+                LocalGregorianCalendar.Date jd = jcal.getCalendarDate(Long.MAX_VALUE,
+                                                                      getZone());
+                if (!(date.getEra() == jd.getEra() && date.getYear() == jd.getYear())) {
+                    CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                    d.setDate(date.getNormalizedYear(), date.getMonth(), 1);
+                    int dayOfWeek = gcal.getDayOfWeek(d);
+                    int monthLength = gcal.getMonthLength(d);
+                    dayOfWeek -= getFirstDayOfWeek();
+                    if (dayOfWeek < 0) {
+                        dayOfWeek += 7;
+                    }
+                    int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
+                    value = 3;
+                    if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
+                        value++;
+                    }
+                    monthLength -= nDaysFirstWeek + 7 * 3;
+                    if (monthLength > 0) {
+                        value++;
+                        if (monthLength > 7) {
+                            value++;
+                        }
+                    }
+                } else {
+                    long fd = jcal.getFixedDate(jd);
+                    long month1 = fd - jd.getDayOfMonth() + 1;
+                    value = getWeekNumber(month1, fd);
+                }
+            }
+            break;
+
+        case DAY_OF_WEEK_IN_MONTH:
+            {
+                int ndays, dow1;
+                int dow = date.getDayOfWeek();
+                BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
+                ndays = jcal.getMonthLength(d);
+                d.setDayOfMonth(1);
+                jcal.normalize(d);
+                dow1 = d.getDayOfWeek();
+                int x = dow - dow1;
+                if (x < 0) {
+                    x += 7;
+                }
+                ndays -= x;
+                value = (ndays + 6) / 7;
+            }
+            break;
+
+        case YEAR:
+            {
+                CalendarDate jd = jcal.getCalendarDate(jc.getTimeInMillis(), getZone());
+                CalendarDate d;
+                int eraIndex = getEraIndex(date);
+                if (eraIndex == eras.length - 1) {
+                    d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
+                    value = d.getYear();
+                    // Use an equivalent year for the
+                    // getYearOffsetInMillis call to avoid overflow.
+                    if (value > 400) {
+                        jd.setYear(value - 400);
+                    }
+                } else {
+                    d = jcal.getCalendarDate(eras[eraIndex + 1].getSince(getZone()) - 1,
+                                             getZone());
+                    value = d.getYear();
+                    // Use the same year as d.getYear() to be
+                    // consistent with leap and common years.
+                    jd.setYear(value);
+                }
+                jcal.normalize(jd);
+                if (getYearOffsetInMillis(jd) > getYearOffsetInMillis(d)) {
+                    value--;
+                }
+            }
+            break;
+
+        default:
+            throw new ArrayIndexOutOfBoundsException(field);
+        }
+        return value;
+    }
+
+    /**
+     * Returns the millisecond offset from the beginning of the
+     * year. In the year for Long.MIN_VALUE, it's a pseudo value
+     * beyond the limit. The given CalendarDate object must have been
+     * normalized before calling this method.
+     */
+    private long getYearOffsetInMillis(CalendarDate date) {
+        long t = (jcal.getDayOfYear(date) - 1) * ONE_DAY;
+        return t + date.getTimeOfDay() - date.getZoneOffset();
+    }
+
+    public Object clone() {
+        JapaneseImperialCalendar other = (JapaneseImperialCalendar) super.clone();
+
+        other.jdate = (LocalGregorianCalendar.Date) jdate.clone();
+        other.originalFields = null;
+        other.zoneOffsets = null;
+        return other;
+    }
+
+    public TimeZone getTimeZone() {
+        TimeZone zone = super.getTimeZone();
+        // To share the zone by the CalendarDate
+        jdate.setZone(zone);
+        return zone;
+    }
+
+    public void setTimeZone(TimeZone zone) {
+        super.setTimeZone(zone);
+        // To share the zone by the CalendarDate
+        jdate.setZone(zone);
+    }
+
+    /**
+     * The fixed date corresponding to jdate. If the value is
+     * Long.MIN_VALUE, the fixed date value is unknown.
+     */
+    transient private long cachedFixedDate = Long.MIN_VALUE;
+
+    /**
+     * Converts the time value (millisecond offset from the <a
+     * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
+     * The time is <em>not</em>
+     * recomputed first; to recompute the time, then the fields, call the
+     * <code>complete</code> method.
+     *
+     * @see Calendar#complete
+     */
+    protected void computeFields() {
+        int mask = 0;
+        if (isPartiallyNormalized()) {
+            // Determine which calendar fields need to be computed.
+            mask = getSetStateFields();
+            int fieldMask = ~mask & ALL_FIELDS;
+            if (fieldMask != 0 || cachedFixedDate == Long.MIN_VALUE) {
+                mask |= computeFields(fieldMask,
+                                      mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
+                assert mask == ALL_FIELDS;
+            }
+        } else {
+            // Specify all fields
+            mask = ALL_FIELDS;
+            computeFields(mask, 0);
+        }
+        // After computing all the fields, set the field state to `COMPUTED'.
+        setFieldsComputed(mask);
+    }
+
+    /**
+     * This computeFields implements the conversion from UTC
+     * (millisecond offset from the Epoch) to calendar
+     * field values. fieldMask specifies which fields to change the
+     * setting state to COMPUTED, although all fields are set to
+     * the correct values. This is required to fix 4685354.
+     *
+     * @param fieldMask a bit mask to specify which fields to change
+     * the setting state.
+     * @param tzMask a bit mask to specify which time zone offset
+     * fields to be used for time calculations
+     * @return a new field mask that indicates what field values have
+     * actually been set.
+     */
+    private int computeFields(int fieldMask, int tzMask) {
+        int zoneOffset = 0;
+        TimeZone tz = getZone();
+        if (zoneOffsets == null) {
+            zoneOffsets = new int[2];
+        }
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            // BEGIN Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            // if (tz instanceof ZoneInfo) {
+            //     zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
+            if (tz instanceof libcore.util.ZoneInfo) {
+                zoneOffset = ((libcore.util.ZoneInfo)tz).getOffsetsByUtcTime(time, zoneOffsets);
+            // END Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            } else {
+                zoneOffset = tz.getOffset(time);
+                zoneOffsets[0] = tz.getRawOffset();
+                zoneOffsets[1] = zoneOffset - zoneOffsets[0];
+            }
+        }
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffsets[0] = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                zoneOffsets[1] = internalGet(DST_OFFSET);
+            }
+            zoneOffset = zoneOffsets[0] + zoneOffsets[1];
+        }
+
+        // By computing time and zoneOffset separately, we can take
+        // the wider range of time+zoneOffset than the previous
+        // implementation.
+        long fixedDate = zoneOffset / ONE_DAY;
+        int timeOfDay = zoneOffset % (int)ONE_DAY;
+        fixedDate += time / ONE_DAY;
+        timeOfDay += (int) (time % ONE_DAY);
+        if (timeOfDay >= ONE_DAY) {
+            timeOfDay -= ONE_DAY;
+            ++fixedDate;
+        } else {
+            while (timeOfDay < 0) {
+                timeOfDay += ONE_DAY;
+                --fixedDate;
+            }
+        }
+        fixedDate += EPOCH_OFFSET;
+
+        // See if we can use jdate to avoid date calculation.
+        if (fixedDate != cachedFixedDate || fixedDate < 0) {
+            jcal.getCalendarDateFromFixedDate(jdate, fixedDate);
+            cachedFixedDate = fixedDate;
+        }
+        int era = getEraIndex(jdate);
+        int year = jdate.getYear();
+
+        // Always set the ERA and YEAR values.
+        internalSet(ERA, era);
+        internalSet(YEAR, year);
+        int mask = fieldMask | (ERA_MASK|YEAR_MASK);
+
+        int month =  jdate.getMonth() - 1; // 0-based
+        int dayOfMonth = jdate.getDayOfMonth();
+
+        // Set the basic date fields.
+        if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
+            != 0) {
+            internalSet(MONTH, month);
+            internalSet(DAY_OF_MONTH, dayOfMonth);
+            internalSet(DAY_OF_WEEK, jdate.getDayOfWeek());
+            mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
+        }
+
+        if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                          |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
+            if (timeOfDay != 0) {
+                int hours = timeOfDay / ONE_HOUR;
+                internalSet(HOUR_OF_DAY, hours);
+                internalSet(AM_PM, hours / 12); // Assume AM == 0
+                internalSet(HOUR, hours % 12);
+                int r = timeOfDay % ONE_HOUR;
+                internalSet(MINUTE, r / ONE_MINUTE);
+                r %= ONE_MINUTE;
+                internalSet(SECOND, r / ONE_SECOND);
+                internalSet(MILLISECOND, r % ONE_SECOND);
+            } else {
+                internalSet(HOUR_OF_DAY, 0);
+                internalSet(AM_PM, AM);
+                internalSet(HOUR, 0);
+                internalSet(MINUTE, 0);
+                internalSet(SECOND, 0);
+                internalSet(MILLISECOND, 0);
+            }
+            mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                     |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
+        }
+
+        if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
+            internalSet(ZONE_OFFSET, zoneOffsets[0]);
+            internalSet(DST_OFFSET, zoneOffsets[1]);
+            mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+        }
+
+        if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK
+                          |WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
+            int normalizedYear = jdate.getNormalizedYear();
+            // If it's a year of an era transition, we need to handle
+            // irregular year boundaries.
+            boolean transitionYear = isTransitionYear(jdate.getNormalizedYear());
+            int dayOfYear;
+            long fixedDateJan1;
+            if (transitionYear) {
+                fixedDateJan1 = getFixedDateJan1(jdate, fixedDate);
+                dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+            } else if (normalizedYear == MIN_VALUES[YEAR]) {
+                CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                fixedDateJan1 = jcal.getFixedDate(dx);
+                dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+            } else {
+                dayOfYear = (int) jcal.getDayOfYear(jdate);
+                fixedDateJan1 = fixedDate - dayOfYear + 1;
+            }
+            long fixedDateMonth1 = transitionYear ?
+                getFixedDateMonth1(jdate, fixedDate) : fixedDate - dayOfMonth + 1;
+
+            internalSet(DAY_OF_YEAR, dayOfYear);
+            internalSet(DAY_OF_WEEK_IN_MONTH, (dayOfMonth - 1) / 7 + 1);
+
+            int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
+
+            // The spec is to calculate WEEK_OF_YEAR in the
+            // ISO8601-style. This creates problems, though.
+            if (weekOfYear == 0) {
+                // If the date belongs to the last week of the
+                // previous year, use the week number of "12/31" of
+                // the "previous" year. Again, if the previous year is
+                // a transition year, we need to take care of it.
+                // Usually the previous day of the first day of a year
+                // is December 31, which is not always true in the
+                // Japanese imperial calendar system.
+                long fixedDec31 = fixedDateJan1 - 1;
+                long prevJan1;
+                LocalGregorianCalendar.Date d = getCalendarDate(fixedDec31);
+                if (!(transitionYear || isTransitionYear(d.getNormalizedYear()))) {
+                    prevJan1 = fixedDateJan1 - 365;
+                    if (d.isLeapYear()) {
+                        --prevJan1;
+                    }
+                } else if (transitionYear) {
+                    if (jdate.getYear() == 1) {
+                        // As of Reiwa (since Meiji) there's no case
+                        // that there are multiple transitions in a
+                        // year.  Historically there was such
+                        // case. There might be such case again in the
+                        // future.
+                        if (era > REIWA) {
+                            CalendarDate pd = eras[era - 1].getSinceDate();
+                            if (normalizedYear == pd.getYear()) {
+                                d.setMonth(pd.getMonth()).setDayOfMonth(pd.getDayOfMonth());
+                            }
+                        } else {
+                            d.setMonth(LocalGregorianCalendar.JANUARY).setDayOfMonth(1);
+                        }
+                        jcal.normalize(d);
+                        prevJan1 = jcal.getFixedDate(d);
+                    } else {
+                        prevJan1 = fixedDateJan1 - 365;
+                        if (d.isLeapYear()) {
+                            --prevJan1;
+                        }
+                    }
+                } else {
+                    CalendarDate cd = eras[getEraIndex(jdate)].getSinceDate();
+                    d.setMonth(cd.getMonth()).setDayOfMonth(cd.getDayOfMonth());
+                    jcal.normalize(d);
+                    prevJan1 = jcal.getFixedDate(d);
+                }
+                weekOfYear = getWeekNumber(prevJan1, fixedDec31);
+            } else {
+                if (!transitionYear) {
+                    // Regular years
+                    if (weekOfYear >= 52) {
+                        long nextJan1 = fixedDateJan1 + 365;
+                        if (jdate.isLeapYear()) {
+                            nextJan1++;
+                        }
+                        long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                            getFirstDayOfWeek());
+                        int ndays = (int)(nextJan1st - nextJan1);
+                        if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                            // The first days forms a week in which the date is included.
+                            weekOfYear = 1;
+                        }
+                    }
+                } else {
+                    LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
+                    long nextJan1;
+                    if (jdate.getYear() == 1) {
+                        d.addYear(+1);
+                        d.setMonth(LocalGregorianCalendar.JANUARY).setDayOfMonth(1);
+                        nextJan1 = jcal.getFixedDate(d);
+                    } else {
+                        int nextEraIndex = getEraIndex(d) + 1;
+                        CalendarDate cd = eras[nextEraIndex].getSinceDate();
+                        d.setEra(eras[nextEraIndex]);
+                        d.setDate(1, cd.getMonth(), cd.getDayOfMonth());
+                        jcal.normalize(d);
+                        nextJan1 = jcal.getFixedDate(d);
+                    }
+                    long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                        getFirstDayOfWeek());
+                    int ndays = (int)(nextJan1st - nextJan1);
+                    if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                        // The first days forms a week in which the date is included.
+                        weekOfYear = 1;
+                    }
+                }
+            }
+            internalSet(WEEK_OF_YEAR, weekOfYear);
+            internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
+            mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
+        }
+        return mask;
+    }
+
+    /**
+     * Returns the number of weeks in a period between fixedDay1 and
+     * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
+     * is applied to calculate the number of weeks.
+     *
+     * @param fixedDay1 the fixed date of the first day of the period
+     * @param fixedDate the fixed date of the last day of the period
+     * @return the number of weeks of the given period
+     */
+    private int getWeekNumber(long fixedDay1, long fixedDate) {
+        // We can always use `jcal' since Julian and Gregorian are the
+        // same thing for this calculation.
+        long fixedDay1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
+                                                                             getFirstDayOfWeek());
+        int ndays = (int)(fixedDay1st - fixedDay1);
+        assert ndays <= 7;
+        if (ndays >= getMinimalDaysInFirstWeek()) {
+            fixedDay1st -= 7;
+        }
+        int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
+        if (normalizedDayOfPeriod >= 0) {
+            return normalizedDayOfPeriod / 7 + 1;
+        }
+        return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
+    }
+
+    /**
+     * Converts calendar field values to the time value (millisecond
+     * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
+     *
+     * @exception IllegalArgumentException if any calendar fields are invalid.
+     */
+    protected void computeTime() {
+        // In non-lenient mode, perform brief checking of calendar
+        // fields which have been set externally. Through this
+        // checking, the field values are stored in originalFields[]
+        // to see if any of them are normalized later.
+        if (!isLenient()) {
+            if (originalFields == null) {
+                originalFields = new int[FIELD_COUNT];
+            }
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                int value = internalGet(field);
+                if (isExternallySet(field)) {
+                    // Quick validation for any out of range values
+                    if (value < getMinimum(field) || value > getMaximum(field)) {
+                        throw new IllegalArgumentException(getFieldName(field));
+                    }
+                }
+                originalFields[field] = value;
+            }
+        }
+
+        // Let the super class determine which calendar fields to be
+        // used to calculate the time.
+        int fieldMask = selectFields();
+
+        int year;
+        int era;
+
+        if (isSet(ERA)) {
+            era = internalGet(ERA);
+            year = isSet(YEAR) ? internalGet(YEAR) : 1;
+        } else {
+            if (isSet(YEAR)) {
+                era = currentEra;
+                year = internalGet(YEAR);
+            } else {
+                // Equivalent to 1970 (Gregorian)
+                era = SHOWA;
+                year = 45;
+            }
+        }
+
+        // Calculate the time of day. We rely on the convention that
+        // an UNSET field has 0.
+        long timeOfDay = 0;
+        if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
+            timeOfDay += (long) internalGet(HOUR_OF_DAY);
+        } else {
+            timeOfDay += internalGet(HOUR);
+            // The default value of AM_PM is 0 which designates AM.
+            if (isFieldSet(fieldMask, AM_PM)) {
+                timeOfDay += 12 * internalGet(AM_PM);
+            }
+        }
+        timeOfDay *= 60;
+        timeOfDay += internalGet(MINUTE);
+        timeOfDay *= 60;
+        timeOfDay += internalGet(SECOND);
+        timeOfDay *= 1000;
+        timeOfDay += internalGet(MILLISECOND);
+
+        // Convert the time of day to the number of days and the
+        // millisecond offset from midnight.
+        long fixedDate = timeOfDay / ONE_DAY;
+        timeOfDay %= ONE_DAY;
+        while (timeOfDay < 0) {
+            timeOfDay += ONE_DAY;
+            --fixedDate;
+        }
+
+        // Calculate the fixed date since January 1, 1 (Gregorian).
+        fixedDate += getFixedDate(era, year, fieldMask);
+
+        // millis represents local wall-clock time in milliseconds.
+        long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
+
+        // Compute the time zone offset and DST offset.  There are two potential
+        // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
+        // for discussion purposes here.
+        // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
+        //    can be in standard or in DST depending.  However, 2:00 am is an invalid
+        //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
+        //    We assume standard time.
+        // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
+        //    can be in standard or DST.  Both are valid representations (the rep
+        //    jumps from 1:59:59 DST to 1:00:00 Std).
+        //    Again, we assume standard time.
+        // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
+        // or DST_OFFSET fields; then we use those fields.
+        TimeZone zone = getZone();
+        if (zoneOffsets == null) {
+            zoneOffsets = new int[2];
+        }
+        int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            // if (zone instanceof ZoneInfo) {
+            //     ((ZoneInfo)zone).getOffsetsByWall(millis, zoneOffsets);
+            // } else {
+                zone.getOffsets(millis - zone.getRawOffset(), zoneOffsets);
+            // }
+        }
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffsets[0] = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                zoneOffsets[1] = internalGet(DST_OFFSET);
+            }
+        }
+
+        // Adjust the time zone offset values to get the UTC time.
+        millis -= zoneOffsets[0] + zoneOffsets[1];
+
+        // Set this calendar's time in milliseconds
+        time = millis;
+
+        int mask = computeFields(fieldMask | getSetStateFields(), tzMask);
+
+        if (!isLenient()) {
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                if (!isExternallySet(field)) {
+                    continue;
+                }
+                if (originalFields[field] != internalGet(field)) {
+                    int wrongValue = internalGet(field);
+                    // Restore the original field values
+                    System.arraycopy(originalFields, 0, fields, 0, fields.length);
+                    throw new IllegalArgumentException(getFieldName(field) + "=" + wrongValue
+                                                       + ", expected " + originalFields[field]);
+                }
+            }
+        }
+        setFieldsNormalized(mask);
+    }
+
+    /**
+     * Computes the fixed date under either the Gregorian or the
+     * Julian calendar, using the given year and the specified calendar fields.
+     *
+     * @param era era index
+     * @param year the normalized year number, with 0 indicating the
+     * year 1 BCE, -1 indicating 2 BCE, etc.
+     * @param fieldMask the calendar fields to be used for the date calculation
+     * @return the fixed date
+     * @see Calendar#selectFields
+     */
+    private long getFixedDate(int era, int year, int fieldMask) {
+        int month = JANUARY;
+        int firstDayOfMonth = 1;
+        if (isFieldSet(fieldMask, MONTH)) {
+            // No need to check if MONTH has been set (no isSet(MONTH)
+            // call) since its unset value happens to be JANUARY (0).
+            month = internalGet(MONTH);
+
+            // If the month is out of range, adjust it into range.
+            if (month > DECEMBER) {
+                year += month / 12;
+                month %= 12;
+            } else if (month < JANUARY) {
+                int[] rem = new int[1];
+                year += CalendarUtils.floorDivide(month, 12, rem);
+                month = rem[0];
+            }
+        } else {
+            if (year == 1 && era != 0) {
+                CalendarDate d = eras[era].getSinceDate();
+                month = d.getMonth() - 1;
+                firstDayOfMonth = d.getDayOfMonth();
+            }
+        }
+
+        // Adjust the base date if year is the minimum value.
+        if (year == MIN_VALUES[YEAR]) {
+            CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+            int m = dx.getMonth() - 1;
+            if (month < m) {
+                month = m;
+            }
+            if (month == m) {
+                firstDayOfMonth = dx.getDayOfMonth();
+            }
+        }
+
+        LocalGregorianCalendar.Date date = jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        date.setEra(era > 0 ? eras[era] : null);
+        date.setDate(year, month + 1, firstDayOfMonth);
+        jcal.normalize(date);
+
+        // Get the fixed date since Jan 1, 1 (Gregorian). We are on
+        // the first day of either `month' or January in 'year'.
+        long fixedDate = jcal.getFixedDate(date);
+
+        if (isFieldSet(fieldMask, MONTH)) {
+            // Month-based calculations
+            if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
+                // We are on the "first day" of the month (which may
+                // not be 1). Just add the offset if DAY_OF_MONTH is
+                // set. If the isSet call returns false, that means
+                // DAY_OF_MONTH has been selected just because of the
+                // selected combination. We don't need to add any
+                // since the default value is the "first day".
+                if (isSet(DAY_OF_MONTH)) {
+                    // To avoid underflow with DAY_OF_MONTH-firstDayOfMonth, add
+                    // DAY_OF_MONTH, then subtract firstDayOfMonth.
+                    fixedDate += internalGet(DAY_OF_MONTH);
+                    fixedDate -= firstDayOfMonth;
+                }
+            } else {
+                if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
+                    long firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                                            getFirstDayOfWeek());
+                    // If we have enough days in the first week, then
+                    // move to the previous week.
+                    if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                        firstDayOfWeek -= 7;
+                    }
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                           internalGet(DAY_OF_WEEK));
+                    }
+                    // In lenient mode, we treat days of the previous
+                    // months as a part of the specified
+                    // WEEK_OF_MONTH. See 4633646.
+                    fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
+                } else {
+                    int dayOfWeek;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        dayOfWeek = internalGet(DAY_OF_WEEK);
+                    } else {
+                        dayOfWeek = getFirstDayOfWeek();
+                    }
+                    // We are basing this on the day-of-week-in-month.  The only
+                    // trickiness occurs if the day-of-week-in-month is
+                    // negative.
+                    int dowim;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
+                        dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
+                    } else {
+                        dowim = 1;
+                    }
+                    if (dowim >= 0) {
+                        fixedDate = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
+                                                                                      dayOfWeek);
+                    } else {
+                        // Go to the first day of the next week of
+                        // the specified week boundary.
+                        int lastDate = monthLength(month, year) + (7 * (dowim + 1));
+                        // Then, get the day of week date on or before the last date.
+                        fixedDate = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
+                                                                                      dayOfWeek);
+                    }
+                }
+            }
+        } else {
+            // We are on the first day of the year.
+            if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
+                if (isTransitionYear(date.getNormalizedYear())) {
+                    fixedDate = getFixedDateJan1(date, fixedDate);
+                }
+                // Add the offset, then subtract 1. (Make sure to avoid underflow.)
+                fixedDate += internalGet(DAY_OF_YEAR);
+                fixedDate--;
+            } else {
+                long firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                                        getFirstDayOfWeek());
+                // If we have enough days in the first week, then move
+                // to the previous week.
+                if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                    firstDayOfWeek -= 7;
+                }
+                if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                    int dayOfWeek = internalGet(DAY_OF_WEEK);
+                    if (dayOfWeek != getFirstDayOfWeek()) {
+                        firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                           dayOfWeek);
+                    }
+                }
+                fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
+            }
+        }
+        return fixedDate;
+    }
+
+    /**
+     * Returns the fixed date of the first day of the year (usually
+     * January 1) before the specified date.
+     *
+     * @param date the date for which the first day of the year is
+     * calculated. The date has to be in the cut-over year.
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateJan1(LocalGregorianCalendar.Date date, long fixedDate) {
+        Era era = date.getEra();
+        if (date.getEra() != null && date.getYear() == 1) {
+            for (int eraIndex = getEraIndex(date); eraIndex > 0; eraIndex--) {
+                CalendarDate d = eras[eraIndex].getSinceDate();
+                long fd = gcal.getFixedDate(d);
+                // There might be multiple era transitions in a year.
+                if (fd > fixedDate) {
+                    continue;
+                }
+                return fd;
+            }
+        }
+        CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        d.setDate(date.getNormalizedYear(), Gregorian.JANUARY, 1);
+        return gcal.getFixedDate(d);
+    }
+
+    /**
+     * Returns the fixed date of the first date of the month (usually
+     * the 1st of the month) before the specified date.
+     *
+     * @param date the date for which the first day of the month is
+     * calculated. The date must be in the era transition year.
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateMonth1(LocalGregorianCalendar.Date date,
+                                          long fixedDate) {
+        int eraIndex = getTransitionEraIndex(date);
+        if (eraIndex != -1) {
+            long transition = sinceFixedDates[eraIndex];
+            // If the given date is on or after the transition date, then
+            // return the transition date.
+            if (transition <= fixedDate) {
+                return transition;
+            }
+        }
+
+        // Otherwise, we can use the 1st day of the month.
+        return fixedDate - date.getDayOfMonth() + 1;
+    }
+
+    /**
+     * Returns a LocalGregorianCalendar.Date produced from the specified fixed date.
+     *
+     * @param fd the fixed date
+     */
+    private static LocalGregorianCalendar.Date getCalendarDate(long fd) {
+        LocalGregorianCalendar.Date d = jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        jcal.getCalendarDateFromFixedDate(d, fd);
+        return d;
+    }
+
+    /**
+     * Returns the length of the specified month in the specified
+     * Gregorian year. The year number must be normalized.
+     *
+     * @see GregorianCalendar#isLeapYear(int)
+     */
+    private int monthLength(int month, int gregorianYear) {
+        return CalendarUtils.isGregorianLeapYear(gregorianYear) ?
+            GregorianCalendar.LEAP_MONTH_LENGTH[month] : GregorianCalendar.MONTH_LENGTH[month];
+    }
+
+    /**
+     * Returns the length of the specified month in the year provided
+     * by internalGet(YEAR).
+     *
+     * @see GregorianCalendar#isLeapYear(int)
+     */
+    private int monthLength(int month) {
+        assert jdate.isNormalized();
+        return jdate.isLeapYear() ?
+            GregorianCalendar.LEAP_MONTH_LENGTH[month] : GregorianCalendar.MONTH_LENGTH[month];
+    }
+
+    private int actualMonthLength() {
+        int length = jcal.getMonthLength(jdate);
+        int eraIndex = getTransitionEraIndex(jdate);
+        if (eraIndex == -1) {
+            long transitionFixedDate = sinceFixedDates[eraIndex];
+            CalendarDate d = eras[eraIndex].getSinceDate();
+            if (transitionFixedDate <= cachedFixedDate) {
+                length -= d.getDayOfMonth() - 1;
+            } else {
+                length = d.getDayOfMonth() - 1;
+            }
+        }
+        return length;
+    }
+
+    /**
+     * Returns the index to the new era if the given date is in a
+     * transition month.  For example, if the give date is Heisei 1
+     * (1989) January 20, then the era index for Heisei is
+     * returned. Likewise, if the given date is Showa 64 (1989)
+     * January 3, then the era index for Heisei is returned. If the
+     * given date is not in any transition month, then -1 is returned.
+     */
+    private static int getTransitionEraIndex(LocalGregorianCalendar.Date date) {
+        int eraIndex = getEraIndex(date);
+        CalendarDate transitionDate = eras[eraIndex].getSinceDate();
+        if (transitionDate.getYear() == date.getNormalizedYear() &&
+            transitionDate.getMonth() == date.getMonth()) {
+            return eraIndex;
+        }
+        if (eraIndex < eras.length - 1) {
+            transitionDate = eras[++eraIndex].getSinceDate();
+            if (transitionDate.getYear() == date.getNormalizedYear() &&
+                transitionDate.getMonth() == date.getMonth()) {
+                return eraIndex;
+            }
+        }
+        return -1;
+    }
+
+    private boolean isTransitionYear(int normalizedYear) {
+        for (int i = eras.length - 1; i > 0; i--) {
+            int transitionYear = eras[i].getSinceDate().getYear();
+            if (normalizedYear == transitionYear) {
+                return true;
+            }
+            if (normalizedYear > transitionYear) {
+                break;
+            }
+        }
+        return false;
+    }
+
+    private static int getEraIndex(LocalGregorianCalendar.Date date) {
+        Era era = date.getEra();
+        for (int i = eras.length - 1; i > 0; i--) {
+            if (eras[i] == era) {
+                return i;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Returns this object if it's normalized (all fields and time are
+     * in sync). Otherwise, a cloned object is returned after calling
+     * complete() in lenient mode.
+     */
+    private JapaneseImperialCalendar getNormalizedCalendar() {
+        JapaneseImperialCalendar jc;
+        if (isFullyNormalized()) {
+            jc = this;
+        } else {
+            // Create a clone and normalize the calendar fields
+            jc = (JapaneseImperialCalendar) this.clone();
+            jc.setLenient(true);
+            jc.complete();
+        }
+        return jc;
+    }
+
+    /**
+     * After adjustments such as add(MONTH), add(YEAR), we don't want the
+     * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
+     * 3, we want it to go to Feb 28.  Adjustments which might run into this
+     * problem call this method to retain the proper month.
+     */
+    private void pinDayOfMonth(LocalGregorianCalendar.Date date) {
+        int year = date.getYear();
+        int dom = date.getDayOfMonth();
+        if (year != getMinimum(YEAR)) {
+            date.setDayOfMonth(1);
+            jcal.normalize(date);
+            int monthLength = jcal.getMonthLength(date);
+            if (dom > monthLength) {
+                date.setDayOfMonth(monthLength);
+            } else {
+                date.setDayOfMonth(dom);
+            }
+            jcal.normalize(date);
+        } else {
+            LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+            LocalGregorianCalendar.Date realDate = jcal.getCalendarDate(time, getZone());
+            long tod = realDate.getTimeOfDay();
+            // Use an equivalent year.
+            realDate.addYear(+400);
+            realDate.setMonth(date.getMonth());
+            realDate.setDayOfMonth(1);
+            jcal.normalize(realDate);
+            int monthLength = jcal.getMonthLength(realDate);
+            if (dom > monthLength) {
+                realDate.setDayOfMonth(monthLength);
+            } else {
+                if (dom < d.getDayOfMonth()) {
+                    realDate.setDayOfMonth(d.getDayOfMonth());
+                } else {
+                    realDate.setDayOfMonth(dom);
+                }
+            }
+            if (realDate.getDayOfMonth() == d.getDayOfMonth() && tod < d.getTimeOfDay()) {
+                realDate.setDayOfMonth(Math.min(dom + 1, monthLength));
+            }
+            // restore the year.
+            date.setDate(year, realDate.getMonth(), realDate.getDayOfMonth());
+            // Don't normalize date here so as not to cause underflow.
+        }
+    }
+
+    /**
+     * Returns the new value after 'roll'ing the specified value and amount.
+     */
+    private static int getRolledValue(int value, int amount, int min, int max) {
+        assert value >= min && value <= max;
+        int range = max - min + 1;
+        amount %= range;
+        int n = value + amount;
+        if (n > max) {
+            n -= range;
+        } else if (n < min) {
+            n += range;
+        }
+        assert n >= min && n <= max;
+        return n;
+    }
+
+    /**
+     * Returns the ERA.  We need a special method for this because the
+     * default ERA is the current era, but a zero (unset) ERA means before Meiji.
+     */
+    private int internalGetEra() {
+        return isSet(ERA) ? internalGet(ERA) : currentEra;
+    }
+
+    /**
+     * Updates internal state.
+     */
+    private void readObject(ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+        stream.defaultReadObject();
+        if (jdate == null) {
+            jdate = jcal.newCalendarDate(getZone());
+            cachedFixedDate = Long.MIN_VALUE;
+        }
+    }
+}
diff --git a/java/util/JumboEnumSet.java b/java/util/JumboEnumSet.java
new file mode 100644
index 0000000..6798511
--- /dev/null
+++ b/java/util/JumboEnumSet.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Private implementation class for EnumSet, for "jumbo" enum types
+ * (i.e., those with more than 64 elements).
+ *
+ * @author Josh Bloch
+ * @since 1.5
+ * @serial exclude
+ */
+class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
+    private static final long serialVersionUID = 334349849919042784L;
+
+    /**
+     * Bit vector representation of this set.  The ith bit of the jth
+     * element of this array represents the  presence of universe[64*j +i]
+     * in this set.
+     */
+    private long elements[];
+
+    // Redundant - maintained for performance
+    private int size = 0;
+
+    JumboEnumSet(Class<E>elementType, Enum<?>[] universe) {
+        super(elementType, universe);
+        elements = new long[(universe.length + 63) >>> 6];
+    }
+
+    void addRange(E from, E to) {
+        int fromIndex = from.ordinal() >>> 6;
+        int toIndex = to.ordinal() >>> 6;
+
+        if (fromIndex == toIndex) {
+            elements[fromIndex] = (-1L >>>  (from.ordinal() - to.ordinal() - 1))
+                            << from.ordinal();
+        } else {
+            elements[fromIndex] = (-1L << from.ordinal());
+            for (int i = fromIndex + 1; i < toIndex; i++)
+                elements[i] = -1;
+            elements[toIndex] = -1L >>> (63 - to.ordinal());
+        }
+        size = to.ordinal() - from.ordinal() + 1;
+    }
+
+    void addAll() {
+        for (int i = 0; i < elements.length; i++)
+            elements[i] = -1;
+        elements[elements.length - 1] >>>= -universe.length;
+        size = universe.length;
+    }
+
+    void complement() {
+        for (int i = 0; i < elements.length; i++)
+            elements[i] = ~elements[i];
+        elements[elements.length - 1] &= (-1L >>> -universe.length);
+        size = universe.length - size;
+    }
+
+    /**
+     * Returns an iterator over the elements contained in this set.  The
+     * iterator traverses the elements in their <i>natural order</i> (which is
+     * the order in which the enum constants are declared). The returned
+     * Iterator is a "weakly consistent" iterator that will never throw {@link
+     * ConcurrentModificationException}.
+     *
+     * @return an iterator over the elements contained in this set
+     */
+    public Iterator<E> iterator() {
+        return new EnumSetIterator<>();
+    }
+
+    private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
+        /**
+         * A bit vector representing the elements in the current "word"
+         * of the set not yet returned by this iterator.
+         */
+        long unseen;
+
+        /**
+         * The index corresponding to unseen in the elements array.
+         */
+        int unseenIndex = 0;
+
+        /**
+         * The bit representing the last element returned by this iterator
+         * but not removed, or zero if no such element exists.
+         */
+        long lastReturned = 0;
+
+        /**
+         * The index corresponding to lastReturned in the elements array.
+         */
+        int lastReturnedIndex = 0;
+
+        EnumSetIterator() {
+            unseen = elements[0];
+        }
+
+        @Override
+        public boolean hasNext() {
+            while (unseen == 0 && unseenIndex < elements.length - 1)
+                unseen = elements[++unseenIndex];
+            return unseen != 0;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturned = unseen & -unseen;
+            lastReturnedIndex = unseenIndex;
+            unseen -= lastReturned;
+            return (E) universe[(lastReturnedIndex << 6)
+                                + Long.numberOfTrailingZeros(lastReturned)];
+        }
+
+        @Override
+        public void remove() {
+            if (lastReturned == 0)
+                throw new IllegalStateException();
+            final long oldElements = elements[lastReturnedIndex];
+            elements[lastReturnedIndex] &= ~lastReturned;
+            if (oldElements != elements[lastReturnedIndex]) {
+                size--;
+            }
+            lastReturned = 0;
+        }
+    }
+
+    /**
+     * Returns the number of elements in this set.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains no elements.
+     *
+     * @return <tt>true</tt> if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains the specified element.
+     *
+     * @param e element to be checked for containment in this collection
+     * @return <tt>true</tt> if this set contains the specified element
+     */
+    public boolean contains(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+
+        int eOrdinal = ((Enum<?>)e).ordinal();
+        return (elements[eOrdinal >>> 6] & (1L << eOrdinal)) != 0;
+    }
+
+    // Modification Operations
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     *
+     * @param e element to be added to this set
+     * @return <tt>true</tt> if the set changed as a result of the call
+     *
+     * @throws NullPointerException if <tt>e</tt> is null
+     */
+    public boolean add(E e) {
+        typeCheck(e);
+
+        int eOrdinal = e.ordinal();
+        int eWordNum = eOrdinal >>> 6;
+
+        long oldElements = elements[eWordNum];
+        elements[eWordNum] |= (1L << eOrdinal);
+        boolean result = (elements[eWordNum] != oldElements);
+        if (result)
+            size++;
+        return result;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     *
+     * @param e element to be removed from this set, if present
+     * @return <tt>true</tt> if the set contained the specified element
+     */
+    public boolean remove(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+        int eOrdinal = ((Enum<?>)e).ordinal();
+        int eWordNum = eOrdinal >>> 6;
+
+        long oldElements = elements[eWordNum];
+        elements[eWordNum] &= ~(1L << eOrdinal);
+        boolean result = (elements[eWordNum] != oldElements);
+        if (result)
+            size--;
+        return result;
+    }
+
+    // Bulk Operations
+
+    /**
+     * Returns <tt>true</tt> if this set contains all of the elements
+     * in the specified collection.
+     *
+     * @param c collection to be checked for containment in this set
+     * @return <tt>true</tt> if this set contains all of the elements
+     *        in the specified collection
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean containsAll(Collection<?> c) {
+        if (!(c instanceof JumboEnumSet))
+            return super.containsAll(c);
+
+        JumboEnumSet<?> es = (JumboEnumSet<?>)c;
+        if (es.elementType != elementType)
+            return es.isEmpty();
+
+        for (int i = 0; i < elements.length; i++)
+            if ((es.elements[i] & ~elements[i]) != 0)
+                return false;
+        return true;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set.
+     *
+     * @param c collection whose elements are to be added to this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection or any of
+     *     its elements are null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (!(c instanceof JumboEnumSet))
+            return super.addAll(c);
+
+        JumboEnumSet<?> es = (JumboEnumSet<?>)c;
+        if (es.elementType != elementType) {
+            if (es.isEmpty())
+                return false;
+            else
+                throw new ClassCastException(
+                    es.elementType + " != " + elementType);
+        }
+
+        for (int i = 0; i < elements.length; i++)
+            elements[i] |= es.elements[i];
+        return recalculateSize();
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in
+     * the specified collection.
+     *
+     * @param c elements to be removed from this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean removeAll(Collection<?> c) {
+        if (!(c instanceof JumboEnumSet))
+            return super.removeAll(c);
+
+        JumboEnumSet<?> es = (JumboEnumSet<?>)c;
+        if (es.elementType != elementType)
+            return false;
+
+        for (int i = 0; i < elements.length; i++)
+            elements[i] &= ~es.elements[i];
+        return recalculateSize();
+    }
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection.
+     *
+     * @param c elements to be retained in this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean retainAll(Collection<?> c) {
+        if (!(c instanceof JumboEnumSet))
+            return super.retainAll(c);
+
+        JumboEnumSet<?> es = (JumboEnumSet<?>)c;
+        if (es.elementType != elementType) {
+            boolean changed = (size != 0);
+            clear();
+            return changed;
+        }
+
+        for (int i = 0; i < elements.length; i++)
+            elements[i] &= es.elements[i];
+        return recalculateSize();
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     */
+    public void clear() {
+        Arrays.fill(elements, 0);
+        size = 0;
+    }
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * <tt>true</tt> if the given object is also a set, the two sets have
+     * the same size, and every member of the given set is contained in
+     * this set.
+     *
+     * @param o object to be compared for equality with this set
+     * @return <tt>true</tt> if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        if (!(o instanceof JumboEnumSet))
+            return super.equals(o);
+
+        JumboEnumSet<?> es = (JumboEnumSet<?>)o;
+        if (es.elementType != elementType)
+            return size == 0 && es.size == 0;
+
+        return Arrays.equals(es.elements, elements);
+    }
+
+    /**
+     * Recalculates the size of the set.  Returns true if it's changed.
+     */
+    private boolean recalculateSize() {
+        int oldSize = size;
+        size = 0;
+        for (long elt : elements)
+            size += Long.bitCount(elt);
+
+        return size != oldSize;
+    }
+
+    public EnumSet<E> clone() {
+        JumboEnumSet<E> result = (JumboEnumSet<E>) super.clone();
+        result.elements = result.elements.clone();
+        return result;
+    }
+}
diff --git a/java/util/KeyValueHolder.java b/java/util/KeyValueHolder.java
new file mode 100644
index 0000000..3b7250e
--- /dev/null
+++ b/java/util/KeyValueHolder.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import jdk.internal.vm.annotation.Stable;
+
+/**
+ * An immutable container for a key and a value, suitable for use
+ * in creating and populating {@code Map} instances.
+ *
+ * <p>This is a <a href="../lang/doc-files/ValueBased.html">value-based</a>
+ * class; use of identity-sensitive operations (including reference equality
+ * ({@code ==}), identity hash code, or synchronization) on instances of
+ * {@code KeyValueHolder} may have unpredictable results and should be avoided.
+ *
+ * @apiNote
+ * This class is not public. Instances can be created using the
+ * {@link Map#entry Map.entry(k, v)} factory method, which is public.
+ *
+ * <p>This class differs from AbstractMap.SimpleImmutableEntry in the following ways:
+ * it is not serializable, it is final, and its key and value must be non-null.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ *
+ * @see Map#ofEntries Map.ofEntries()
+ * @since 9
+ */
+final class KeyValueHolder<K,V> implements Map.Entry<K,V> {
+    @Stable
+    final K key;
+    @Stable
+    final V value;
+
+    KeyValueHolder(K k, V v) {
+        key = Objects.requireNonNull(k);
+        value = Objects.requireNonNull(v);
+    }
+
+    /**
+     * Gets the key from this holder.
+     *
+     * @return the key
+     */
+    @Override
+    public K getKey() {
+        return key;
+    }
+
+    /**
+     * Gets the value from this holder.
+     *
+     * @return the value
+     */
+    @Override
+    public V getValue() {
+        return value;
+    }
+
+    /**
+     * Throws {@link UnsupportedOperationException}.
+     *
+     * @param value ignored
+     * @return never returns normally
+     */
+    @Override
+    public V setValue(V value) {
+        throw new UnsupportedOperationException("not supported");
+    }
+
+    /**
+     * Compares the specified object with this entry for equality.
+     * Returns {@code true} if the given object is also a map entry and
+     * the two entries' keys and values are equal. Note that key and
+     * value are non-null, so equals() can be called safely on them.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof Map.Entry))
+            return false;
+        Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+        return key.equals(e.getKey()) && value.equals(e.getValue());
+    }
+
+    /**
+     * Returns the hash code value for this map entry. The hash code
+     * is {@code key.hashCode() ^ value.hashCode()}. Note that key and
+     * value are non-null, so hashCode() can be called safely on them.
+     */
+    @Override
+    public int hashCode() {
+        return key.hashCode() ^ value.hashCode();
+    }
+
+    /**
+     * Returns a String representation of this map entry.  This
+     * implementation returns the string representation of this
+     * entry's key followed by the equals character ("{@code =}")
+     * followed by the string representation of this entry's value.
+     *
+     * @return a String representation of this map entry
+     */
+    @Override
+    public String toString() {
+        return key + "=" + value;
+    }
+}
diff --git a/java/util/LinkedHashMap.annotated.java b/java/util/LinkedHashMap.annotated.java
new file mode 100644
index 0000000..9f494b6
--- /dev/null
+++ b/java/util/LinkedHashMap.annotated.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class LinkedHashMap<K, V> extends java.util.HashMap<K,V> implements java.util.Map<K,V> {
+
+public LinkedHashMap(int initialCapacity, float loadFactor) { throw new RuntimeException("Stub!"); }
+
+public LinkedHashMap(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+public LinkedHashMap() { throw new RuntimeException("Stub!"); }
+
+public LinkedHashMap(java.util.Map<? extends K, ? extends V> m) { throw new RuntimeException("Stub!"); }
+
+public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { throw new RuntimeException("Stub!"); }
+
+public boolean containsValue(java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public V get(java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public V getOrDefault(java.lang.Object key, V defaultValue) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public java.util.Map.Entry<K,V> eldest() { throw new RuntimeException("Stub!"); }
+
+protected boolean removeEldestEntry(java.util.Map.Entry<K,V> eldest) { throw new RuntimeException("Stub!"); }
+
+public java.util.Set<K> keySet() { throw new RuntimeException("Stub!"); }
+
+public java.util.Collection<V> values() { throw new RuntimeException("Stub!"); }
+
+public java.util.Set<java.util.Map.Entry<K,V>> entrySet() { throw new RuntimeException("Stub!"); }
+
+public void forEach(java.util.function.BiConsumer<? super K,? super V> action) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(java.util.function.BiFunction<? super K,? super V,? extends V> function) { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/util/LinkedHashMap.java b/java/util/LinkedHashMap.java
new file mode 100644
index 0000000..9d3815f
--- /dev/null
+++ b/java/util/LinkedHashMap.java
@@ -0,0 +1,794 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.io.IOException;
+
+// Android-added: Note about spliterator order b/33945212 in Android N
+/**
+ * <p>Hash table and linked list implementation of the <tt>Map</tt> interface,
+ * with predictable iteration order.  This implementation differs from
+ * <tt>HashMap</tt> in that it maintains a doubly-linked list running through
+ * all of its entries.  This linked list defines the iteration ordering,
+ * which is normally the order in which keys were inserted into the map
+ * (<i>insertion-order</i>).  Note that insertion order is not affected
+ * if a key is <i>re-inserted</i> into the map.  (A key <tt>k</tt> is
+ * reinserted into a map <tt>m</tt> if <tt>m.put(k, v)</tt> is invoked when
+ * <tt>m.containsKey(k)</tt> would return <tt>true</tt> immediately prior to
+ * the invocation.)
+ *
+ * <p>This implementation spares its clients from the unspecified, generally
+ * chaotic ordering provided by {@link HashMap} (and {@link Hashtable}),
+ * without incurring the increased cost associated with {@link TreeMap}.  It
+ * can be used to produce a copy of a map that has the same order as the
+ * original, regardless of the original map's implementation:
+ * <pre>
+ *     void foo(Map m) {
+ *         Map copy = new LinkedHashMap(m);
+ *         ...
+ *     }
+ * </pre>
+ * This technique is particularly useful if a module takes a map on input,
+ * copies it, and later returns results whose order is determined by that of
+ * the copy.  (Clients generally appreciate having things returned in the same
+ * order they were presented.)
+ *
+ * <p>A special {@link #LinkedHashMap(int,float,boolean) constructor} is
+ * provided to create a linked hash map whose order of iteration is the order
+ * in which its entries were last accessed, from least-recently accessed to
+ * most-recently (<i>access-order</i>).  This kind of map is well-suited to
+ * building LRU caches.  Invoking the {@code put}, {@code putIfAbsent},
+ * {@code get}, {@code getOrDefault}, {@code compute}, {@code computeIfAbsent},
+ * {@code computeIfPresent}, or {@code merge} methods results
+ * in an access to the corresponding entry (assuming it exists after the
+ * invocation completes). The {@code replace} methods only result in an access
+ * of the entry if the value is replaced.  The {@code putAll} method generates one
+ * entry access for each mapping in the specified map, in the order that
+ * key-value mappings are provided by the specified map's entry set iterator.
+ * <i>No other methods generate entry accesses.</i>  In particular, operations
+ * on collection-views do <i>not</i> affect the order of iteration of the
+ * backing map.
+ *
+ * <p>The {@link #removeEldestEntry(Map.Entry)} method may be overridden to
+ * impose a policy for removing stale mappings automatically when new mappings
+ * are added to the map.
+ *
+ * <p>This class provides all of the optional <tt>Map</tt> operations, and
+ * permits null elements.  Like <tt>HashMap</tt>, it provides constant-time
+ * performance for the basic operations (<tt>add</tt>, <tt>contains</tt> and
+ * <tt>remove</tt>), assuming the hash function disperses elements
+ * properly among the buckets.  Performance is likely to be just slightly
+ * below that of <tt>HashMap</tt>, due to the added expense of maintaining the
+ * linked list, with one exception: Iteration over the collection-views
+ * of a <tt>LinkedHashMap</tt> requires time proportional to the <i>size</i>
+ * of the map, regardless of its capacity.  Iteration over a <tt>HashMap</tt>
+ * is likely to be more expensive, requiring time proportional to its
+ * <i>capacity</i>.
+ *
+ * <p>A linked hash map has two parameters that affect its performance:
+ * <i>initial capacity</i> and <i>load factor</i>.  They are defined precisely
+ * as for <tt>HashMap</tt>.  Note, however, that the penalty for choosing an
+ * excessively high value for initial capacity is less severe for this class
+ * than for <tt>HashMap</tt>, as iteration times for this class are unaffected
+ * by capacity.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a linked hash map concurrently, and at least
+ * one of the threads modifies the map structurally, it <em>must</em> be
+ * synchronized externally.  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the map.
+ *
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map:<pre>
+ *   Map m = Collections.synchronizedMap(new LinkedHashMap(...));</pre>
+ *
+ * A structural modification is any operation that adds or deletes one or more
+ * mappings or, in the case of access-ordered linked hash maps, affects
+ * iteration order.  In insertion-ordered linked hash maps, merely changing
+ * the value associated with a key that is already contained in the map is not
+ * a structural modification.  <strong>In access-ordered linked hash maps,
+ * merely querying the map with <tt>get</tt> is a structural modification.
+ * </strong>)
+ *
+ * <p>The iterators returned by the <tt>iterator</tt> method of the collections
+ * returned by all of this class's collection view methods are
+ * <em>fail-fast</em>: if the map is structurally modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * <tt>remove</tt> method, 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 time in the future.
+ *
+ * <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.
+ * 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>
+ *
+ * <p>The spliterators returned by the spliterator method of the collections
+ * returned by all of this class's collection view methods are
+ * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+ * <em>fail-fast</em>, and additionally report {@link Spliterator#ORDERED}.
+ * <em>Note</em>: The implementation of these spliterators in Android Nougat
+ * (API levels 24 and 25) uses the wrong order (inconsistent with the
+ * iterators, which use the correct order), despite reporting
+ * {@link Spliterator#ORDERED}. You may use the following code fragments
+ * to obtain a correctly ordered Spliterator on API level 24 and 25:
+ * <ul>
+ *     <li>For a Collection view {@code c = lhm.keySet()},
+ *         {@code c = lhm.entrySet()} or {@code c = lhm.values()}, use
+ *         {@code java.util.Spliterators.spliterator(c, c.spliterator().characteristics())}
+ *         instead of {@code c.spliterator()}.
+ *     <li>Instead of {@code c.stream()} or {@code c.parallelStream()}, use
+ *         {@code java.util.stream.StreamSupport.stream(spliterator, false)}
+ *         to construct a (nonparallel) {@link java.util.stream.Stream} from
+ *         such a {@code Spliterator}.
+ * </ul>
+ * Note that these workarounds are only suggested where {@code lhm} is a
+ * {@code LinkedHashMap}.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @implNote
+ * The spliterators returned by the spliterator method of the collections
+ * returned by all of this class's collection view methods are created from
+ * the iterators of the corresponding collections.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Map
+ * @see     HashMap
+ * @see     TreeMap
+ * @see     Hashtable
+ * @since   1.4
+ */
+public class LinkedHashMap<K,V>
+    extends HashMap<K,V>
+    implements Map<K,V>
+{
+
+    /*
+     * Implementation note.  A previous version of this class was
+     * internally structured a little differently. Because superclass
+     * HashMap now uses trees for some of its nodes, class
+     * LinkedHashMap.Entry is now treated as intermediary node class
+     * that can also be converted to tree form.
+     *
+     // BEGIN Android-changed
+     * LinkedHashMapEntry should not be renamed. Specifically, for
+     * source compatibility with earlier versions of Android, this
+     * nested class must not be named "Entry". Otherwise, it would
+     * hide Map.Entry which would break compilation of code like:
+     *
+     * LinkedHashMap.Entry<K, V> entry = map.entrySet().iterator.next()
+     *
+     * To compile, that code snippet's "LinkedHashMap.Entry" must
+     * mean java.util.Map.Entry which is the compile time type of
+     * entrySet()'s elements.
+     // END Android-changed
+     *
+     * The changes in node classes also require using two fields
+     * (head, tail) rather than a pointer to a header node to maintain
+     * the doubly-linked before/after list. This class also
+     * previously used a different style of callback methods upon
+     * access, insertion, and removal.
+     */
+
+    /**
+     * HashMap.Node subclass for normal LinkedHashMap entries.
+     */
+    static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> {
+        LinkedHashMapEntry<K,V> before, after;
+        LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) {
+            super(hash, key, value, next);
+        }
+    }
+
+    private static final long serialVersionUID = 3801124242820219131L;
+
+    /**
+     * The head (eldest) of the doubly linked list.
+     */
+    transient LinkedHashMapEntry<K,V> head;
+
+    /**
+     * The tail (youngest) of the doubly linked list.
+     */
+    transient LinkedHashMapEntry<K,V> tail;
+
+    /**
+     * The iteration ordering method for this linked hash map: <tt>true</tt>
+     * for access-order, <tt>false</tt> for insertion-order.
+     *
+     * @serial
+     */
+    final boolean accessOrder;
+
+    // internal utilities
+
+    // link at the end of list
+    private void linkNodeLast(LinkedHashMapEntry<K,V> p) {
+        LinkedHashMapEntry<K,V> last = tail;
+        tail = p;
+        if (last == null)
+            head = p;
+        else {
+            p.before = last;
+            last.after = p;
+        }
+    }
+
+    // apply src's links to dst
+    private void transferLinks(LinkedHashMapEntry<K,V> src,
+                               LinkedHashMapEntry<K,V> dst) {
+        LinkedHashMapEntry<K,V> b = dst.before = src.before;
+        LinkedHashMapEntry<K,V> a = dst.after = src.after;
+        if (b == null)
+            head = dst;
+        else
+            b.after = dst;
+        if (a == null)
+            tail = dst;
+        else
+            a.before = dst;
+    }
+
+    // overrides of HashMap hook methods
+
+    void reinitialize() {
+        super.reinitialize();
+        head = tail = null;
+    }
+
+    Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
+        LinkedHashMapEntry<K,V> p =
+            new LinkedHashMapEntry<K,V>(hash, key, value, e);
+        linkNodeLast(p);
+        return p;
+    }
+
+    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
+        LinkedHashMapEntry<K,V> q = (LinkedHashMapEntry<K,V>)p;
+        LinkedHashMapEntry<K,V> t =
+            new LinkedHashMapEntry<K,V>(q.hash, q.key, q.value, next);
+        transferLinks(q, t);
+        return t;
+    }
+
+    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
+        TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
+        linkNodeLast(p);
+        return p;
+    }
+
+    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
+        LinkedHashMapEntry<K,V> q = (LinkedHashMapEntry<K,V>)p;
+        TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
+        transferLinks(q, t);
+        return t;
+    }
+
+    void afterNodeRemoval(Node<K,V> e) { // unlink
+        LinkedHashMapEntry<K,V> p =
+            (LinkedHashMapEntry<K,V>)e, b = p.before, a = p.after;
+        p.before = p.after = null;
+        if (b == null)
+            head = a;
+        else
+            b.after = a;
+        if (a == null)
+            tail = b;
+        else
+            a.before = b;
+    }
+
+    void afterNodeInsertion(boolean evict) { // possibly remove eldest
+        LinkedHashMapEntry<K,V> first;
+        if (evict && (first = head) != null && removeEldestEntry(first)) {
+            K key = first.key;
+            removeNode(hash(key), key, null, false, true);
+        }
+    }
+
+    void afterNodeAccess(Node<K,V> e) { // move node to last
+        LinkedHashMapEntry<K,V> last;
+        if (accessOrder && (last = tail) != e) {
+            LinkedHashMapEntry<K,V> p =
+                (LinkedHashMapEntry<K,V>)e, b = p.before, a = p.after;
+            p.after = null;
+            if (b == null)
+                head = a;
+            else
+                b.after = a;
+            if (a != null)
+                a.before = b;
+            else
+                last = b;
+            if (last == null)
+                head = p;
+            else {
+                p.before = last;
+                last.after = p;
+            }
+            tail = p;
+            ++modCount;
+        }
+    }
+
+    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
+        for (LinkedHashMapEntry<K,V> e = head; e != null; e = e.after) {
+            s.writeObject(e.key);
+            s.writeObject(e.value);
+        }
+    }
+
+    /**
+     * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
+     * with the specified initial capacity and load factor.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public LinkedHashMap(int initialCapacity, float loadFactor) {
+        super(initialCapacity, loadFactor);
+        accessOrder = false;
+    }
+
+    /**
+     * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
+     * with the specified initial capacity and a default load factor (0.75).
+     *
+     * @param  initialCapacity the initial capacity
+     * @throws IllegalArgumentException if the initial capacity is negative
+     */
+    public LinkedHashMap(int initialCapacity) {
+        super(initialCapacity);
+        accessOrder = false;
+    }
+
+    /**
+     * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
+     * with the default initial capacity (16) and load factor (0.75).
+     */
+    public LinkedHashMap() {
+        super();
+        accessOrder = false;
+    }
+
+    /**
+     * Constructs an insertion-ordered <tt>LinkedHashMap</tt> instance with
+     * the same mappings as the specified map.  The <tt>LinkedHashMap</tt>
+     * instance is created with a default load factor (0.75) and an initial
+     * capacity sufficient to hold the mappings in the specified map.
+     *
+     * @param  m the map whose mappings are to be placed in this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public LinkedHashMap(Map<? extends K, ? extends V> m) {
+        super();
+        accessOrder = false;
+        putMapEntries(m, false);
+    }
+
+    /**
+     * Constructs an empty <tt>LinkedHashMap</tt> instance with the
+     * specified initial capacity, load factor and ordering mode.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @param  accessOrder     the ordering mode - <tt>true</tt> for
+     *         access-order, <tt>false</tt> for insertion-order
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public LinkedHashMap(int initialCapacity,
+                         float loadFactor,
+                         boolean accessOrder) {
+        super(initialCapacity, loadFactor);
+        this.accessOrder = accessOrder;
+    }
+
+
+    /**
+     * 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) {
+        for (LinkedHashMapEntry<K,V> e = head; e != null; e = e.after) {
+            V v = e.value;
+            if (v == value || (value != null && value.equals(v)))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
+     * key.equals(k))}, then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} 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 {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     */
+    public V get(Object key) {
+        Node<K,V> e;
+        if ((e = getNode(hash(key), key)) == null)
+            return null;
+        if (accessOrder)
+            afterNodeAccess(e);
+        return e.value;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public V getOrDefault(Object key, V defaultValue) {
+       Node<K,V> e;
+       if ((e = getNode(hash(key), key)) == null)
+           return defaultValue;
+       if (accessOrder)
+           afterNodeAccess(e);
+       return e.value;
+   }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() {
+        super.clear();
+        head = tail = null;
+    }
+
+    // Android-added: eldest(), for internal use in LRU caches
+    /**
+     * Returns the eldest entry in the map, or {@code null} if the map is empty.
+     * @hide
+     */
+    public Map.Entry<K, V> eldest() {
+        return head;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map should remove its eldest entry.
+     * This method is invoked by <tt>put</tt> and <tt>putAll</tt> after
+     * inserting a new entry into the map.  It provides the implementor
+     * with the opportunity to remove the eldest entry each time a new one
+     * is added.  This is useful if the map represents a cache: it allows
+     * the map to reduce memory consumption by deleting stale entries.
+     *
+     * <p>Sample use: this override will allow the map to grow up to 100
+     * entries and then delete the eldest entry each time a new entry is
+     * added, maintaining a steady state of 100 entries.
+     * <pre>
+     *     private static final int MAX_ENTRIES = 100;
+     *
+     *     protected boolean removeEldestEntry(Map.Entry eldest) {
+     *        return size() &gt; MAX_ENTRIES;
+     *     }
+     * </pre>
+     *
+     * <p>This method typically does not modify the map in any way,
+     * instead allowing the map to modify itself as directed by its
+     * return value.  It <i>is</i> permitted for this method to modify
+     * the map directly, but if it does so, it <i>must</i> return
+     * <tt>false</tt> (indicating that the map should not attempt any
+     * further modification).  The effects of returning <tt>true</tt>
+     * after modifying the map from within this method are unspecified.
+     *
+     * <p>This implementation merely returns <tt>false</tt> (so that this
+     * map acts like a normal map - the eldest element is never removed).
+     *
+     * @param    eldest The least recently inserted entry in the map, or if
+     *           this is an access-ordered map, the least recently accessed
+     *           entry.  This is the entry that will be removed it this
+     *           method returns <tt>true</tt>.  If the map was empty prior
+     *           to the <tt>put</tt> or <tt>putAll</tt> invocation resulting
+     *           in this invocation, this will be the entry that was just
+     *           inserted; in other words, if the map contains a single
+     *           entry, the eldest entry is also the newest.
+     * @return   <tt>true</tt> if the eldest entry should be removed
+     *           from the map; <tt>false</tt> if it should be retained.
+     */
+    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
+        return false;
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+     * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
+     * operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a set view of the keys contained in this map
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new LinkedKeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    final class LinkedKeySet extends AbstractSet<K> {
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<K> iterator() {
+            return new LinkedKeyIterator();
+        }
+        public final boolean contains(Object o) { return containsKey(o); }
+        public final boolean remove(Object key) {
+            return removeNode(hash(key), key, null, false, true) != null;
+        }
+        public final Spliterator<K> spliterator()  {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED |
+                                            Spliterator.DISTINCT);
+        }
+        public final void forEach(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            // Android-changed: Detect changes to modCount early.
+            for (LinkedHashMapEntry<K,V> e = head; (e != null && modCount == mc); e = e.after)
+                action.accept(e.key);
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own <tt>remove</tt> operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
+     * support the <tt>add</tt> or <tt>addAll</tt> operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a view of the values contained in this map
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new LinkedValues();
+            values = vs;
+        }
+        return vs;
+    }
+
+    final class LinkedValues extends AbstractCollection<V> {
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<V> iterator() {
+            return new LinkedValueIterator();
+        }
+        public final boolean contains(Object o) { return containsValue(o); }
+        public final Spliterator<V> spliterator() {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED);
+        }
+        public final void forEach(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            // Android-changed: Detect changes to modCount early.
+            for (LinkedHashMapEntry<K,V> e = head; (e != null && modCount == mc); e = e.after)
+                action.accept(e.value);
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation, or through the
+     * <tt>setValue</tt> operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
+     * <tt>clear</tt> operations.  It does not support the
+     * <tt>add</tt> or <tt>addAll</tt> operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a set view of the mappings contained in this map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es;
+        return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
+    }
+
+    final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<Map.Entry<K,V>> iterator() {
+            return new LinkedEntryIterator();
+        }
+        public final boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+            Object key = e.getKey();
+            Node<K,V> candidate = getNode(hash(key), key);
+            return candidate != null && candidate.equals(e);
+        }
+        public final boolean remove(Object o) {
+            if (o instanceof Map.Entry) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                Object key = e.getKey();
+                Object value = e.getValue();
+                return removeNode(hash(key), key, value, true, true) != null;
+            }
+            return false;
+        }
+        public final Spliterator<Map.Entry<K,V>> spliterator() {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED |
+                                            Spliterator.DISTINCT);
+        }
+        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            // Android-changed: Detect changes to modCount early.
+            for (LinkedHashMapEntry<K,V> e = head; (e != null && mc == modCount); e = e.after)
+                action.accept(e);
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    // Map overrides
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null)
+            throw new NullPointerException();
+        int mc = modCount;
+        // Android-changed: Detect changes to modCount early.
+        for (LinkedHashMapEntry<K,V> e = head; modCount == mc && e != null; e = e.after)
+            action.accept(e.key, e.value);
+        if (modCount != mc)
+            throw new ConcurrentModificationException();
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        if (function == null)
+            throw new NullPointerException();
+        int mc = modCount;
+        // Android-changed: Detect changes to modCount early.
+        for (LinkedHashMapEntry<K,V> e = head; modCount == mc && e != null; e = e.after)
+            e.value = function.apply(e.key, e.value);
+        if (modCount != mc)
+            throw new ConcurrentModificationException();
+    }
+
+    // Iterators
+
+    abstract class LinkedHashIterator {
+        LinkedHashMapEntry<K,V> next;
+        LinkedHashMapEntry<K,V> current;
+        int expectedModCount;
+
+        LinkedHashIterator() {
+            next = head;
+            expectedModCount = modCount;
+            current = null;
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        final LinkedHashMapEntry<K,V> nextNode() {
+            LinkedHashMapEntry<K,V> e = next;
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (e == null)
+                throw new NoSuchElementException();
+            current = e;
+            next = e.after;
+            return e;
+        }
+
+        public final void remove() {
+            Node<K,V> p = current;
+            if (p == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            current = null;
+            K key = p.key;
+            removeNode(hash(key), key, null, false, false);
+            expectedModCount = modCount;
+        }
+    }
+
+    final class LinkedKeyIterator extends LinkedHashIterator
+        implements Iterator<K> {
+        public final K next() { return nextNode().getKey(); }
+    }
+
+    final class LinkedValueIterator extends LinkedHashIterator
+        implements Iterator<V> {
+        public final V next() { return nextNode().value; }
+    }
+
+    final class LinkedEntryIterator extends LinkedHashIterator
+        implements Iterator<Map.Entry<K,V>> {
+        public final Map.Entry<K,V> next() { return nextNode(); }
+    }
+
+
+}
diff --git a/java/util/LinkedHashSet.java b/java/util/LinkedHashSet.java
new file mode 100644
index 0000000..08606cf
--- /dev/null
+++ b/java/util/LinkedHashSet.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * <p>Hash table and linked list implementation of the <tt>Set</tt> interface,
+ * with predictable iteration order.  This implementation differs from
+ * <tt>HashSet</tt> in that it maintains a doubly-linked list running through
+ * all of its entries.  This linked list defines the iteration ordering,
+ * which is the order in which elements were inserted into the set
+ * (<i>insertion-order</i>).  Note that insertion order is <i>not</i> affected
+ * if an element is <i>re-inserted</i> into the set.  (An element <tt>e</tt>
+ * is reinserted into a set <tt>s</tt> if <tt>s.add(e)</tt> is invoked when
+ * <tt>s.contains(e)</tt> would return <tt>true</tt> immediately prior to
+ * the invocation.)
+ *
+ * <p>This implementation spares its clients from the unspecified, generally
+ * chaotic ordering provided by {@link HashSet}, without incurring the
+ * increased cost associated with {@link TreeSet}.  It can be used to
+ * produce a copy of a set that has the same order as the original, regardless
+ * of the original set's implementation:
+ * <pre>
+ *     void foo(Set s) {
+ *         Set copy = new LinkedHashSet(s);
+ *         ...
+ *     }
+ * </pre>
+ * This technique is particularly useful if a module takes a set on input,
+ * copies it, and later returns results whose order is determined by that of
+ * the copy.  (Clients generally appreciate having things returned in the same
+ * order they were presented.)
+ *
+ * <p>This class provides all of the optional <tt>Set</tt> operations, and
+ * permits null elements.  Like <tt>HashSet</tt>, it provides constant-time
+ * performance for the basic operations (<tt>add</tt>, <tt>contains</tt> and
+ * <tt>remove</tt>), assuming the hash function disperses elements
+ * properly among the buckets.  Performance is likely to be just slightly
+ * below that of <tt>HashSet</tt>, due to the added expense of maintaining the
+ * linked list, with one exception: Iteration over a <tt>LinkedHashSet</tt>
+ * requires time proportional to the <i>size</i> of the set, regardless of
+ * its capacity.  Iteration over a <tt>HashSet</tt> is likely to be more
+ * expensive, requiring time proportional to its <i>capacity</i>.
+ *
+ * <p>A linked hash set has two parameters that affect its performance:
+ * <i>initial capacity</i> and <i>load factor</i>.  They are defined precisely
+ * as for <tt>HashSet</tt>.  Note, however, that the penalty for choosing an
+ * excessively high value for initial capacity is less severe for this class
+ * than for <tt>HashSet</tt>, as iteration times for this class are unaffected
+ * by capacity.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a linked hash set concurrently, and at least
+ * one of the threads modifies the set, it <em>must</em> be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the set.
+ *
+ * If no such object exists, the set should be "wrapped" using the
+ * {@link Collections#synchronizedSet Collections.synchronizedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the set: <pre>
+ *   Set s = Collections.synchronizedSet(new LinkedHashSet(...));</pre>
+ *
+ * <p>The iterators returned by this class's <tt>iterator</tt> method are
+ * <em>fail-fast</em>: if the set is modified at any time after the iterator
+ * is created, in any way except through the iterator's own <tt>remove</tt>
+ * method, 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 time in the future.
+ *
+ * <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.
+ * 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>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Set
+ * @see     HashSet
+ * @see     TreeSet
+ * @see     Hashtable
+ * @since   1.4
+ */
+
+public class LinkedHashSet<E>
+    extends HashSet<E>
+    implements Set<E>, Cloneable, java.io.Serializable {
+
+    private static final long serialVersionUID = -2851667679971038690L;
+
+    /**
+     * Constructs a new, empty linked hash set with the specified initial
+     * capacity and load factor.
+     *
+     * @param      initialCapacity the initial capacity of the linked hash set
+     * @param      loadFactor      the load factor of the linked hash set
+     * @throws     IllegalArgumentException  if the initial capacity is less
+     *               than zero, or if the load factor is nonpositive
+     */
+    public LinkedHashSet(int initialCapacity, float loadFactor) {
+        super(initialCapacity, loadFactor, true);
+    }
+
+    /**
+     * Constructs a new, empty linked hash set with the specified initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param   initialCapacity   the initial capacity of the LinkedHashSet
+     * @throws  IllegalArgumentException if the initial capacity is less
+     *              than zero
+     */
+    public LinkedHashSet(int initialCapacity) {
+        super(initialCapacity, .75f, true);
+    }
+
+    /**
+     * Constructs a new, empty linked hash set with the default initial
+     * capacity (16) and load factor (0.75).
+     */
+    public LinkedHashSet() {
+        super(16, .75f, true);
+    }
+
+    /**
+     * Constructs a new linked hash set with the same elements as the
+     * specified collection.  The linked hash set is created with an initial
+     * capacity sufficient to hold the elements in the specified collection
+     * and the default load factor (0.75).
+     *
+     * @param c  the collection whose elements are to be placed into
+     *           this set
+     * @throws NullPointerException if the specified collection is null
+     */
+    public LinkedHashSet(Collection<? extends E> c) {
+        super(Math.max(2*c.size(), 11), .75f, true);
+        addAll(c);
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@code Spliterator} over the elements in this set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#DISTINCT}, and {@code ORDERED}.  Implementations
+     * should document the reporting of additional characteristic values.
+     *
+     * @implNote
+     * The implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the set's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the set's iterator.
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
+    }
+}
diff --git a/java/util/LinkedList.annotated.java b/java/util/LinkedList.annotated.java
new file mode 100644
index 0000000..f85afd1
--- /dev/null
+++ b/java/util/LinkedList.annotated.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class LinkedList<E> extends java.util.AbstractSequentialList<E> implements java.util.List<E>, java.util.Deque<E>, java.lang.Cloneable, java.io.Serializable {
+
+public LinkedList() { throw new RuntimeException("Stub!"); }
+
+public LinkedList(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public E getFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E getLast() { throw new RuntimeException("Stub!"); }
+
[email protected] public E removeFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E removeLast() { throw new RuntimeException("Stub!"); }
+
+public void addFirst(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public void addLast(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected] public E get(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
[email protected] public E peek() { throw new RuntimeException("Stub!"); }
+
[email protected] public E element() { throw new RuntimeException("Stub!"); }
+
[email protected] public E poll() { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove() { throw new RuntimeException("Stub!"); }
+
+public boolean offer(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean offerFirst(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean offerLast(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public E peekFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E peekLast() { throw new RuntimeException("Stub!"); }
+
[email protected] public E pollFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E pollLast() { throw new RuntimeException("Stub!"); }
+
+public void push(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public E pop() { throw new RuntimeException("Stub!"); }
+
+public boolean removeFirstOccurrence(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean removeLastOccurrence(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> descendingIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/LinkedList.java b/java/util/LinkedList.java
new file mode 100644
index 0000000..60f4c41
--- /dev/null
+++ b/java/util/LinkedList.java
@@ -0,0 +1,1262 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * Doubly-linked list implementation of the {@code List} and {@code Deque}
+ * interfaces.  Implements all optional list operations, and permits all
+ * elements (including {@code null}).
+ *
+ * <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><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a linked list concurrently, and at least
+ * one of the threads modifies the list structurally, it <i>must</i> be
+ * synchronized externally.  (A structural modification is any operation
+ * that adds or deletes one or more elements; merely setting the value of
+ * an element is not a structural modification.)  This is typically
+ * accomplished by synchronizing on some object that naturally
+ * encapsulates the list.
+ *
+ * If no such object exists, the list should be "wrapped" using the
+ * {@link Collections#synchronizedList Collections.synchronizedList}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the list:<pre>
+ *   List list = Collections.synchronizedList(new LinkedList(...));</pre>
+ *
+ * <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 {@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
+ * time in the future.
+ *
+ * <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 {@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>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @see     List
+ * @see     ArrayList
+ * @since 1.2
+ * @param <E> the type of elements held in this collection
+ */
+
+public class LinkedList<E>
+    extends AbstractSequentialList<E>
+    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
+{
+    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() {
+    }
+
+    /**
+     * Constructs a list containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param  c the collection whose elements are to be placed into this list
+     * @throws NullPointerException if the specified collection is null
+     */
+    public LinkedList(Collection<? extends E> c) {
+        this();
+        addAll(c);
+    }
+
+    /**
+     * Links e as first element.
+     */
+    private void linkFirst(E e) {
+        final Node<E> f = first;
+        final Node<E> newNode = new Node<>(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<>(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<>(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() {
+        final Node<E> f = first;
+        if (f == null)
+            throw new NoSuchElementException();
+        return f.item;
+    }
+
+    /**
+     * Returns the last element in this list.
+     *
+     * @return the last element in this list
+     * @throws NoSuchElementException if this list is empty
+     */
+    public E getLast() {
+        final Node<E> l = last;
+        if (l == null)
+            throw new NoSuchElementException();
+        return l.item;
+    }
+
+    /**
+     * Removes and returns the first element from this list.
+     *
+     * @return the first element from this list
+     * @throws NoSuchElementException if this list is empty
+     */
+    public E removeFirst() {
+        final Node<E> f = first;
+        if (f == null)
+            throw new NoSuchElementException();
+        return unlinkFirst(f);
+    }
+
+    /**
+     * Removes and returns the last element from this list.
+     *
+     * @return the last element from this list
+     * @throws NoSuchElementException if this list is empty
+     */
+    public E removeLast() {
+        final Node<E> l = last;
+        if (l == null)
+            throw new NoSuchElementException();
+        return unlinkLast(l);
+    }
+
+    /**
+     * Inserts the specified element at the beginning of this list.
+     *
+     * @param e the element to add
+     */
+    public void addFirst(E e) {
+        linkFirst(e);
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @param e the element to add
+     */
+    public void addLast(E e) {
+        linkLast(e);
+    }
+
+    /**
+     * 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 {@code true} if this list contains the specified element
+     */
+    public boolean contains(Object o) {
+        return indexOf(o) != -1;
+    }
+
+    /**
+     * Returns the number of elements in this list.
+     *
+     * @return the number of elements in this list
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     */
+    public boolean add(E e) {
+        linkLast(e);
+        return true;
+    }
+
+    /**
+     * 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
+     * {@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 {@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 {@code true} if this list contained the specified element
+     */
+    public boolean remove(Object o) {
+        if (o == null) {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (x.item == null) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        } else {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (o.equals(x.item)) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this list, in the order that they are returned by the specified
+     * collection's iterator.  The behavior of this operation is undefined if
+     * the specified collection is modified while the operation is in
+     * progress.  (Note that this will occur if the specified collection is
+     * this list, and it's nonempty.)
+     *
+     * @param c collection containing elements to be added to this list
+     * @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) {
+        return addAll(size, c);
+    }
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list, starting at the specified position.  Shifts the element
+     * currently at that position (if any) and any subsequent elements to
+     * the right (increases their indices).  The new elements will appear
+     * in the list in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @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 {@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) {
+        checkPositionIndex(index);
+
+        Object[] a = c.toArray();
+        int numNew = a.length;
+        if (numNew == 0)
+            return false;
+
+        Node<E> pred, succ;
+        if (index == size) {
+            succ = null;
+            pred = last;
+        } else {
+            succ = node(index);
+            pred = succ.prev;
+        }
+
+        for (Object o : a) {
+            @SuppressWarnings("unchecked") E e = (E) o;
+            Node<E> newNode = new Node<>(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() {
+        // 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;
+        }
+        first = last = null;
+        size = 0;
+        modCount++;
+    }
+
+
+    // Positional Access Operations
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * @param index index of the element to return
+     * @return the element at the specified position in this list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        checkElementIndex(index);
+        return node(index).item;
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element.
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        checkElementIndex(index);
+        Node<E> x = node(index);
+        E oldVal = x.item;
+        x.item = element;
+        return oldVal;
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this list.
+     * Shifts the element currently at that position (if any) and any
+     * subsequent elements to the right (adds one to their indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        checkPositionIndex(index);
+
+        if (index == size)
+            linkLast(element);
+        else
+            linkBefore(element, node(index));
+    }
+
+    /**
+     * Removes the element at the specified position in this list.  Shifts any
+     * subsequent elements to the left (subtracts one from their indices).
+     * Returns the element that was removed from the list.
+     *
+     * @param index the index of the element to be removed
+     * @return the element previously at the specified position
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E remove(int index) {
+        checkElementIndex(index);
+        return unlink(node(index));
+    }
+
+    /**
+     * Tells if the argument is the index of an existing element.
+     */
+    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 {@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.
+     *
+     * @param o element to search for
+     * @return the index of the first occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     */
+    public int indexOf(Object o) {
+        int index = 0;
+        if (o == null) {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (x.item == null)
+                    return index;
+                index++;
+            }
+        } else {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (o.equals(x.item))
+                    return index;
+                index++;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * 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 {@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.
+     *
+     * @param o element to search for
+     * @return the index of the last occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     */
+    public int lastIndexOf(Object o) {
+        int index = size;
+        if (o == null) {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                index--;
+                if (x.item == null)
+                    return index;
+            }
+        } else {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                index--;
+                if (o.equals(x.item))
+                    return index;
+            }
+        }
+        return -1;
+    }
+
+    // Queue operations.
+
+    /**
+     * Retrieves, but does not remove, 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 peek() {
+        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
+     */
+    public E element() {
+        return getFirst();
+    }
+
+    /**
+     * 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() {
+        final Node<E> f = first;
+        return (f == null) ? null : unlinkFirst(f);
+    }
+
+    /**
+     * Retrieves and removes the head (first element) of this list.
+     *
+     * @return the head of this list
+     * @throws NoSuchElementException if this list is empty
+     * @since 1.5
+     */
+    public E remove() {
+        return removeFirst();
+    }
+
+    /**
+     * Adds the specified element as the tail (last element) of this list.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @since 1.5
+     */
+    public boolean offer(E e) {
+        return add(e);
+    }
+
+    // Deque operations
+    /**
+     * Inserts the specified element at the front of this list.
+     *
+     * @param e the element to insert
+     * @return {@code true} (as specified by {@link Deque#offerFirst})
+     * @since 1.6
+     */
+    public boolean offerFirst(E e) {
+        addFirst(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this list.
+     *
+     * @param e the element to insert
+     * @return {@code true} (as specified by {@link Deque#offerLast})
+     * @since 1.6
+     */
+    public boolean offerLast(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * Retrieves, but does not remove, the first element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the first element of this list, or {@code null}
+     *         if this list is empty
+     * @since 1.6
+     */
+    public E peekFirst() {
+        final Node<E> f = first;
+        return (f == null) ? null : f.item;
+     }
+
+    /**
+     * Retrieves, but does not remove, the last element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the last element of this list, or {@code null}
+     *         if this list is empty
+     * @since 1.6
+     */
+    public E peekLast() {
+        final Node<E> l = last;
+        return (l == null) ? null : l.item;
+    }
+
+    /**
+     * Retrieves and removes the first element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the first element of this list, or {@code null} if
+     *     this list is empty
+     * @since 1.6
+     */
+    public E pollFirst() {
+        final Node<E> f = first;
+        return (f == null) ? null : unlinkFirst(f);
+    }
+
+    /**
+     * Retrieves and removes the last element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the last element of this list, or {@code null} if
+     *     this list is empty
+     * @since 1.6
+     */
+    public E pollLast() {
+        final Node<E> l = last;
+        return (l == null) ? null : unlinkLast(l);
+    }
+
+    /**
+     * Pushes an element onto the stack represented by this list.  In other
+     * words, inserts the element at the front of this list.
+     *
+     * <p>This method is equivalent to {@link #addFirst}.
+     *
+     * @param e the element to push
+     * @since 1.6
+     */
+    public void push(E e) {
+        addFirst(e);
+    }
+
+    /**
+     * Pops an element from the stack represented by this list.  In other
+     * words, removes and returns the first element of this list.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the element at the front of this list (which is the top
+     *         of the stack represented by this list)
+     * @throws NoSuchElementException if this list is empty
+     * @since 1.6
+     */
+    public E pop() {
+        return removeFirst();
+    }
+
+    /**
+     * Removes the first occurrence of the specified element in this
+     * list (when traversing the list from head to tail).  If the list
+     * does not contain the element, it is unchanged.
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if the list contained the specified element
+     * @since 1.6
+     */
+    public boolean removeFirstOccurrence(Object o) {
+        return remove(o);
+    }
+
+    /**
+     * Removes the last occurrence of the specified element in this
+     * list (when traversing the list from head to tail).  If the list
+     * does not contain the element, it is unchanged.
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if the list contained the specified element
+     * @since 1.6
+     */
+    public boolean removeLastOccurrence(Object o) {
+        if (o == null) {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                if (x.item == null) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        } else {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                if (o.equals(x.item)) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 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 {@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 {@code remove} or {@code add}
+     * methods, the list-iterator will throw a
+     * {@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 {@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 Node<E> lastReturned;
+        private Node<E> next;
+        private int nextIndex;
+        private int expectedModCount = modCount;
+
+        ListItr(int index) {
+            // assert isPositionIndex(index);
+            next = (index == size) ? null : node(index);
+            nextIndex = index;
+        }
+
+        public boolean hasNext() {
+            return nextIndex < size;
+        }
+
+        public E next() {
+            checkForComodification();
+            if (!hasNext())
+                throw new NoSuchElementException();
+
+            lastReturned = next;
+            next = next.next;
+            nextIndex++;
+            return lastReturned.item;
+        }
+
+        public boolean hasPrevious() {
+            return nextIndex > 0;
+        }
+
+        public E previous() {
+            checkForComodification();
+            if (!hasPrevious())
+                throw new NoSuchElementException();
+
+            lastReturned = next = (next == null) ? last : next.prev;
+            nextIndex--;
+            return lastReturned.item;
+        }
+
+        public int nextIndex() {
+            return nextIndex;
+        }
+
+        public int previousIndex() {
+            return nextIndex - 1;
+        }
+
+        public void remove() {
+            checkForComodification();
+            if (lastReturned == null)
+                throw new IllegalStateException();
+
+            Node<E> lastNext = lastReturned.next;
+            unlink(lastReturned);
+            if (next == lastReturned)
+                next = lastNext;
+            else
+                nextIndex--;
+            lastReturned = null;
+            expectedModCount++;
+        }
+
+        public void set(E e) {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            checkForComodification();
+            lastReturned.item = e;
+        }
+
+        public void add(E e) {
+            checkForComodification();
+            lastReturned = null;
+            if (next == null)
+                linkLast(e);
+            else
+                linkBefore(e, next);
+            nextIndex++;
+            expectedModCount++;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            while (modCount == expectedModCount && nextIndex < size) {
+                action.accept(next.item);
+                lastReturned = next;
+                next = next.next;
+                nextIndex++;
+            }
+            checkForComodification();
+        }
+
+        final void checkForComodification() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    private static class Node<E> {
+        E item;
+        Node<E> next;
+        Node<E> prev;
+
+        Node(Node<E> prev, E element, Node<E> next) {
+            this.item = element;
+            this.next = next;
+            this.prev = prev;
+        }
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Iterator<E> descendingIterator() {
+        return new DescendingIterator();
+    }
+
+    /**
+     * 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();
+        }
+        public E next() {
+            return itr.previous();
+        }
+        public void remove() {
+            itr.remove();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private LinkedList<E> superClone() {
+        try {
+            return (LinkedList<E>) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * 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.first = clone.last = null;
+        clone.size = 0;
+        clone.modCount = 0;
+
+        // Initialize clone with our elements
+        for (Node<E> x = first; x != null; x = x.next)
+            clone.add(x.item);
+
+        return clone;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this list
+     *         in proper sequence
+     */
+    public Object[] toArray() {
+        Object[] result = new Object[size];
+        int i = 0;
+        for (Node<E> x = first; x != null; x = x.next)
+            result[i++] = x.item;
+        return result;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list in
+     * proper sequence (from first to last element); the runtime type of
+     * the returned array is that of the specified array.  If the list fits
+     * in the specified array, it is returned therein.  Otherwise, a new
+     * array is allocated with the runtime type of the specified array and
+     * the size of this list.
+     *
+     * <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 {@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.)
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <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 {@code String}:
+     *
+     * <pre>
+     *     String[] y = x.toArray(new String[0]);</pre>
+     *
+     * 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
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of the list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         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 (Node<E> x = first; x != null; x = x.next)
+            result[i++] = x.item;
+
+        if (a.length > size)
+            a[size] = null;
+
+        return a;
+    }
+
+    private static final long serialVersionUID = 876323262645176354L;
+
+    /**
+     * 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
+     *             elements (each an Object) in the proper order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out any hidden serialization magic
+        s.defaultWriteObject();
+
+        // Write out size
+        s.writeInt(size);
+
+        // Write out all elements in the proper order.
+        for (Node<E> x = first; x != null; x = x.next)
+            s.writeObject(x.item);
+    }
+
+    /**
+     * 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
+        s.defaultReadObject();
+
+        // Read in size
+        int size = s.readInt();
+
+        // Read in all elements in the proper order.
+        for (int i = 0; i < size; i++)
+            linkLast((E)s.readObject());
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#ORDERED}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @implNote
+     * The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED}
+     * and implements {@code trySplit} to permit limited parallelism..
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new LLSpliterator<E>(this, -1, 0);
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class LLSpliterator<E> implements Spliterator<E> {
+        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final LinkedList<E> list; // null OK unless traversed
+        Node<E> current;      // current node; null until initialized
+        int est;              // size estimate; -1 until first needed
+        int expectedModCount; // initialized when est set
+        int batch;            // batch size for splits
+
+        LLSpliterator(LinkedList<E> list, int est, int expectedModCount) {
+            this.list = list;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getEst() {
+            int s; // force initialization
+            final LinkedList<E> lst;
+            if ((s = est) < 0) {
+                if ((lst = list) == null)
+                    s = est = 0;
+                else {
+                    expectedModCount = lst.modCount;
+                    current = lst.first;
+                    s = est = lst.size;
+                }
+            }
+            return s;
+        }
+
+        public long estimateSize() { return (long) getEst(); }
+
+        public Spliterator<E> trySplit() {
+            Node<E> p;
+            int s = getEst();
+            if (s > 1 && (p = current) != null) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                Object[] a = new Object[n];
+                int j = 0;
+                do { a[j++] = p.item; } while ((p = p.next) != null && j < n);
+                current = p;
+                batch = j;
+                est = s - j;
+                return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Node<E> p; int n;
+            if (action == null) throw new NullPointerException();
+            if ((n = getEst()) > 0 && (p = current) != null) {
+                current = null;
+                est = 0;
+                do {
+                    E e = p.item;
+                    p = p.next;
+                    action.accept(e);
+                } while (p != null && --n > 0);
+            }
+            if (list.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            if (getEst() > 0 && (p = current) != null) {
+                --est;
+                E e = p.item;
+                current = p.next;
+                action.accept(e);
+                if (list.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                return true;
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+    }
+
+}
diff --git a/java/util/List.annotated.java b/java/util/List.annotated.java
new file mode 100644
index 0000000..2ef4a6f
--- /dev/null
+++ b/java/util/List.annotated.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface List<E> extends java.util.Collection<E> {
+
+public int size();
+
+public boolean isEmpty();
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o);
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator();
+
+public [email protected] Object @libcore.util.NonNull [] toArray();
+
+// TODO: Make param and return types @Nullable T @NonNull [] once metalava supports TYPE_USE.
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a);
+
+public boolean add(@libcore.util.NullFromTypeParam E e);
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o);
+
+public boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c);
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c);
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public default void replaceAll(@libcore.util.NonNull java.util.function.UnaryOperator<@libcore.util.NullFromTypeParam E> operator) { throw new RuntimeException("Stub!"); }
+
+public default void sort(@libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void clear();
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o);
+
+public int hashCode();
+
[email protected] public E get(int index);
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element);
+
+public void add(int index, @libcore.util.NullFromTypeParam E element);
+
[email protected] public E remove(int index);
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o);
+
+public int lastIndexOf(@libcore.util.Nullable java.lang.Object o);
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator();
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index);
+
[email protected] public java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex);
+
[email protected] public default java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9, @libcore.util.NonNull E e10) { throw new RuntimeException("Stub!"); }
+
[email protected]
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(E @libcore.util.NonNull ... elements) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/List.java b/java/util/List.java
new file mode 100644
index 0000000..1b9deb3
--- /dev/null
+++ b/java/util/List.java
@@ -0,0 +1,1061 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.UnaryOperator;
+
+// Android-removed: removed link to collections framework docs
+/**
+ * An ordered collection (also known as a <i>sequence</i>).  The user of this
+ * interface has precise control over where in the list each element is
+ * inserted.  The user can access elements by their integer index (position in
+ * the list), and search for elements in the list.<p>
+ *
+ * Unlike sets, lists typically allow duplicate elements.  More formally,
+ * lists typically allow pairs of elements {@code e1} and {@code e2}
+ * such that {@code e1.equals(e2)}, and they typically allow multiple
+ * null elements if they allow null elements at all.  It is not inconceivable
+ * that someone might wish to implement a list that prohibits duplicates, by
+ * throwing runtime exceptions when the user attempts to insert them, but we
+ * expect this usage to be rare.<p>
+ *
+ * The {@code List} interface places additional stipulations, beyond those
+ * specified in the {@code Collection} interface, on the contracts of the
+ * {@code iterator}, {@code add}, {@code remove}, {@code equals}, and
+ * {@code hashCode} methods.  Declarations for other inherited methods are
+ * also included here for convenience.<p>
+ *
+ * The {@code List} interface provides four methods for positional (indexed)
+ * access to list elements.  Lists (like Java arrays) are zero based.  Note
+ * that these operations may execute in time proportional to the index value
+ * for some implementations (the {@code LinkedList} class, for
+ * example). Thus, iterating over the elements in a list is typically
+ * preferable to indexing through it if the caller does not know the
+ * implementation.<p>
+ *
+ * The {@code List} interface provides a special iterator, called a
+ * {@code ListIterator}, that allows element insertion and replacement, and
+ * bidirectional access in addition to the normal operations that the
+ * {@code Iterator} interface provides.  A method is provided to obtain a
+ * list iterator that starts at a specified position in the list.<p>
+ *
+ * The {@code List} interface provides two methods to search for a specified
+ * object.  From a performance standpoint, these methods should be used with
+ * caution.  In many implementations they will perform costly linear
+ * searches.<p>
+ *
+ * The {@code List} interface provides two methods to efficiently insert and
+ * remove multiple elements at an arbitrary point in the list.<p>
+ *
+ * Note: While it is permissible for lists to contain themselves as elements,
+ * extreme caution is advised: the {@code equals} and {@code hashCode}
+ * methods are no longer well defined on such a list.
+ *
+ * <p>Some list implementations have restrictions on the elements that
+ * they may contain.  For example, some implementations prohibit null elements,
+ * and some have restrictions on the types of their elements.  Attempting to
+ * add an ineligible element throws an unchecked exception, typically
+ * {@code NullPointerException} or {@code ClassCastException}.  Attempting
+ * to query the presence of an ineligible element may throw an exception,
+ * or it may simply return false; some implementations will exhibit the former
+ * behavior and some will exhibit the latter.  More generally, attempting an
+ * operation on an ineligible element whose completion would not result in
+ * the insertion of an ineligible element into the list may throw an
+ * exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <h2><a id="immutable">Immutable List Static Factory Methods</a></h2>
+ * <p>The {@link List#of(Object...) List.of()} static factory methods
+ * provide a convenient way to create immutable lists. The {@code List}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Elements cannot be added, removed,
+ * or replaced. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained elements are themselves mutable,
+ * this may cause the List's contents to appear to change.
+ * <li>They disallow {@code null} elements. Attempts to create them with
+ * {@code null} elements result in {@code NullPointerException}.
+ * <li>They are serializable if all elements are serializable.
+ * <li>The order of elements in the list is the same as the order of the
+ * provided arguments, or of the elements in the provided array.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
+ * @param <E> the type of elements in this list
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see Set
+ * @see ArrayList
+ * @see LinkedList
+ * @see Vector
+ * @see Arrays#asList(Object[])
+ * @see Collections#nCopies(int, Object)
+ * @see Collections#EMPTY_LIST
+ * @see AbstractList
+ * @see AbstractSequentialList
+ * @since 1.2
+ */
+
+public interface List<E> extends Collection<E> {
+    // Query Operations
+
+    /**
+     * Returns the number of elements in this list.  If this list contains
+     * more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @return the number of elements in this list
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this list contains no elements.
+     *
+     * @return {@code true} if this list contains no elements
+     */
+    boolean isEmpty();
+
+    /**
+     * 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
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this list is to be tested
+     * @return {@code true} if this list contains the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an array containing all of the elements in this list in proper
+     * sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must
+     * allocate a new array even if this list is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this list in proper
+     *         sequence
+     * @see Arrays#asList(Object[])
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing all of the elements in this list in
+     * proper sequence (from first to last element); the runtime type of
+     * the returned array is that of the specified array.  If the list fits
+     * in the specified array, it is returned therein.  Otherwise, a new
+     * array is allocated with the runtime type of the specified array and
+     * the size of this list.
+     *
+     * <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 {@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.)
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <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 {@code String}:
+     *
+     * <pre>{@code
+     *     String[] y = x.toArray(new String[0]);
+     * }</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of this list are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of this list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this list
+     * @throws NullPointerException if the specified array is null
+     */
+    <T> T[] toArray(T[] a);
+
+
+    // Modification Operations
+
+    /**
+     * Appends the specified element to the end of this list (optional
+     * operation).
+     *
+     * <p>Lists that support this operation may place limitations on what
+     * elements may be added to this list.  In particular, some
+     * lists will refuse to add null elements, and others will impose
+     * restrictions on the type of elements that may be added.  List
+     * classes should clearly specify in their documentation any restrictions
+     * on what elements may be added.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this list
+     */
+    boolean add(E e);
+
+    /**
+     * Removes the first occurrence of the specified element from this list,
+     * if it is present (optional operation).  If this list does not contain
+     * the element, it is unchanged.  More formally, removes the element with
+     * the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))}
+     * (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 {@code true} if this list contained the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this list
+     */
+    boolean remove(Object o);
+
+
+    // Bulk Modification Operations
+
+    /**
+     * Returns {@code true} if this list contains all of the elements of the
+     * specified collection.
+     *
+     * @param  c collection to be checked for containment in this list
+     * @return {@code true} if this list contains all of the elements of the
+     *         specified collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in the specified collection are incompatible with this
+     *         list
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this list does not permit null
+     *         elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #contains(Object)
+     */
+    boolean containsAll(Collection<?> c);
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this list, in the order that they are returned by the specified
+     * collection's iterator (optional operation).  The behavior of this
+     * operation is undefined if the specified collection is modified while
+     * the operation is in progress.  (Note that this will occur if the
+     * specified collection is this list, and it's nonempty.)
+     *
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code addAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this list
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this list does not permit null
+     *         elements, or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this list
+     * @see #add(Object)
+     */
+    boolean addAll(Collection<? extends E> c);
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list at the specified position (optional operation).  Shifts the
+     * element currently at that position (if any) and any subsequent
+     * elements to the right (increases their indices).  The new elements
+     * will appear in this list in the order that they are returned by the
+     * specified collection's iterator.  The behavior of this operation is
+     * undefined if the specified collection is modified while the
+     * operation is in progress.  (Note that this will occur if the specified
+     * collection is this list, and it's nonempty.)
+     *
+     * @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 {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code addAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this list
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this list does not permit null
+     *         elements, or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    boolean addAll(int index, Collection<? extends E> c);
+
+    /**
+     * Removes from this list all of its elements that are contained in the
+     * specified collection (optional operation).
+     *
+     * @param c collection containing elements to be removed from this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code removeAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean removeAll(Collection<?> c);
+
+    /**
+     * Retains only the elements in this list that are contained in the
+     * specified collection (optional operation).  In other words, removes
+     * from this list all of its elements that are not contained in the
+     * specified collection.
+     *
+     * @param c collection containing elements to be retained in this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code retainAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean retainAll(Collection<?> c);
+
+    /**
+     * Replaces each element of this list with the result of applying the
+     * operator to that element.  Errors or runtime exceptions thrown by
+     * the operator are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code list}:
+     * <pre>{@code
+     *     final ListIterator<E> li = list.listIterator();
+     *     while (li.hasNext()) {
+     *         li.set(operator.apply(li.next()));
+     *     }
+     * }</pre>
+     *
+     * If the list's list-iterator does not support the {@code set} operation
+     * then an {@code UnsupportedOperationException} will be thrown when
+     * replacing the first element.
+     *
+     * @param operator the operator to apply to each element
+     * @throws UnsupportedOperationException if this list is unmodifiable.
+     *         Implementations may throw this exception if an element
+     *         cannot be replaced or if, in general, modification is not
+     *         supported
+     * @throws NullPointerException if the specified operator is null or
+     *         if the operator result is a null value and this list does
+     *         not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default void replaceAll(UnaryOperator<E> operator) {
+        Objects.requireNonNull(operator);
+        final ListIterator<E> li = this.listIterator();
+        while (li.hasNext()) {
+            li.set(operator.apply(li.next()));
+        }
+    }
+
+    // Android-added: List.sort() vs. Collections.sort() app compat.
+    // Added a warning in the documentation.
+    // Collections.sort() calls List.sort() for apps targeting API version >= 26
+    // (Android Oreo) but the other way around for app targeting <= 25 (Nougat).
+    /**
+     * Sorts this list according to the order induced by the specified
+     * {@link Comparator}.
+     *
+     * <p>All elements in this list must be <i>mutually comparable</i> using the
+     * specified comparator (that is, {@code c.compare(e1, e2)} must not throw
+     * a {@code ClassCastException} for any elements {@code e1} and {@code e2}
+     * in the list).
+     *
+     * <p>If the specified comparator is {@code null} then all elements in this
+     * list must implement the {@link Comparable} interface and the elements'
+     * {@linkplain Comparable natural ordering} should be used.
+     *
+     * <p>This list must be modifiable, but need not be resizable.
+     *
+     * <p>For apps running on and targeting Android versions greater than
+     * Nougat (API level {@code > 25}), {@link Collections#sort(List)}
+     * delegates to this method. Such apps must not call
+     * {@link Collections#sort(List)} from this method. Instead, prefer
+     * not overriding this method at all. If you must override it, consider
+     * this implementation:
+     * <pre>
+     * &#064;Override
+     * public void sort(Comparator&lt;? super E&gt; c) {
+     *   Object[] elements = toArray();
+     *   Arrays.sort(elements, c);
+     *   ListIterator&lt;E&gt; iterator = (ListIterator&lt;Object&gt;) listIterator();
+     *   for (Object element : elements) {
+     *     iterator.next();
+     *     iterator.set((E) element);
+     *   }
+     * }
+     * </pre>
+     *
+     * @implSpec
+     * The default implementation obtains an array containing all elements in
+     * this list, sorts the array, and iterates over this list resetting each
+     * element from the corresponding position in the array. (This avoids the
+     * n<sup>2</sup> log(n) performance that would result from attempting
+     * to sort a linked list in place.)
+     *
+     * @implNote
+     * This implementation is a stable, adaptive, iterative mergesort that
+     * requires far fewer than n lg(n) comparisons when the input array is
+     * partially sorted, while offering the performance of a traditional
+     * mergesort when the input array is randomly ordered.  If the input array
+     * is nearly sorted, the implementation requires approximately n
+     * comparisons.  Temporary storage requirements vary from a small constant
+     * for nearly sorted input arrays to n/2 object references for randomly
+     * ordered input arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param c the {@code Comparator} used to compare list elements.
+     *          A {@code null} value indicates that the elements'
+     *          {@linkplain Comparable natural ordering} should be used
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator
+     * @throws UnsupportedOperationException if the list's list-iterator does
+     *         not support the {@code set} operation
+     * @throws IllegalArgumentException
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     *         if the comparator is found to violate the {@link Comparator}
+     *         contract
+     * @since 1.8
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    default void sort(Comparator<? super E> c) {
+        Object[] a = this.toArray();
+        Arrays.sort(a, (Comparator) c);
+        ListIterator<E> i = this.listIterator();
+        for (Object e : a) {
+            i.next();
+            i.set((E) e);
+        }
+    }
+
+    /**
+     * Removes all of the elements from this list (optional operation).
+     * The list will be empty after this call returns.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} operation
+     *         is not supported by this list
+     */
+    void clear();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this list for equality.  Returns
+     * {@code true} if and only if the specified object is also a list, both
+     * lists have the same size, and all corresponding pairs of elements in
+     * the two lists are <i>equal</i>.  (Two elements {@code e1} and
+     * {@code e2} are <i>equal</i> if {@code Objects.equals(e1, e2)}.)
+     * In other words, two lists are defined to be
+     * equal if they contain the same elements in the same order.  This
+     * definition ensures that the equals method works properly across
+     * different implementations of the {@code List} interface.
+     *
+     * @param o the object to be compared for equality with this list
+     * @return {@code true} if the specified object is equal to this list
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this list.  The hash code of a list
+     * is defined to be the result of the following calculation:
+     * <pre>{@code
+     *     int hashCode = 1;
+     *     for (E e : list)
+     *         hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
+     * }</pre>
+     * This ensures that {@code list1.equals(list2)} implies that
+     * {@code list1.hashCode()==list2.hashCode()} for any two lists,
+     * {@code list1} and {@code list2}, as required by the general
+     * contract of {@link Object#hashCode}.
+     *
+     * @return the hash code value for this list
+     * @see Object#equals(Object)
+     * @see #equals(Object)
+     */
+    int hashCode();
+
+
+    // Positional Access Operations
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * @param index index of the element to return
+     * @return the element at the specified position in this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    E get(int index);
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element (optional operation).
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws UnsupportedOperationException if the {@code set} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and
+     *         this list does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    E set(int index, E element);
+
+    /**
+     * Inserts the specified element at the specified position in this list
+     * (optional operation).  Shifts the element currently at that position
+     * (if any) and any subsequent elements to the right (adds one to their
+     * indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and
+     *         this list does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    void add(int index, E element);
+
+    /**
+     * Removes the element at the specified position in this list (optional
+     * operation).  Shifts any subsequent elements to the left (subtracts one
+     * from their indices).  Returns the element that was removed from the
+     * list.
+     *
+     * @param index the index of the element to be removed
+     * @return the element previously at the specified position
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    E remove(int index);
+
+
+    // 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 {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the first occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    int indexOf(Object o);
+
+    /**
+     * 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 {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the last occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    int lastIndexOf(Object o);
+
+
+    // List Iterators
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * @return a list iterator over the elements in this list (in proper
+     *         sequence)
+     */
+    ListIterator<E> listIterator();
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence), starting at the specified position in the list.
+     * The specified index indicates the first element that would be
+     * returned by an initial call to {@link ListIterator#next next}.
+     * An initial call to {@link ListIterator#previous previous} would
+     * return the element with the specified index minus one.
+     *
+     * @param index index of the first element to be returned from the
+     *        list iterator (by a call to {@link ListIterator#next next})
+     * @return a list iterator over the elements in this list (in proper
+     *         sequence), starting at the specified position in the list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    ListIterator<E> listIterator(int index);
+
+    // View
+
+    /**
+     * Returns a view of the portion of this list between the specified
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
+     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
+     * empty.)  The returned list is backed by this list, so non-structural
+     * changes in the returned list are reflected in this list, and vice-versa.
+     * The returned list supports all of the optional list operations supported
+     * by this list.<p>
+     *
+     * This method eliminates the need for explicit range operations (of
+     * the sort that commonly exist for arrays).  Any operation that expects
+     * a list can be used as a range operation by passing a subList view
+     * instead of a whole list.  For example, the following idiom
+     * removes a range of elements from a list:
+     * <pre>{@code
+     *      list.subList(from, to).clear();
+     * }</pre>
+     * Similar idioms may be constructed for {@code indexOf} and
+     * {@code lastIndexOf}, and all of the algorithms in the
+     * {@code Collections} class can be applied to a subList.<p>
+     *
+     * The semantics of the list returned by this method become undefined if
+     * the backing list (i.e., this list) is <i>structurally modified</i> in
+     * any way other than via the returned list.  (Structural modifications are
+     * those that change the size of this list, or otherwise perturb it in such
+     * a fashion that iterations in progress may yield incorrect results.)
+     *
+     * @param fromIndex low endpoint (inclusive) of the subList
+     * @param toIndex high endpoint (exclusive) of the subList
+     * @return a view of the specified range within this list
+     * @throws IndexOutOfBoundsException for an illegal endpoint index value
+     *         ({@code fromIndex < 0 || toIndex > size ||
+     *         fromIndex > toIndex})
+     */
+    List<E> subList(int fromIndex, int toIndex);
+
+    /**
+     * Creates a {@link Spliterator} over the elements in this list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#ORDERED}.  Implementations should document the
+     * reporting of additional characteristic values.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * spliterator as follows:
+     * <ul>
+     * <li>If the list is an instance of {@link RandomAccess} then the default
+     *     implementation creates a spliterator that traverses elements by
+     *     invoking the method {@link List#get}.  If such invocation results or
+     *     would result in an {@code IndexOutOfBoundsException} then the
+     *     spliterator will <em>fail-fast</em> and throw a
+     *     {@code ConcurrentModificationException}.
+     *     If the list is also an instance of {@link AbstractList} then the
+     *     spliterator will use the list's {@link AbstractList#modCount modCount}
+     *     field to provide additional <em>fail-fast</em> behavior.
+     * <li>Otherwise, the default implementation creates a spliterator from the
+     *     list's {@code Iterator}.  The spliterator inherits the
+     *     <em>fail-fast</em> of the list's iterator.
+     * </ul>
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        if (this instanceof RandomAccess) {
+            return new AbstractList.RandomAccessSpliterator<>(this);
+        } else {
+            return Spliterators.spliterator(this, Spliterator.ORDERED);
+        }
+    }
+
+    /**
+     * Returns an immutable list containing zero elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @return an empty {@code List}
+     *
+     * @since 9
+     */
+    static <E> List<E> of() {
+        return ImmutableCollections.List0.instance();
+    }
+
+    /**
+     * Returns an immutable list containing one element.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the single element
+     * @return a {@code List} containing the specified element
+     * @throws NullPointerException if the element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1) {
+        return new ImmutableCollections.List1<>(e1);
+    }
+
+    /**
+     * Returns an immutable list containing two elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2) {
+        return new ImmutableCollections.List2<>(e1, e2);
+    }
+
+    /**
+     * Returns an immutable list containing three elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3);
+    }
+
+    /**
+     * Returns an immutable list containing four elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4);
+    }
+
+    /**
+     * Returns an immutable list containing five elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5);
+    }
+
+    /**
+     * Returns an immutable list containing six elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6);
+    }
+
+    /**
+     * Returns an immutable list containing seven elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7);
+    }
+
+    /**
+     * Returns an immutable list containing eight elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8);
+    }
+
+    /**
+     * Returns an immutable list containing nine elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8, e9);
+    }
+
+    /**
+     * Returns an immutable list containing ten elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @param e10 the tenth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8, e9, e10);
+    }
+
+    /**
+     * Returns an immutable list containing an arbitrary number of elements.
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * This method also accepts a single array as an argument. The element type of
+     * the resulting list will be the component type of the array, and the size of
+     * the list will be equal to the length of the array. To create a list with
+     * a single element that is an array, do the following:
+     *
+     * <pre>{@code
+     *     String[] array = ... ;
+     *     List<String[]> list = List.<String[]>of(array);
+     * }</pre>
+     *
+     * This will cause the {@link List#of(Object) List.of(E)} method
+     * to be invoked instead.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param elements the elements to be contained in the list
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null} or if the array is {@code null}
+     *
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <E> List<E> of(E... elements) {
+        switch (elements.length) { // implicit null check of elements
+            case 0:
+                return ImmutableCollections.List0.instance();
+            case 1:
+                return new ImmutableCollections.List1<>(elements[0]);
+            case 2:
+                return new ImmutableCollections.List2<>(elements[0], elements[1]);
+            default:
+                return new ImmutableCollections.ListN<>(elements);
+        }
+    }
+}
diff --git a/java/util/ListIterator.java b/java/util/ListIterator.java
new file mode 100644
index 0000000..6ad98fe
--- /dev/null
+++ b/java/util/ListIterator.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * An iterator for lists that allows the programmer
+ * to traverse the list in either direction, modify
+ * the list during iteration, and obtain the iterator's
+ * current position in the list. A {@code ListIterator}
+ * has no current element; its <I>cursor position</I> always
+ * lies between the element that would be returned by a call
+ * to {@code previous()} and the element that would be
+ * returned by a call to {@code next()}.
+ * An iterator for a list of length {@code n} has {@code n+1} possible
+ * cursor positions, as illustrated by the carets ({@code ^}) below:
+ * <PRE>
+ *                      Element(0)   Element(1)   Element(2)   ... Element(n-1)
+ * cursor positions:  ^            ^            ^            ^                  ^
+ * </PRE>
+ * Note that the {@link #remove} and {@link #set(Object)} methods are
+ * <i>not</i> defined in terms of the cursor position;  they are defined to
+ * operate on the last element returned by a call to {@link #next} or
+ * {@link #previous()}.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @see Collection
+ * @see List
+ * @see Iterator
+ * @see Enumeration
+ * @see List#listIterator()
+ * @since   1.2
+ */
+public interface ListIterator<E> extends Iterator<E> {
+    // Query Operations
+
+    /**
+     * Returns {@code true} if this list iterator has more elements when
+     * traversing the list in the forward direction. (In other words,
+     * returns {@code true} if {@link #next} would return an element rather
+     * than throwing an exception.)
+     *
+     * @return {@code true} if the list iterator has more elements when
+     *         traversing the list in the forward direction
+     */
+    boolean hasNext();
+
+    /**
+     * Returns the next element in the list and advances the cursor position.
+     * This method may be called repeatedly to iterate through the list,
+     * or intermixed with calls to {@link #previous} to go back and forth.
+     * (Note that alternating calls to {@code next} and {@code previous}
+     * will return the same element repeatedly.)
+     *
+     * @return the next element in the list
+     * @throws NoSuchElementException if the iteration has no next element
+     */
+    E next();
+
+    /**
+     * Returns {@code true} if this list iterator has more elements when
+     * traversing the list in the reverse direction.  (In other words,
+     * returns {@code true} if {@link #previous} would return an element
+     * rather than throwing an exception.)
+     *
+     * @return {@code true} if the list iterator has more elements when
+     *         traversing the list in the reverse direction
+     */
+    boolean hasPrevious();
+
+    /**
+     * Returns the previous element in the list and moves the cursor
+     * position backwards.  This method may be called repeatedly to
+     * iterate through the list backwards, or intermixed with calls to
+     * {@link #next} to go back and forth.  (Note that alternating calls
+     * to {@code next} and {@code previous} will return the same
+     * element repeatedly.)
+     *
+     * @return the previous element in the list
+     * @throws NoSuchElementException if the iteration has no previous
+     *         element
+     */
+    E previous();
+
+    /**
+     * Returns the index of the element that would be returned by a
+     * subsequent call to {@link #next}. (Returns list size if the list
+     * iterator is at the end of the list.)
+     *
+     * @return the index of the element that would be returned by a
+     *         subsequent call to {@code next}, or list size if the list
+     *         iterator is at the end of the list
+     */
+    int nextIndex();
+
+    /**
+     * Returns the index of the element that would be returned by a
+     * subsequent call to {@link #previous}. (Returns -1 if the list
+     * iterator is at the beginning of the list.)
+     *
+     * @return the index of the element that would be returned by a
+     *         subsequent call to {@code previous}, or -1 if the list
+     *         iterator is at the beginning of the list
+     */
+    int previousIndex();
+
+
+    // Modification Operations
+
+    /**
+     * Removes from the list the last element that was returned by {@link
+     * #next} or {@link #previous} (optional operation).  This call can
+     * only be made once per call to {@code next} or {@code previous}.
+     * It can be made only if {@link #add} has not been
+     * called after the last call to {@code next} or {@code previous}.
+     *
+     * @throws UnsupportedOperationException if the {@code remove}
+     *         operation is not supported by this list iterator
+     * @throws IllegalStateException if neither {@code next} nor
+     *         {@code previous} have been called, or {@code remove} or
+     *         {@code add} have been called after the last call to
+     *         {@code next} or {@code previous}
+     */
+    void remove();
+
+    /**
+     * Replaces the last element returned by {@link #next} or
+     * {@link #previous} with the specified element (optional operation).
+     * This call can be made only if neither {@link #remove} nor {@link
+     * #add} have been called after the last call to {@code next} or
+     * {@code previous}.
+     *
+     * @param e the element with which to replace the last element returned by
+     *          {@code next} or {@code previous}
+     * @throws UnsupportedOperationException if the {@code set} operation
+     *         is not supported by this list iterator
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws IllegalArgumentException if some aspect of the specified
+     *         element prevents it from being added to this list
+     * @throws IllegalStateException if neither {@code next} nor
+     *         {@code previous} have been called, or {@code remove} or
+     *         {@code add} have been called after the last call to
+     *         {@code next} or {@code previous}
+     */
+    void set(E e);
+
+    /**
+     * Inserts the specified element into the list (optional operation).
+     * The element is inserted immediately before the element that
+     * would be returned by {@link #next}, if any, and after the element
+     * that would be returned by {@link #previous}, if any.  (If the
+     * list contains no elements, the new element becomes the sole element
+     * on the list.)  The new element is inserted before the implicit
+     * cursor: a subsequent call to {@code next} would be unaffected, and a
+     * subsequent call to {@code previous} would return the new element.
+     * (This call increases by one the value that would be returned by a
+     * call to {@code nextIndex} or {@code previousIndex}.)
+     *
+     * @param e the element to insert
+     * @throws UnsupportedOperationException if the {@code add} method is
+     *         not supported by this list iterator
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws IllegalArgumentException if some aspect of this element
+     *         prevents it from being added to this list
+     */
+    void add(E e);
+}
diff --git a/java/util/ListResourceBundle.java b/java/util/ListResourceBundle.java
new file mode 100644
index 0000000..99090ca
--- /dev/null
+++ b/java/util/ListResourceBundle.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import sun.util.ResourceBundleEnumeration;
+
+/**
+ * <code>ListResourceBundle</code> is an abstract subclass of
+ * <code>ResourceBundle</code> that manages resources for a locale
+ * in a convenient and easy to use list. See <code>ResourceBundle</code> for
+ * more information about resource bundles in general.
+ *
+ * <P>
+ * Subclasses must override <code>getContents</code> and provide an array,
+ * where each item in the array is a pair of objects.
+ * The first element of each pair is the key, which must be a
+ * <code>String</code>, and the second element is the value associated with
+ * that key.
+ *
+ * <p>
+ * The following <a name="sample">example</a> shows two members of a resource
+ * bundle family with the base name "MyResources".
+ * "MyResources" is the default member of the bundle family, and
+ * "MyResources_fr" is the French member.
+ * These members are based on <code>ListResourceBundle</code>
+ * (a related <a href="PropertyResourceBundle.html#sample">example</a> shows
+ * how you can add a bundle to this family that's based on a properties file).
+ * The keys in this example are of the form "s1" etc. The actual
+ * keys are entirely up to your choice, so long as they are the same as
+ * the keys you use in your program to retrieve the objects from the bundle.
+ * Keys are case-sensitive.
+ * <blockquote>
+ * <pre>
+ *
+ * public class MyResources extends ListResourceBundle {
+ *     protected Object[][] getContents() {
+ *         return new Object[][] {
+ *         // LOCALIZE THIS
+ *             {"s1", "The disk \"{1}\" contains {0}."},  // MessageFormat pattern
+ *             {"s2", "1"},                               // location of {0} in pattern
+ *             {"s3", "My Disk"},                         // sample disk name
+ *             {"s4", "no files"},                        // first ChoiceFormat choice
+ *             {"s5", "one file"},                        // second ChoiceFormat choice
+ *             {"s6", "{0,number} files"},                // third ChoiceFormat choice
+ *             {"s7", "3 Mar 96"},                        // sample date
+ *             {"s8", new Dimension(1,5)}                 // real object, not just string
+ *         // END OF MATERIAL TO LOCALIZE
+ *         };
+ *     }
+ * }
+ *
+ * public class MyResources_fr extends ListResourceBundle {
+ *     protected Object[][] getContents() {
+ *         return new Object[][] {
+ *         // LOCALIZE THIS
+ *             {"s1", "Le disque \"{1}\" {0}."},          // MessageFormat pattern
+ *             {"s2", "1"},                               // location of {0} in pattern
+ *             {"s3", "Mon disque"},                      // sample disk name
+ *             {"s4", "ne contient pas de fichiers"},     // first ChoiceFormat choice
+ *             {"s5", "contient un fichier"},             // second ChoiceFormat choice
+ *             {"s6", "contient {0,number} fichiers"},    // third ChoiceFormat choice
+ *             {"s7", "3 mars 1996"},                     // sample date
+ *             {"s8", new Dimension(1,3)}                 // real object, not just string
+ *         // END OF MATERIAL TO LOCALIZE
+ *         };
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
+ *
+ * <p>
+ * The implementation of a {@code ListResourceBundle} subclass must be thread-safe
+ * if it's simultaneously used by multiple threads. The default implementations
+ * of the methods in this class are thread-safe.
+ *
+ * @see ResourceBundle
+ * @see PropertyResourceBundle
+ * @since JDK1.1
+ */
+public abstract class ListResourceBundle extends ResourceBundle {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public ListResourceBundle() {
+    }
+
+    // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
+    public final Object handleGetObject(String key) {
+        // lazily load the lookup hashtable.
+        if (lookup == null) {
+            loadLookup();
+        }
+        if (key == null) {
+            throw new NullPointerException();
+        }
+        return lookup.get(key); // this class ignores locales
+    }
+
+    /**
+     * Returns an <code>Enumeration</code> of the keys contained in
+     * this <code>ResourceBundle</code> and its parent bundles.
+     *
+     * @return an <code>Enumeration</code> of the keys contained in
+     *         this <code>ResourceBundle</code> and its parent bundles.
+     * @see #keySet()
+     */
+    public Enumeration<String> getKeys() {
+        // lazily load the lookup hashtable.
+        if (lookup == null) {
+            loadLookup();
+        }
+
+        ResourceBundle parent = this.parent;
+        return new ResourceBundleEnumeration(lookup.keySet(),
+                (parent != null) ? parent.getKeys() : null);
+    }
+
+    /**
+     * Returns a <code>Set</code> of the keys contained
+     * <em>only</em> in this <code>ResourceBundle</code>.
+     *
+     * @return a <code>Set</code> of the keys contained only in this
+     *         <code>ResourceBundle</code>
+     * @since 1.6
+     * @see #keySet()
+     */
+    protected Set<String> handleKeySet() {
+        if (lookup == null) {
+            loadLookup();
+        }
+        return lookup.keySet();
+    }
+
+    /**
+     * Returns an array in which each item is a pair of objects in an
+     * <code>Object</code> array. The first element of each pair is
+     * the key, which must be a <code>String</code>, and the second
+     * element is the value associated with that key.  See the class
+     * description for details.
+     *
+     * @return an array of an <code>Object</code> array representing a
+     * key-value pair.
+     */
+    abstract protected Object[][] getContents();
+
+    // ==================privates====================
+
+    /**
+     * We lazily load the lookup hashtable.  This function does the
+     * loading.
+     */
+    private synchronized void loadLookup() {
+        if (lookup != null)
+            return;
+
+        Object[][] contents = getContents();
+        HashMap<String,Object> temp = new HashMap<>(contents.length);
+        for (int i = 0; i < contents.length; ++i) {
+            // key must be non-null String, value must be non-null
+            String key = (String) contents[i][0];
+            Object value = contents[i][1];
+            if (key == null || value == null) {
+                throw new NullPointerException();
+            }
+            temp.put(key, value);
+        }
+        lookup = temp;
+    }
+
+    // Android-changed: Fix unsafe publication http://b/31467561
+    // Fixed in OpenJDK 9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/29ecac30ecae
+    // was: private Map<String,Object> lookup = null;
+    private volatile Map<String,Object> lookup = null;
+}
diff --git a/java/util/Locale.annotated.java b/java/util/Locale.annotated.java
new file mode 100644
index 0000000..d8aad03
--- /dev/null
+++ b/java/util/Locale.annotated.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+
+package java.util;
+
+import java.text.MessageFormat;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Locale implements java.lang.Cloneable, java.io.Serializable {
+
+public Locale(java.lang.String language, java.lang.String country, java.lang.String variant) { throw new RuntimeException("Stub!"); }
+
+public Locale(java.lang.String language, java.lang.String country) { throw new RuntimeException("Stub!"); }
+
+public Locale(java.lang.String language) { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale getDefault() { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale getDefault(java.util.Locale.Category category) { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale initDefault() { throw new RuntimeException("Stub!"); }
+
+public static synchronized void setDefault(java.util.Locale newLocale) { throw new RuntimeException("Stub!"); }
+
+public static synchronized void setDefault(java.util.Locale.Category category, java.util.Locale newLocale) { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale[] getAvailableLocales() { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String[] getISOCountries() { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String[] getISOLanguages() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getLanguage() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getScript() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getCountry() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getVariant() { throw new RuntimeException("Stub!"); }
+
+public boolean hasExtensions() { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale stripExtensions() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getExtension(char key) { throw new RuntimeException("Stub!"); }
+
+public java.util.Set<java.lang.Character> getExtensionKeys() { throw new RuntimeException("Stub!"); }
+
+public java.util.Set<java.lang.String> getUnicodeLocaleAttributes() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getUnicodeLocaleType(java.lang.String key) { throw new RuntimeException("Stub!"); }
+
+public java.util.Set<java.lang.String> getUnicodeLocaleKeys() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toLanguageTag() { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale forLanguageTag(java.lang.String languageTag) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getISO3Language() throws java.util.MissingResourceException { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getISO3Country() throws java.util.MissingResourceException { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayLanguage() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayLanguage(java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayScript() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayScript(java.util.Locale inLocale) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayCountry() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayCountry(java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayVariant() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayVariant(java.util.Locale inLocale) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayName() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayName(java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
+public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static java.lang.String adjustLanguageCode(java.lang.String languageCode) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.util.Locale> locales, java.util.Locale.FilteringMode mode) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.util.Locale> locales) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.lang.String> tags, java.util.Locale.FilteringMode mode) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.lang.String> tags) { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale lookup(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.util.Locale> locales) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String lookupTag(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.lang.String> tags) { throw new RuntimeException("Stub!"); }
+
+public static final java.util.Locale CANADA;
+static { CANADA = null; }
+
+public static final java.util.Locale CANADA_FRENCH;
+static { CANADA_FRENCH = null; }
+
+public static final java.util.Locale CHINA;
+static { CHINA = null; }
+
+public static final java.util.Locale CHINESE;
+static { CHINESE = null; }
+
+public static final java.util.Locale ENGLISH;
+static { ENGLISH = null; }
+
+public static final java.util.Locale FRANCE;
+static { FRANCE = null; }
+
+public static final java.util.Locale FRENCH;
+static { FRENCH = null; }
+
+public static final java.util.Locale GERMAN;
+static { GERMAN = null; }
+
+public static final java.util.Locale GERMANY;
+static { GERMANY = null; }
+
+public static final java.util.Locale ITALIAN;
+static { ITALIAN = null; }
+
+public static final java.util.Locale ITALY;
+static { ITALY = null; }
+
+public static final java.util.Locale JAPAN;
+static { JAPAN = null; }
+
+public static final java.util.Locale JAPANESE;
+static { JAPANESE = null; }
+
+public static final java.util.Locale KOREA;
+static { KOREA = null; }
+
+public static final java.util.Locale KOREAN;
+static { KOREAN = null; }
+
+public static final java.util.Locale PRC;
+static { PRC = null; }
+
+public static final char PRIVATE_USE_EXTENSION = 120; // 0x0078 'x'
+
+public static final java.util.Locale ROOT;
+static { ROOT = null; }
+
+public static final java.util.Locale SIMPLIFIED_CHINESE;
+static { SIMPLIFIED_CHINESE = null; }
+
+public static final java.util.Locale TAIWAN;
+static { TAIWAN = null; }
+
+public static final java.util.Locale TRADITIONAL_CHINESE;
+static { TRADITIONAL_CHINESE = null; }
+
+public static final java.util.Locale UK;
+static { UK = null; }
+
+public static final char UNICODE_LOCALE_EXTENSION = 117; // 0x0075 'u'
+
+public static final java.util.Locale US;
+static { US = null; }
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static final class Builder {
+
+public Builder() { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setLocale(java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setLanguageTag(java.lang.String languageTag) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setLanguage(java.lang.String language) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setScript(java.lang.String script) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setRegion(java.lang.String region) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setVariant(java.lang.String variant) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setExtension(char key, java.lang.String value) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setUnicodeLocaleKeyword(java.lang.String key, java.lang.String type) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder addUnicodeLocaleAttribute(java.lang.String attribute) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder removeUnicodeLocaleAttribute(java.lang.String attribute) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder clear() { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder clearExtensions() { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale build() { throw new RuntimeException("Stub!"); }
+}
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static enum Category {
+DISPLAY,
+FORMAT;
+}
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static enum FilteringMode {
+AUTOSELECT_FILTERING,
+EXTENDED_FILTERING,
+IGNORE_EXTENDED_RANGES,
+MAP_EXTENDED_RANGES,
+REJECT_EXTENDED_RANGES;
+}
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static final class LanguageRange {
+
+public LanguageRange(java.lang.String range) { throw new RuntimeException("Stub!"); }
+
+public LanguageRange(java.lang.String range, double weight) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getRange() { throw new RuntimeException("Stub!"); }
+
+public double getWeight() { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String ranges) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String ranges, java.util.Map<java.lang.String, java.util.List<java.lang.String>> map) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.util.Locale.LanguageRange> mapEquivalents(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Map<java.lang.String, java.util.List<java.lang.String>> map) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public static final double MAX_WEIGHT = 1.0;
+
+public static final double MIN_WEIGHT = 0.0;
+}
+
+}
+
diff --git a/java/util/Locale.java b/java/util/Locale.java
new file mode 100644
index 0000000..1ce4a20
--- /dev/null
+++ b/java/util/Locale.java
@@ -0,0 +1,3772 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import com.android.icu.util.LocaleNative;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.text.MessageFormat;
+import libcore.icu.ICU;
+
+import sun.util.locale.BaseLocale;
+import sun.util.locale.InternalLocaleBuilder;
+import sun.util.locale.LanguageTag;
+import sun.util.locale.LocaleExtensions;
+import sun.util.locale.LocaleMatcher;
+import sun.util.locale.LocaleObjectCache;
+import sun.util.locale.LocaleSyntaxException;
+import sun.util.locale.LocaleUtils;
+import sun.util.locale.ParseStatus;
+
+// Android-added: documentation about ICU data & warning of default locale.
+/**
+ * A <code>Locale</code> object represents a specific geographical, political,
+ * or cultural region. An operation that requires a <code>Locale</code> to perform
+ * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
+ * to tailor information for the user. For example, displaying a number
+ * is a locale-sensitive operation&mdash; the number should be formatted
+ * according to the customs and conventions of the user's native country,
+ * region, or culture.
+ *
+ * <p> The {@code Locale} class implements IETF BCP 47 which is composed of
+ * <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 "Matching of Language
+ * Tags"</a> and <a href="http://tools.ietf.org/html/rfc5646">RFC 5646 "Tags
+ * for Identifying Languages"</a> with support for the LDML (UTS#35, "Unicode
+ * Locale Data Markup Language") BCP 47-compatible extensions for locale data
+ * exchange.
+ *
+ * <p> A <code>Locale</code> object logically consists of the fields
+ * described below.
+ *
+ * <dl>
+ *   <dt><a name="def_language"><b>language</b></a></dt>
+ *
+ *   <dd>ISO 639 alpha-2 or alpha-3 language code, or registered
+ *   language subtags up to 8 alpha letters (for future enhancements).
+ *   When a language has both an alpha-2 code and an alpha-3 code, the
+ *   alpha-2 code must be used.  You can find a full list of valid
+ *   language codes in the IANA Language Subtag Registry (search for
+ *   "Type: language").  The language field is case insensitive, but
+ *   <code>Locale</code> always canonicalizes to lower case.</dd>
+ *
+ *   <dd>Well-formed language values have the form
+ *   <code>[a-zA-Z]{2,8}</code>.  Note that this is not the the full
+ *   BCP47 language production, since it excludes extlang.  They are
+ *   not needed since modern three-letter language codes replace
+ *   them.</dd>
+ *
+ *   <dd>Example: "en" (English), "ja" (Japanese), "kok" (Konkani)</dd>
+ *
+ *   <dt><a name="def_script"><b>script</b></a></dt>
+ *
+ *   <dd>ISO 15924 alpha-4 script code.  You can find a full list of
+ *   valid script codes in the IANA Language Subtag Registry (search
+ *   for "Type: script").  The script field is case insensitive, but
+ *   <code>Locale</code> always canonicalizes to title case (the first
+ *   letter is upper case and the rest of the letters are lower
+ *   case).</dd>
+ *
+ *   <dd>Well-formed script values have the form
+ *   <code>[a-zA-Z]{4}</code></dd>
+ *
+ *   <dd>Example: "Latn" (Latin), "Cyrl" (Cyrillic)</dd>
+ *
+ *   <dt><a name="def_region"><b>country (region)</b></a></dt>
+ *
+ *   <dd>ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code.
+ *   You can find a full list of valid country and region codes in the
+ *   IANA Language Subtag Registry (search for "Type: region").  The
+ *   country (region) field is case insensitive, but
+ *   <code>Locale</code> always canonicalizes to upper case.</dd>
+ *
+ *   <dd>Well-formed country/region values have
+ *   the form <code>[a-zA-Z]{2} | [0-9]{3}</code></dd>
+ *
+ *   <dd>Example: "US" (United States), "FR" (France), "029"
+ *   (Caribbean)</dd>
+ *
+ *   <dt><a name="def_variant"><b>variant</b></a></dt>
+ *
+ *   <dd>Any arbitrary value used to indicate a variation of a
+ *   <code>Locale</code>.  Where there are two or more variant values
+ *   each indicating its own semantics, these values should be ordered
+ *   by importance, with most important first, separated by
+ *   underscore('_').  The variant field is case sensitive.</dd>
+ *
+ *   <dd>Note: IETF BCP 47 places syntactic restrictions on variant
+ *   subtags.  Also BCP 47 subtags are strictly used to indicate
+ *   additional variations that define a language or its dialects that
+ *   are not covered by any combinations of language, script and
+ *   region subtags.  You can find a full list of valid variant codes
+ *   in the IANA Language Subtag Registry (search for "Type: variant").
+ *
+ *   <p>However, the variant field in <code>Locale</code> has
+ *   historically been used for any kind of variation, not just
+ *   language variations.  For example, some supported variants
+ *   available in Java SE Runtime Environments indicate alternative
+ *   cultural behaviors such as calendar type or number script.  In
+ *   BCP 47 this kind of information, which does not identify the
+ *   language, is supported by extension subtags or private use
+ *   subtags.</dd>
+ *
+ *   <dd>Well-formed variant values have the form <code>SUBTAG
+ *   (('_'|'-') SUBTAG)*</code> where <code>SUBTAG =
+ *   [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}</code>. (Note: BCP 47 only
+ *   uses hyphen ('-') as a delimiter, this is more lenient).</dd>
+ *
+ *   <dd>Example: "polyton" (Polytonic Greek), "POSIX"</dd>
+ *
+ *   <dt><a name="def_extensions"><b>extensions</b></a></dt>
+ *
+ *   <dd>A map from single character keys to string values, indicating
+ *   extensions apart from language identification.  The extensions in
+ *   <code>Locale</code> implement the semantics and syntax of BCP 47
+ *   extension subtags and private use subtags. The extensions are
+ *   case insensitive, but <code>Locale</code> canonicalizes all
+ *   extension keys and values to lower case. Note that extensions
+ *   cannot have empty values.</dd>
+ *
+ *   <dd>Well-formed keys are single characters from the set
+ *   <code>[0-9a-zA-Z]</code>.  Well-formed values have the form
+ *   <code>SUBTAG ('-' SUBTAG)*</code> where for the key 'x'
+ *   <code>SUBTAG = [0-9a-zA-Z]{1,8}</code> and for other keys
+ *   <code>SUBTAG = [0-9a-zA-Z]{2,8}</code> (that is, 'x' allows
+ *   single-character subtags).</dd>
+ *
+ *   <dd>Example: key="u"/value="ca-japanese" (Japanese Calendar),
+ *   key="x"/value="java-1-7"</dd>
+ * </dl>
+ *
+ * <b>Note:</b> Although BCP 47 requires field values to be registered
+ * in the IANA Language Subtag Registry, the <code>Locale</code> class
+ * does not provide any validation features.  The <code>Builder</code>
+ * only checks if an individual field satisfies the syntactic
+ * requirement (is well-formed), but does not validate the value
+ * itself.  See {@link Builder} for details.
+ *
+ * <h3><a name="def_locale_extension">Unicode locale/language extension</a></h3>
+ *
+ * <p>UTS#35, "Unicode Locale Data Markup Language" defines optional
+ * attributes and keywords to override or refine the default behavior
+ * associated with a locale.  A keyword is represented by a pair of
+ * key and type.  For example, "nu-thai" indicates that Thai local
+ * digits (value:"thai") should be used for formatting numbers
+ * (key:"nu").
+ *
+ * <p>The keywords are mapped to a BCP 47 extension value using the
+ * extension key 'u' ({@link #UNICODE_LOCALE_EXTENSION}).  The above
+ * example, "nu-thai", becomes the extension "u-nu-thai".code
+ *
+ * <p>Thus, when a <code>Locale</code> object contains Unicode locale
+ * attributes and keywords,
+ * <code>getExtension(UNICODE_LOCALE_EXTENSION)</code> will return a
+ * String representing this information, for example, "nu-thai".  The
+ * <code>Locale</code> class also provides {@link
+ * #getUnicodeLocaleAttributes}, {@link #getUnicodeLocaleKeys}, and
+ * {@link #getUnicodeLocaleType} which allow you to access Unicode
+ * locale attributes and key/type pairs directly.  When represented as
+ * a string, the Unicode Locale Extension lists attributes
+ * alphabetically, followed by key/type sequences with keys listed
+ * alphabetically (the order of subtags comprising a key's type is
+ * fixed when the type is defined)
+ *
+ * <p>A well-formed locale key has the form
+ * <code>[0-9a-zA-Z]{2}</code>.  A well-formed locale type has the
+ * form <code>"" | [0-9a-zA-Z]{3,8} ('-' [0-9a-zA-Z]{3,8})*</code> (it
+ * can be empty, or a series of subtags 3-8 alphanums in length).  A
+ * well-formed locale attribute has the form
+ * <code>[0-9a-zA-Z]{3,8}</code> (it is a single subtag with the same
+ * form as a locale type subtag).
+ *
+ * <p>The Unicode locale extension specifies optional behavior in
+ * locale-sensitive services.  Although the LDML specification defines
+ * various keys and values, actual locale-sensitive service
+ * implementations in a Java Runtime Environment might not support any
+ * particular Unicode locale attributes or key/type pairs.
+ *
+ * <h4>Creating a Locale</h4>
+ *
+ * <p>There are several different ways to create a <code>Locale</code>
+ * object.
+ *
+ * <h5>Builder</h5>
+ *
+ * <p>Using {@link Builder} you can construct a <code>Locale</code> object
+ * that conforms to BCP 47 syntax.
+ *
+ * <h5>Constructors</h5>
+ *
+ * <p>The <code>Locale</code> class provides three constructors:
+ * <blockquote>
+ * <pre>
+ *     {@link #Locale(String language)}
+ *     {@link #Locale(String language, String country)}
+ *     {@link #Locale(String language, String country, String variant)}
+ * </pre>
+ * </blockquote>
+ * These constructors allow you to create a <code>Locale</code> object
+ * with language, country and variant, but you cannot specify
+ * script or extensions.
+ *
+ * <h5>Factory Methods</h5>
+ *
+ * <p>The method {@link #forLanguageTag} creates a <code>Locale</code>
+ * object for a well-formed BCP 47 language tag.
+ *
+ * <h5>Locale Constants</h5>
+ *
+ * <p>The <code>Locale</code> class provides a number of convenient constants
+ * that you can use to create <code>Locale</code> objects for commonly used
+ * locales. For example, the following creates a <code>Locale</code> object
+ * for the United States:
+ * <blockquote>
+ * <pre>
+ *     Locale.US
+ * </pre>
+ * </blockquote>
+ *
+ * <h4><a name="LocaleMatching">Locale Matching</a></h4>
+ *
+ * <p>If an application or a system is internationalized and provides localized
+ * resources for multiple locales, it sometimes needs to find one or more
+ * locales (or language tags) which meet each user's specific preferences. Note
+ * that a term "language tag" is used interchangeably with "locale" in this
+ * locale matching documentation.
+ *
+ * <p>In order to do matching a user's preferred locales to a set of language
+ * tags, <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 Matching of
+ * Language Tags</a> defines two mechanisms: filtering and lookup.
+ * <em>Filtering</em> is used to get all matching locales, whereas
+ * <em>lookup</em> is to choose the best matching locale.
+ * Matching is done case-insensitively. These matching mechanisms are described
+ * in the following sections.
+ *
+ * <p>A user's preference is called a <em>Language Priority List</em> and is
+ * expressed as a list of language ranges. There are syntactically two types of
+ * language ranges: basic and extended. See
+ * {@link Locale.LanguageRange Locale.LanguageRange} for details.
+ *
+ * <h5>Filtering</h5>
+ *
+ * <p>The filtering operation returns all matching language tags. It is defined
+ * in RFC 4647 as follows:
+ * "In filtering, each language range represents the least specific language
+ * tag (that is, the language tag with fewest number of subtags) that is an
+ * acceptable match. All of the language tags in the matching set of tags will
+ * have an equal or greater number of subtags than the language range. Every
+ * non-wildcard subtag in the language range will appear in every one of the
+ * matching language tags."
+ *
+ * <p>There are two types of filtering: filtering for basic language ranges
+ * (called "basic filtering") and filtering for extended language ranges
+ * (called "extended filtering"). They may return different results by what
+ * kind of language ranges are included in the given Language Priority List.
+ * {@link Locale.FilteringMode} is a parameter to specify how filtering should
+ * be done.
+ *
+ * <h5>Lookup</h5>
+ *
+ * <p>The lookup operation returns the best matching language tags. It is
+ * defined in RFC 4647 as follows:
+ * "By contrast with filtering, each language range represents the most
+ * specific tag that is an acceptable match.  The first matching tag found,
+ * according to the user's priority, is considered the closest match and is the
+ * item returned."
+ *
+ * <p>For example, if a Language Priority List consists of two language ranges,
+ * {@code "zh-Hant-TW"} and {@code "en-US"}, in prioritized order, lookup
+ * method progressively searches the language tags below in order to find the
+ * best matching language tag.
+ * <blockquote>
+ * <pre>
+ *    1. zh-Hant-TW
+ *    2. zh-Hant
+ *    3. zh
+ *    4. en-US
+ *    5. en
+ * </pre>
+ * </blockquote>
+ * If there is a language tag which matches completely to a language range
+ * above, the language tag is returned.
+ *
+ * <p>{@code "*"} is the special language range, and it is ignored in lookup.
+ *
+ * <p>If multiple language tags match as a result of the subtag {@code '*'}
+ * included in a language range, the first matching language tag returned by
+ * an {@link Iterator} over a {@link Collection} of language tags is treated as
+ * the best matching one.
+ *
+ * <h4>Use of Locale</h4>
+ *
+ * <p>Once you've created a <code>Locale</code> you can query it for information
+ * about itself. Use <code>getCountry</code> to get the country (or region)
+ * code and <code>getLanguage</code> to get the language code.
+ * You can use <code>getDisplayCountry</code> to get the
+ * name of the country suitable for displaying to the user. Similarly,
+ * you can use <code>getDisplayLanguage</code> to get the name of
+ * the language suitable for displaying to the user. Interestingly,
+ * the <code>getDisplayXXX</code> methods are themselves locale-sensitive
+ * and have two versions: one that uses the default
+ * {@link Locale.Category#DISPLAY DISPLAY} locale and one
+ * that uses the locale specified as an argument.
+ *
+ * <p>The Java Platform provides a number of classes that perform locale-sensitive
+ * operations. For example, the <code>NumberFormat</code> class formats
+ * numbers, currency, and percentages in a locale-sensitive manner. Classes
+ * such as <code>NumberFormat</code> have several convenience methods
+ * for creating a default object of that type. For example, the
+ * <code>NumberFormat</code> class provides these three convenience methods
+ * for creating a default <code>NumberFormat</code> object:
+ * <blockquote>
+ * <pre>
+ *     NumberFormat.getInstance()
+ *     NumberFormat.getCurrencyInstance()
+ *     NumberFormat.getPercentInstance()
+ * </pre>
+ * </blockquote>
+ * Each of these methods has two variants; one with an explicit locale
+ * and one without; the latter uses the default
+ * {@link Locale.Category#FORMAT FORMAT} locale:
+ * <blockquote>
+ * <pre>
+ *     NumberFormat.getInstance(myLocale)
+ *     NumberFormat.getCurrencyInstance(myLocale)
+ *     NumberFormat.getPercentInstance(myLocale)
+ * </pre>
+ * </blockquote>
+ * A <code>Locale</code> is the mechanism for identifying the kind of object
+ * (<code>NumberFormat</code>) that you would like to get. The locale is
+ * <STRONG>just</STRONG> a mechanism for identifying objects,
+ * <STRONG>not</STRONG> a container for the objects themselves.
+ *
+ * <h4>Compatibility</h4>
+ *
+ * <p>In order to maintain compatibility with existing usage, Locale's
+ * constructors retain their behavior prior to the Java Runtime
+ * Environment version 1.7.  The same is largely true for the
+ * <code>toString</code> method. Thus Locale objects can continue to
+ * be used as they were. In particular, clients who parse the output
+ * of toString into language, country, and variant fields can continue
+ * to do so (although this is strongly discouraged), although the
+ * variant field will have additional information in it if script or
+ * extensions are present.
+ *
+ * <p>In addition, BCP 47 imposes syntax restrictions that are not
+ * imposed by Locale's constructors. This means that conversions
+ * between some Locales and BCP 47 language tags cannot be made without
+ * losing information. Thus <code>toLanguageTag</code> cannot
+ * represent the state of locales whose language, country, or variant
+ * do not conform to BCP 47.
+ *
+ * <p>Because of these issues, it is recommended that clients migrate
+ * away from constructing non-conforming locales and use the
+ * <code>forLanguageTag</code> and <code>Locale.Builder</code> APIs instead.
+ * Clients desiring a string representation of the complete locale can
+ * then always rely on <code>toLanguageTag</code> for this purpose.
+ *
+ * <h5><a name="special_cases_constructor">Special cases</a></h5>
+ *
+ * <p>For compatibility reasons, two
+ * non-conforming locales are treated as special cases.  These are
+ * <b><tt>ja_JP_JP</tt></b> and <b><tt>th_TH_TH</tt></b>. These are ill-formed
+ * in BCP 47 since the variants are too short. To ease migration to BCP 47,
+ * these are treated specially during construction.  These two cases (and only
+ * these) cause a constructor to generate an extension, all other values behave
+ * exactly as they did prior to Java 7.
+ *
+ * <p>Java has used <tt>ja_JP_JP</tt> to represent Japanese as used in
+ * Japan together with the Japanese Imperial calendar. This is now
+ * representable using a Unicode locale extension, by specifying the
+ * Unicode locale key <tt>ca</tt> (for "calendar") and type
+ * <tt>japanese</tt>. When the Locale constructor is called with the
+ * arguments "ja", "JP", "JP", the extension "u-ca-japanese" is
+ * automatically added.
+ *
+ * <p>Java has used <tt>th_TH_TH</tt> to represent Thai as used in
+ * Thailand together with Thai digits. This is also now representable using
+ * a Unicode locale extension, by specifying the Unicode locale key
+ * <tt>nu</tt> (for "number") and value <tt>thai</tt>. When the Locale
+ * constructor is called with the arguments "th", "TH", "TH", the
+ * extension "u-nu-thai" is automatically added.
+ *
+ * <h5>Serialization</h5>
+ *
+ * <p>During serialization, writeObject writes all fields to the output
+ * stream, including extensions.
+ *
+ * <p>During deserialization, readResolve adds extensions as described
+ * in <a href="#special_cases_constructor">Special Cases</a>, only
+ * for the two cases th_TH_TH and ja_JP_JP.
+ *
+ * <h5>Legacy language codes</h5>
+ *
+ * <p>Locale's constructor has always converted three language codes to
+ * their earlier, obsoleted forms: <tt>he</tt> maps to <tt>iw</tt>,
+ * <tt>yi</tt> maps to <tt>ji</tt>, and <tt>id</tt> maps to
+ * <tt>in</tt>.  This continues to be the case, in order to not break
+ * backwards compatibility.
+ *
+ * <p>The APIs added in 1.7 map between the old and new language codes,
+ * maintaining the old codes internal to Locale (so that
+ * <code>getLanguage</code> and <code>toString</code> reflect the old
+ * code), but using the new codes in the BCP 47 language tag APIs (so
+ * that <code>toLanguageTag</code> reflects the new one). This
+ * preserves the equivalence between Locales no matter which code or
+ * API is used to construct them. Java's default resource bundle
+ * lookup mechanism also implements this mapping, so that resources
+ * can be named using either convention, see {@link ResourceBundle.Control}.
+ *
+ * <h5>Three-letter language/country(region) codes</h5>
+ *
+ * <p>The Locale constructors have always specified that the language
+ * and the country param be two characters in length, although in
+ * practice they have accepted any length.  The specification has now
+ * been relaxed to allow language codes of two to eight characters and
+ * country (region) codes of two to three characters, and in
+ * particular, three-letter language codes and three-digit region
+ * codes as specified in the IANA Language Subtag Registry.  For
+ * compatibility, the implementation still does not impose a length
+ * constraint.
+ *
+ * <a name="locale_data"></a><h4>Locale data</h4>
+ * <p>Note that locale data comes solely from ICU. User-supplied locale service providers (using
+ * the {@code java.text.spi} or {@code java.util.spi} mechanisms) are not supported.
+ *
+ * <p>Here are the versions of ICU (and the corresponding CLDR and Unicode versions) used in
+ * various Android releases:
+ * <table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+ * <tr><td>Android 1.5 (Cupcake)/Android 1.6 (Donut)/Android 2.0 (Eclair)</td>
+ *     <td>ICU 3.8</td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-5">CLDR 1.5</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode5.0.0/">Unicode 5.0</a></td></tr>
+ * <tr><td>Android 2.2 (Froyo)</td>
+ *     <td>ICU 4.2</td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-7">CLDR 1.7</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode5.1.0/">Unicode 5.1</a></td></tr>
+ * <tr><td>Android 2.3 (Gingerbread)/Android 3.0 (Honeycomb)</td>
+ *     <td>ICU 4.4</td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-8">CLDR 1.8</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode5.2.0/">Unicode 5.2</a></td></tr>
+ * <tr><td>Android 4.0 (Ice Cream Sandwich)</td>
+ *     <td><a href="http://site.icu-project.org/download/46">ICU 4.6</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-9">CLDR 1.9</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
+ * <tr><td>Android 4.1 (Jelly Bean)</td>
+ *     <td><a href="http://site.icu-project.org/download/48">ICU 4.8</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-2-0">CLDR 2.0</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
+ * <tr><td>Android 4.3 (Jelly Bean MR2)</td>
+ *     <td><a href="http://site.icu-project.org/download/50">ICU 50</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-22-1">CLDR 22.1</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.2.0/">Unicode 6.2</a></td></tr>
+ * <tr><td>Android 4.4 (KitKat)</td>
+ *     <td><a href="http://site.icu-project.org/download/51">ICU 51</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-23">CLDR 23</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.2.0/">Unicode 6.2</a></td></tr>
+ * <tr><td>Android 5.0 (Lollipop)</td>
+ *     <td><a href="http://site.icu-project.org/download/53">ICU 53</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-25">CLDR 25</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode 6.3</a></td></tr>
+ * <tr><td>Android 6.0 (Marshmallow)</td>
+ *     <td><a href="http://site.icu-project.org/download/55">ICU 55.1</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-27">CLDR 27.0.1</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode7.0.0/">Unicode 7.0</a></td></tr>
+ * <tr><td>Android 7.0 (Nougat)</td>
+ *     <td><a href="http://site.icu-project.org/download/56">ICU 56.1</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-28">CLDR 28</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode8.0.0/">Unicode 8.0</a></td></tr>
+ * <tr><td>Android 8.0 (Oreo)</td>
+ *     <td><a href="http://site.icu-project.org/download/58">ICU 58.2</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-30">CLDR 30.0.3</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode9.0.0/">Unicode 9.0</a></td></tr>
+ * <tr><td>Android 9.0 (Pie)</td>
+ *     <td><a href="http://site.icu-project.org/download/60">ICU 60.2</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-32">CLDR 32.0.1</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode10.0.0/">Unicode 10.0</a></td></tr>
+ * <tr><td>Android 10.0 (Q)</td>
+ *     <td><a href="http://site.icu-project.org/download/63">ICU 63.2</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-34">CLDR 34</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode11.0.0/">Unicode 11.0</a></td></tr>
+ * </table>
+ *
+ * <a name="default_locale"></a><h4>Be wary of the default locale</h3>
+ * <p>Note that there are many convenience methods that automatically use the default locale, but
+ * using them may lead to subtle bugs.
+ *
+ * <p>The default locale is appropriate for tasks that involve presenting data to the user. In
+ * this case, you want to use the user's date/time formats, number
+ * formats, rules for conversion to lowercase, and so on. In this case, it's safe to use the
+ * convenience methods.
+ *
+ * <p>The default locale is <i>not</i> appropriate for machine-readable output. The best choice
+ * there is usually {@code Locale.US}&nbsp;&ndash; this locale is guaranteed to be available on all
+ * devices, and the fact that it has no surprising special cases and is frequently used (especially
+ * for computer-computer communication) means that it tends to be the most efficient choice too.
+ *
+ * <p>A common mistake is to implicitly use the default locale when producing output meant to be
+ * machine-readable. This tends to work on the developer's test devices (especially because so many
+ * developers use en_US), but fails when run on a device whose user is in a more complex locale.
+ *
+ * <p>For example, if you're formatting integers some locales will use non-ASCII decimal
+ * digits. As another example, if you're formatting floating-point numbers some locales will use
+ * {@code ','} as the decimal point and {@code '.'} for digit grouping. That's correct for
+ * human-readable output, but likely to cause problems if presented to another
+ * computer ({@link Double#parseDouble} can't parse such a number, for example).
+ * You should also be wary of the {@link String#toLowerCase} and
+ * {@link String#toUpperCase} overloads that don't take a {@code Locale}: in Turkey, for example,
+ * the characters {@code 'i'} and {@code 'I'} won't be converted to {@code 'I'} and {@code 'i'}.
+ * This is the correct behavior for Turkish text (such as user input), but inappropriate for, say,
+ * HTTP headers.
+ *
+ * @see Builder
+ * @see ResourceBundle
+ * @see java.text.Format
+ * @see java.text.NumberFormat
+ * @see java.text.Collator
+ * @author Mark Davis
+ * @since 1.1
+ */
+public final class Locale implements Cloneable, Serializable {
+
+    static private final  Cache LOCALECACHE = new Cache();
+
+    /** Useful constant for language.
+     */
+    static public final Locale ENGLISH = createConstant("en", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale FRENCH = createConstant("fr", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale GERMAN = createConstant("de", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale ITALIAN = createConstant("it", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale JAPANESE = createConstant("ja", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale KOREAN = createConstant("ko", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale CHINESE = createConstant("zh", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");
+
+    /** Useful constant for language.
+     */
+    static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW");
+
+    /** Useful constant for country.
+     */
+    static public final Locale FRANCE = createConstant("fr", "FR");
+
+    /** Useful constant for country.
+     */
+    static public final Locale GERMANY = createConstant("de", "DE");
+
+    /** Useful constant for country.
+     */
+    static public final Locale ITALY = createConstant("it", "IT");
+
+    /** Useful constant for country.
+     */
+    static public final Locale JAPAN = createConstant("ja", "JP");
+
+    /** Useful constant for country.
+     */
+    static public final Locale KOREA = createConstant("ko", "KR");
+
+    /** Useful constant for country.
+     */
+    static public final Locale CHINA = SIMPLIFIED_CHINESE;
+
+    /** Useful constant for country.
+     */
+    static public final Locale PRC = SIMPLIFIED_CHINESE;
+
+    /** Useful constant for country.
+     */
+    static public final Locale TAIWAN = TRADITIONAL_CHINESE;
+
+    /** Useful constant for country.
+     */
+    static public final Locale UK = createConstant("en", "GB");
+
+    /** Useful constant for country.
+     */
+    static public final Locale US = createConstant("en", "US");
+
+    /** Useful constant for country.
+     */
+    static public final Locale CANADA = createConstant("en", "CA");
+
+    /** Useful constant for country.
+     */
+    static public final Locale CANADA_FRENCH = createConstant("fr", "CA");
+
+    // Android-added: (internal only): ISO 639-3 generic code for undetermined languages.
+    private static final String UNDETERMINED_LANGUAGE = "und";
+
+    /**
+     * Useful constant for the root locale.  The root locale is the locale whose
+     * language, country, and variant are empty ("") strings.  This is regarded
+     * as the base locale of all locales, and is used as the language/country
+     * neutral locale for the locale sensitive operations.
+     *
+     * @since 1.6
+     */
+    static public final Locale ROOT = createConstant("", "");
+
+    /**
+     * The key for the private use extension ('x').
+     *
+     * @see #getExtension(char)
+     * @see Builder#setExtension(char, String)
+     * @since 1.7
+     */
+    static public final char PRIVATE_USE_EXTENSION = 'x';
+
+    /**
+     * The key for Unicode locale extension ('u').
+     *
+     * @see #getExtension(char)
+     * @see Builder#setExtension(char, String)
+     * @since 1.7
+     */
+    static public final char UNICODE_LOCALE_EXTENSION = 'u';
+
+    /** serialization ID
+     */
+    static final long serialVersionUID = 9149081749638150636L;
+
+    /**
+     * Display types for retrieving localized names from the name providers.
+     */
+    private static final int DISPLAY_LANGUAGE = 0;
+    private static final int DISPLAY_COUNTRY  = 1;
+    private static final int DISPLAY_VARIANT  = 2;
+    private static final int DISPLAY_SCRIPT   = 3;
+
+    /**
+     * Private constructor used by getInstance method
+     */
+    private Locale(BaseLocale baseLocale, LocaleExtensions extensions) {
+        this.baseLocale = baseLocale;
+        this.localeExtensions = extensions;
+    }
+
+    /**
+     * Construct a locale from language, country and variant.
+     * This constructor normalizes the language value to lowercase and
+     * the country value to uppercase.
+     * <p>
+     * <b>Note:</b>
+     * <ul>
+     * <li>ISO 639 is not a stable standard; some of the language codes it defines
+     * (specifically "iw", "ji", and "in") have changed.  This constructor accepts both the
+     * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
+     * API on Locale will return only the OLD codes.
+     * <li>For backward compatibility reasons, this constructor does not make
+     * any syntactic checks on the input.
+     * <li>The two cases ("ja", "JP", "JP") and ("th", "TH", "TH") are handled specially,
+     * see <a href="#special_cases_constructor">Special Cases</a> for more information.
+     * </ul>
+     *
+     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
+     * up to 8 characters in length.  See the <code>Locale</code> class description about
+     * valid language values.
+     * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
+     * See the <code>Locale</code> class description about valid country values.
+     * @param variant Any arbitrary value used to indicate a variation of a <code>Locale</code>.
+     * See the <code>Locale</code> class description for the details.
+     * @exception NullPointerException thrown if any argument is null.
+     */
+    public Locale(String language, String country, String variant) {
+        if (language== null || country == null || variant == null) {
+            throw new NullPointerException();
+        }
+        baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant);
+        localeExtensions = getCompatibilityExtensions(language, "", country, variant);
+    }
+
+    /**
+     * Construct a locale from language and country.
+     * This constructor normalizes the language value to lowercase and
+     * the country value to uppercase.
+     * <p>
+     * <b>Note:</b>
+     * <ul>
+     * <li>ISO 639 is not a stable standard; some of the language codes it defines
+     * (specifically "iw", "ji", and "in") have changed.  This constructor accepts both the
+     * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
+     * API on Locale will return only the OLD codes.
+     * <li>For backward compatibility reasons, this constructor does not make
+     * any syntactic checks on the input.
+     * </ul>
+     *
+     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
+     * up to 8 characters in length.  See the <code>Locale</code> class description about
+     * valid language values.
+     * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
+     * See the <code>Locale</code> class description about valid country values.
+     * @exception NullPointerException thrown if either argument is null.
+     */
+    public Locale(String language, String country) {
+        this(language, country, "");
+    }
+
+    /**
+     * Construct a locale from a language code.
+     * This constructor normalizes the language value to lowercase.
+     * <p>
+     * <b>Note:</b>
+     * <ul>
+     * <li>ISO 639 is not a stable standard; some of the language codes it defines
+     * (specifically "iw", "ji", and "in") have changed.  This constructor accepts both the
+     * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
+     * API on Locale will return only the OLD codes.
+     * <li>For backward compatibility reasons, this constructor does not make
+     * any syntactic checks on the input.
+     * </ul>
+     *
+     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
+     * up to 8 characters in length.  See the <code>Locale</code> class description about
+     * valid language values.
+     * @exception NullPointerException thrown if argument is null.
+     * @since 1.4
+     */
+    public Locale(String language) {
+        this(language, "", "");
+    }
+
+    /**
+     * This method must be called only for creating the Locale.*
+     * constants due to making shortcuts.
+     */
+    private static Locale createConstant(String lang, String country) {
+        BaseLocale base = BaseLocale.createInstance(lang, country);
+        return getInstance(base, null);
+    }
+
+    /**
+     * Returns a <code>Locale</code> constructed from the given
+     * <code>language</code>, <code>country</code> and
+     * <code>variant</code>. If the same <code>Locale</code> instance
+     * is available in the cache, then that instance is
+     * returned. Otherwise, a new <code>Locale</code> instance is
+     * created and cached.
+     *
+     * @param language lowercase 2 to 8 language code.
+     * @param country uppercase two-letter ISO-3166 code and numric-3 UN M.49 area code.
+     * @param variant vendor and browser specific code. See class description.
+     * @return the <code>Locale</code> instance requested
+     * @exception NullPointerException if any argument is null.
+     */
+    static Locale getInstance(String language, String country, String variant) {
+        return getInstance(language, "", country, variant, null);
+    }
+
+    static Locale getInstance(String language, String script, String country,
+                                      String variant, LocaleExtensions extensions) {
+        if (language== null || script == null || country == null || variant == null) {
+            throw new NullPointerException();
+        }
+
+        if (extensions == null) {
+            extensions = getCompatibilityExtensions(language, script, country, variant);
+        }
+
+        BaseLocale baseloc = BaseLocale.getInstance(language, script, country, variant);
+        return getInstance(baseloc, extensions);
+    }
+
+    static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) {
+        LocaleKey key = new LocaleKey(baseloc, extensions);
+        return LOCALECACHE.get(key);
+    }
+
+    private static class Cache extends LocaleObjectCache<LocaleKey, Locale> {
+        private Cache() {
+        }
+
+        @Override
+        protected Locale createObject(LocaleKey key) {
+            return new Locale(key.base, key.exts);
+        }
+    }
+
+    private static final class LocaleKey {
+        private final BaseLocale base;
+        private final LocaleExtensions exts;
+        private final int hash;
+
+        private LocaleKey(BaseLocale baseLocale, LocaleExtensions extensions) {
+            base = baseLocale;
+            exts = extensions;
+
+            // Calculate the hash value here because it's always used.
+            int h = base.hashCode();
+            if (exts != null) {
+                h ^= exts.hashCode();
+            }
+            hash = h;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof LocaleKey)) {
+                return false;
+            }
+            LocaleKey other = (LocaleKey)obj;
+            if (hash != other.hash || !base.equals(other.base)) {
+                return false;
+            }
+            if (exts == null) {
+                return other.exts == null;
+            }
+            return exts.equals(other.exts);
+        }
+
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+    }
+
+    /**
+     * Gets the current value of the default locale for this instance
+     * of the Java Virtual Machine.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup
+     * based on the host environment. It is used by many locale-sensitive
+     * methods if no locale is explicitly specified.
+     * It can be changed using the
+     * {@link #setDefault(java.util.Locale) setDefault} method.
+     *
+     * @return the default locale for this instance of the Java Virtual Machine
+     */
+    public static Locale getDefault() {
+        // do not synchronize this method - see 4071298
+        // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+        // return defaultLocale;
+        return NoImagePreloadHolder.defaultLocale;
+    }
+
+    /**
+     * Gets the current value of the default locale for the specified Category
+     * for this instance of the Java Virtual Machine.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup based
+     * on the host environment. It is used by many locale-sensitive methods
+     * if no locale is explicitly specified. It can be changed using the
+     * setDefault(Locale.Category, Locale) method.
+     *
+     * @param category - the specified category to get the default locale
+     * @throws NullPointerException - if category is null
+     * @return the default locale for the specified Category for this instance
+     *     of the Java Virtual Machine
+     * @see #setDefault(Locale.Category, Locale)
+     * @since 1.7
+     */
+    public static Locale getDefault(Locale.Category category) {
+        // do not synchronize this method - see 4071298
+        switch (category) {
+        case DISPLAY:
+            if (defaultDisplayLocale == null) {
+                synchronized(Locale.class) {
+                    if (defaultDisplayLocale == null) {
+                        defaultDisplayLocale = initDefault(category);
+                    }
+                }
+            }
+            return defaultDisplayLocale;
+        case FORMAT:
+            if (defaultFormatLocale == null) {
+                synchronized(Locale.class) {
+                    if (defaultFormatLocale == null) {
+                        defaultFormatLocale = initDefault(category);
+                    }
+                }
+            }
+            return defaultFormatLocale;
+        default:
+            assert false: "Unknown Category";
+        }
+        return getDefault();
+    }
+
+    /**
+     * @hide visible for testing.
+     */
+    // Android-changed: Make initDefault() @hide public for testing.
+    // private static Locale initDefault() {
+    public static Locale initDefault() {
+        // BEGIN Android-added: In initDefault(), prioritize user.locale.
+        // user.locale gets priority
+        final String languageTag = System.getProperty("user.locale", "");
+        if (!languageTag.isEmpty()) {
+            return Locale.forLanguageTag(languageTag);
+        }
+        // END Android-added: In initDefault(), prioritize user.locale.
+
+        // BEGIN Android-changed: Short-circuit legacy security code.
+        // Use System.getProperty(name, default) instead of
+        // AccessController.doPrivileged(new GetPropertyAction(name, default)).
+        String language, region, script, country, variant;
+        language = System.getProperty("user.language", "en");
+        // for compatibility, check for old user.region property
+        region = System.getProperty("user.region");
+        if (region != null) {
+            // region can be of form country, country_variant, or _variant
+            int i = region.indexOf('_');
+            if (i >= 0) {
+                country = region.substring(0, i);
+                variant = region.substring(i + 1);
+            } else {
+                country = region;
+                variant = "";
+            }
+            script = "";
+        } else {
+            script = System.getProperty("user.script", "");
+            country = System.getProperty("user.country", "");
+            variant = System.getProperty("user.variant", "");
+        }
+        // END Android-changed: Short-circuit legacy security code.
+
+        return getInstance(language, script, country, variant, null);
+    }
+
+    private static Locale initDefault(Locale.Category category) {
+        // Android-added: Add NoImagePreloadHolder to allow compile-time initialization.
+        final Locale defaultLocale = NoImagePreloadHolder.defaultLocale;
+        // BEGIN Android-changed: Short-circuit legacy security code.
+        /*
+        return getInstance(
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.languageKey, defaultLocale.getLanguage())),
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.scriptKey, defaultLocale.getScript())),
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.countryKey, defaultLocale.getCountry())),
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.variantKey, defaultLocale.getVariant())),
+            null);
+        */
+        return getInstance(
+            System.getProperty(category.languageKey, defaultLocale.getLanguage()),
+            System.getProperty(category.scriptKey, defaultLocale.getScript()),
+            System.getProperty(category.countryKey, defaultLocale.getCountry()),
+            System.getProperty(category.variantKey, defaultLocale.getVariant()),
+            null);
+        // END Android-changed: Short-circuit legacy security code.
+    }
+
+    /**
+     * Sets the default locale for this instance of the Java Virtual Machine.
+     * This does not affect the host locale.
+     * <p>
+     * If there is a security manager, its <code>checkPermission</code>
+     * method is called with a <code>PropertyPermission("user.language", "write")</code>
+     * permission before the default locale is changed.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup
+     * based on the host environment. It is used by many locale-sensitive
+     * methods if no locale is explicitly specified.
+     * <p>
+     * Since changing the default locale may affect many different areas
+     * of functionality, this method should only be used if the caller
+     * is prepared to reinitialize locale-sensitive code running
+     * within the same Java Virtual Machine.
+     * <p>
+     * By setting the default locale with this method, all of the default
+     * locales for each Category are also set to the specified default locale.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        <code>checkPermission</code> method doesn't allow the operation.
+     * @throws NullPointerException if <code>newLocale</code> is null
+     * @param newLocale the new default locale
+     * @see SecurityManager#checkPermission
+     * @see java.util.PropertyPermission
+     */
+    public static synchronized void setDefault(Locale newLocale) {
+        setDefault(Category.DISPLAY, newLocale);
+        setDefault(Category.FORMAT, newLocale);
+        // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+        // defaultLocale = newLocale;
+        NoImagePreloadHolder.defaultLocale = newLocale;
+        // Android-added: Keep ICU state in sync with java.util.
+        ICU.setDefaultLocale(newLocale.toLanguageTag());
+    }
+
+    /**
+     * Sets the default locale for the specified Category for this instance
+     * of the Java Virtual Machine. This does not affect the host locale.
+     * <p>
+     * If there is a security manager, its checkPermission method is called
+     * with a PropertyPermission("user.language", "write") permission before
+     * the default locale is changed.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup based
+     * on the host environment. It is used by many locale-sensitive methods
+     * if no locale is explicitly specified.
+     * <p>
+     * Since changing the default locale may affect many different areas of
+     * functionality, this method should only be used if the caller is
+     * prepared to reinitialize locale-sensitive code running within the
+     * same Java Virtual Machine.
+     * <p>
+     *
+     * @param category - the specified category to set the default locale
+     * @param newLocale - the new default locale
+     * @throws SecurityException - if a security manager exists and its
+     *     checkPermission method doesn't allow the operation.
+     * @throws NullPointerException - if category and/or newLocale is null
+     * @see SecurityManager#checkPermission(java.security.Permission)
+     * @see PropertyPermission
+     * @see #getDefault(Locale.Category)
+     * @since 1.7
+     */
+    public static synchronized void setDefault(Locale.Category category,
+        Locale newLocale) {
+        if (category == null)
+            throw new NullPointerException("Category cannot be NULL");
+        if (newLocale == null)
+            throw new NullPointerException("Can't set default locale to NULL");
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) sm.checkPermission(new PropertyPermission
+                        ("user.language", "write"));
+        switch (category) {
+        case DISPLAY:
+            defaultDisplayLocale = newLocale;
+            break;
+        case FORMAT:
+            defaultFormatLocale = newLocale;
+            break;
+        default:
+            assert false: "Unknown Category";
+        }
+    }
+
+    // Android-changed: Removed documentation references to LocaleServiceProvider.
+    /**
+     * Returns an array of all installed locales.
+     *
+     * @return An array of installed locales.
+     */
+    public static Locale[] getAvailableLocales() {
+        // Android-changed: Use ICU.
+        // return LocaleServiceProviderPool.getAllAvailableLocales();
+        return ICU.getAvailableLocales();
+    }
+
+    /**
+     * Returns a list of all 2-letter country codes defined in ISO 3166.
+     * Can be used to create Locales.
+     * <p>
+     * <b>Note:</b> The <code>Locale</code> class also supports other codes for
+     * country (region), such as 3-letter numeric UN M.49 area codes.
+     * Therefore, the list returned by this method does not contain ALL valid
+     * codes that can be used to create Locales.
+     *
+     * @return An array of ISO 3166 two-letter country codes.
+     */
+    public static String[] getISOCountries() {
+        // Android-changed: Use ICU.
+        /*
+        if (isoCountries == null) {
+            isoCountries = getISO2Table(LocaleISOData.isoCountryTable);
+        }
+        String[] result = new String[isoCountries.length];
+        System.arraycopy(isoCountries, 0, result, 0, isoCountries.length);
+        return result;
+        */
+        return ICU.getISOCountries();
+    }
+
+    /**
+     * Returns a list of all 2-letter language codes defined in ISO 639.
+     * Can be used to create Locales.
+     * <p>
+     * <b>Note:</b>
+     * <ul>
+     * <li>ISO 639 is not a stable standard&mdash; some languages' codes have changed.
+     * The list this function returns includes both the new and the old codes for the
+     * languages whose codes have changed.
+     * <li>The <code>Locale</code> class also supports language codes up to
+     * 8 characters in length.  Therefore, the list returned by this method does
+     * not contain ALL valid codes that can be used to create Locales.
+     * </ul>
+     *
+     * @return Am array of ISO 639 two-letter language codes.
+     */
+    public static String[] getISOLanguages() {
+        // Android-changed: Use ICU.
+        /*
+        if (isoLanguages == null) {
+            isoLanguages = getISO2Table(LocaleISOData.isoLanguageTable);
+        }
+        String[] result = new String[isoLanguages.length];
+        System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
+        return result;
+        */
+        return ICU.getISOLanguages();
+    }
+
+    // Android-removed: Use ICU.
+    // Private helper method getISO2Table(), unused on Android.
+    /*
+    private static String[] getISO2Table(String table) {
+        int len = table.length() / 5;
+        String[] isoTable = new String[len];
+        for (int i = 0, j = 0; i < len; i++, j += 5) {
+            isoTable[i] = table.substring(j, j + 2);
+        }
+        return isoTable;
+    }
+    */
+
+    /**
+     * Returns the language code of this Locale.
+     *
+     * <p><b>Note:</b> ISO 639 is not a stable standard&mdash; some languages' codes have changed.
+     * Locale's constructor recognizes both the new and the old codes for the languages
+     * whose codes have changed, but this function always returns the old code.  If you
+     * want to check for a specific language whose code has changed, don't do
+     * <pre>
+     * if (locale.getLanguage().equals("he")) // BAD!
+     *    ...
+     * </pre>
+     * Instead, do
+     * <pre>
+     * if (locale.getLanguage().equals(new Locale("he").getLanguage()))
+     *    ...
+     * </pre>
+     * @return The language code, or the empty string if none is defined.
+     * @see #getDisplayLanguage
+     */
+    public String getLanguage() {
+        return baseLocale.getLanguage();
+    }
+
+    /**
+     * Returns the script for this locale, which should
+     * either be the empty string or an ISO 15924 4-letter script
+     * code. The first letter is uppercase and the rest are
+     * lowercase, for example, 'Latn', 'Cyrl'.
+     *
+     * @return The script code, or the empty string if none is defined.
+     * @see #getDisplayScript
+     * @since 1.7
+     */
+    public String getScript() {
+        return baseLocale.getScript();
+    }
+
+    /**
+     * Returns the country/region code for this locale, which should
+     * either be the empty string, an uppercase ISO 3166 2-letter code,
+     * or a UN M.49 3-digit code.
+     *
+     * @return The country/region code, or the empty string if none is defined.
+     * @see #getDisplayCountry
+     */
+    public String getCountry() {
+        return baseLocale.getRegion();
+    }
+
+    /**
+     * Returns the variant code for this locale.
+     *
+     * @return The variant code, or the empty string if none is defined.
+     * @see #getDisplayVariant
+     */
+    public String getVariant() {
+        return baseLocale.getVariant();
+    }
+
+    /**
+     * Returns {@code true} if this {@code Locale} has any <a href="#def_extensions">
+     * extensions</a>.
+     *
+     * @return {@code true} if this {@code Locale} has any extensions
+     * @since 1.8
+     */
+    public boolean hasExtensions() {
+        return localeExtensions != null;
+    }
+
+    /**
+     * Returns a copy of this {@code Locale} with no <a href="#def_extensions">
+     * extensions</a>. If this {@code Locale} has no extensions, this {@code Locale}
+     * is returned.
+     *
+     * @return a copy of this {@code Locale} with no extensions, or {@code this}
+     *         if {@code this} has no extensions
+     * @since 1.8
+     */
+    public Locale stripExtensions() {
+        return hasExtensions() ? Locale.getInstance(baseLocale, null) : this;
+    }
+
+    /**
+     * Returns the extension (or private use) value associated with
+     * the specified key, or null if there is no extension
+     * associated with the key. To be well-formed, the key must be one
+     * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so
+     * for example 'z' and 'Z' represent the same extension.
+     *
+     * @param key the extension key
+     * @return The extension, or null if this locale defines no
+     * extension for the specified key.
+     * @throws IllegalArgumentException if key is not well-formed
+     * @see #PRIVATE_USE_EXTENSION
+     * @see #UNICODE_LOCALE_EXTENSION
+     * @since 1.7
+     */
+    public String getExtension(char key) {
+        if (!LocaleExtensions.isValidKey(key)) {
+            throw new IllegalArgumentException("Ill-formed extension key: " + key);
+        }
+        return hasExtensions() ? localeExtensions.getExtensionValue(key) : null;
+    }
+
+    /**
+     * Returns the set of extension keys associated with this locale, or the
+     * empty set if it has no extensions. The returned set is unmodifiable.
+     * The keys will all be lower-case.
+     *
+     * @return The set of extension keys, or the empty set if this locale has
+     * no extensions.
+     * @since 1.7
+     */
+    public Set<Character> getExtensionKeys() {
+        if (!hasExtensions()) {
+            return Collections.emptySet();
+        }
+        return localeExtensions.getKeys();
+    }
+
+    /**
+     * Returns the set of unicode locale attributes associated with
+     * this locale, or the empty set if it has no attributes. The
+     * returned set is unmodifiable.
+     *
+     * @return The set of attributes.
+     * @since 1.7
+     */
+    public Set<String> getUnicodeLocaleAttributes() {
+        if (!hasExtensions()) {
+            return Collections.emptySet();
+        }
+        return localeExtensions.getUnicodeLocaleAttributes();
+    }
+
+    /**
+     * Returns the Unicode locale type associated with the specified Unicode locale key
+     * for this locale. Returns the empty string for keys that are defined with no type.
+     * Returns null if the key is not defined. Keys are case-insensitive. The key must
+     * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is
+     * thrown.
+     *
+     * @param key the Unicode locale key
+     * @return The Unicode locale type associated with the key, or null if the
+     * locale does not define the key.
+     * @throws IllegalArgumentException if the key is not well-formed
+     * @throws NullPointerException if <code>key</code> is null
+     * @since 1.7
+     */
+    public String getUnicodeLocaleType(String key) {
+        if (!isUnicodeExtensionKey(key)) {
+            throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key);
+        }
+        return hasExtensions() ? localeExtensions.getUnicodeLocaleType(key) : null;
+    }
+
+    /**
+     * Returns the set of Unicode locale keys defined by this locale, or the empty set if
+     * this locale has none.  The returned set is immutable.  Keys are all lower case.
+     *
+     * @return The set of Unicode locale keys, or the empty set if this locale has
+     * no Unicode locale keywords.
+     * @since 1.7
+     */
+    public Set<String> getUnicodeLocaleKeys() {
+        if (localeExtensions == null) {
+            return Collections.emptySet();
+        }
+        return localeExtensions.getUnicodeLocaleKeys();
+    }
+
+    /**
+     * Package locale method returning the Locale's BaseLocale,
+     * used by ResourceBundle
+     * @return base locale of this Locale
+     */
+    BaseLocale getBaseLocale() {
+        return baseLocale;
+    }
+
+    /**
+     * Package private method returning the Locale's LocaleExtensions,
+     * used by ResourceBundle.
+     * @return locale exnteions of this Locale,
+     *         or {@code null} if no extensions are defined
+     */
+     LocaleExtensions getLocaleExtensions() {
+         return localeExtensions;
+     }
+
+    /**
+     * Returns a string representation of this <code>Locale</code>
+     * object, consisting of language, country, variant, script,
+     * and extensions as below:
+     * <blockquote>
+     * language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions
+     * </blockquote>
+     *
+     * Language is always lower case, country is always upper case, script is always title
+     * case, and extensions are always lower case.  Extensions and private use subtags
+     * will be in canonical order as explained in {@link #toLanguageTag}.
+     *
+     * <p>When the locale has neither script nor extensions, the result is the same as in
+     * Java 6 and prior.
+     *
+     * <p>If both the language and country fields are missing, this function will return
+     * the empty string, even if the variant, script, or extensions field is present (you
+     * can't have a locale with just a variant, the variant must accompany a well-formed
+     * language or country code).
+     *
+     * <p>If script or extensions are present and variant is missing, no underscore is
+     * added before the "#".
+     *
+     * <p>This behavior is designed to support debugging and to be compatible with
+     * previous uses of <code>toString</code> that expected language, country, and variant
+     * fields only.  To represent a Locale as a String for interchange purposes, use
+     * {@link #toLanguageTag}.
+     *
+     * <p>Examples: <ul>
+     * <li><tt>en</tt></li>
+     * <li><tt>de_DE</tt></li>
+     * <li><tt>_GB</tt></li>
+     * <li><tt>en_US_WIN</tt></li>
+     * <li><tt>de__POSIX</tt></li>
+     * <li><tt>zh_CN_#Hans</tt></li>
+     * <li><tt>zh_TW_#Hant-x-java</tt></li>
+     * <li><tt>th_TH_TH_#u-nu-thai</tt></li></ul>
+     *
+     * @return A string representation of the Locale, for debugging.
+     * @see #getDisplayName
+     * @see #toLanguageTag
+     */
+    @Override
+    public final String toString() {
+        boolean l = (baseLocale.getLanguage().length() != 0);
+        boolean s = (baseLocale.getScript().length() != 0);
+        boolean r = (baseLocale.getRegion().length() != 0);
+        boolean v = (baseLocale.getVariant().length() != 0);
+        boolean e = (localeExtensions != null && localeExtensions.getID().length() != 0);
+
+        StringBuilder result = new StringBuilder(baseLocale.getLanguage());
+        if (r || (l && (v || s || e))) {
+            result.append('_')
+                .append(baseLocale.getRegion()); // This may just append '_'
+        }
+        if (v && (l || r)) {
+            result.append('_')
+                .append(baseLocale.getVariant());
+        }
+
+        if (s && (l || r)) {
+            result.append("_#")
+                .append(baseLocale.getScript());
+        }
+
+        if (e && (l || r)) {
+            result.append('_');
+            if (!s) {
+                result.append('#');
+            }
+            result.append(localeExtensions.getID());
+        }
+
+        return result.toString();
+    }
+
+    /**
+     * Returns a well-formed IETF BCP 47 language tag representing
+     * this locale.
+     *
+     * <p>If this <code>Locale</code> has a language, country, or
+     * variant that does not satisfy the IETF BCP 47 language tag
+     * syntax requirements, this method handles these fields as
+     * described below:
+     *
+     * <p><b>Language:</b> If language is empty, or not <a
+     * href="#def_language" >well-formed</a> (for example "a" or
+     * "e2"), it will be emitted as "und" (Undetermined).
+     *
+     * <p><b>Country:</b> If country is not <a
+     * href="#def_region">well-formed</a> (for example "12" or "USA"),
+     * it will be omitted.
+     *
+     * <p><b>Variant:</b> If variant <b>is</b> <a
+     * href="#def_variant">well-formed</a>, each sub-segment
+     * (delimited by '-' or '_') is emitted as a subtag.  Otherwise:
+     * <ul>
+     *
+     * <li>if all sub-segments match <code>[0-9a-zA-Z]{1,8}</code>
+     * (for example "WIN" or "Oracle_JDK_Standard_Edition"), the first
+     * ill-formed sub-segment and all following will be appended to
+     * the private use subtag.  The first appended subtag will be
+     * "lvariant", followed by the sub-segments in order, separated by
+     * hyphen. For example, "x-lvariant-WIN",
+     * "Oracle-x-lvariant-JDK-Standard-Edition".
+     *
+     * <li>if any sub-segment does not match
+     * <code>[0-9a-zA-Z]{1,8}</code>, the variant will be truncated
+     * and the problematic sub-segment and all following sub-segments
+     * will be omitted.  If the remainder is non-empty, it will be
+     * emitted as a private use subtag as above (even if the remainder
+     * turns out to be well-formed).  For example,
+     * "Solaris_isjustthecoolestthing" is emitted as
+     * "x-lvariant-Solaris", not as "solaris".</li></ul>
+     *
+     * <p><b>Special Conversions:</b> Java supports some old locale
+     * representations, including deprecated ISO language codes,
+     * for compatibility. This method performs the following
+     * conversions:
+     * <ul>
+     *
+     * <li>Deprecated ISO language codes "iw", "ji", and "in" are
+     * converted to "he", "yi", and "id", respectively.
+     *
+     * <li>A locale with language "no", country "NO", and variant
+     * "NY", representing Norwegian Nynorsk (Norway), is converted
+     * to a language tag "nn-NO".</li></ul>
+     *
+     * <p><b>Note:</b> Although the language tag created by this
+     * method is well-formed (satisfies the syntax requirements
+     * defined by the IETF BCP 47 specification), it is not
+     * necessarily a valid BCP 47 language tag.  For example,
+     * <pre>
+     *   new Locale("xx", "YY").toLanguageTag();</pre>
+     *
+     * will return "xx-YY", but the language subtag "xx" and the
+     * region subtag "YY" are invalid because they are not registered
+     * in the IANA Language Subtag Registry.
+     *
+     * @return a BCP47 language tag representing the locale
+     * @see #forLanguageTag(String)
+     * @since 1.7
+     */
+    public String toLanguageTag() {
+        if (languageTag != null) {
+            return languageTag;
+        }
+
+        LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
+        StringBuilder buf = new StringBuilder();
+
+        String subtag = tag.getLanguage();
+        if (subtag.length() > 0) {
+            buf.append(LanguageTag.canonicalizeLanguage(subtag));
+        }
+
+        subtag = tag.getScript();
+        if (subtag.length() > 0) {
+            buf.append(LanguageTag.SEP);
+            buf.append(LanguageTag.canonicalizeScript(subtag));
+        }
+
+        subtag = tag.getRegion();
+        if (subtag.length() > 0) {
+            buf.append(LanguageTag.SEP);
+            buf.append(LanguageTag.canonicalizeRegion(subtag));
+        }
+
+        List<String>subtags = tag.getVariants();
+        for (String s : subtags) {
+            buf.append(LanguageTag.SEP);
+            // preserve casing
+            buf.append(s);
+        }
+
+        subtags = tag.getExtensions();
+        for (String s : subtags) {
+            buf.append(LanguageTag.SEP);
+            buf.append(LanguageTag.canonicalizeExtension(s));
+        }
+
+        subtag = tag.getPrivateuse();
+        if (subtag.length() > 0) {
+            if (buf.length() > 0) {
+                buf.append(LanguageTag.SEP);
+            }
+            buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
+            // preserve casing
+            buf.append(subtag);
+        }
+
+        String langTag = buf.toString();
+        synchronized (this) {
+            if (languageTag == null) {
+                languageTag = langTag;
+            }
+        }
+        return languageTag;
+    }
+
+    /**
+     * Returns a locale for the specified IETF BCP 47 language tag string.
+     *
+     * <p>If the specified language tag contains any ill-formed subtags,
+     * the first such subtag and all following subtags are ignored.  Compare
+     * to {@link Locale.Builder#setLanguageTag} which throws an exception
+     * in this case.
+     *
+     * <p>The following <b>conversions</b> are performed:<ul>
+     *
+     * <li>The language code "und" is mapped to language "".
+     *
+     * <li>The language codes "he", "yi", and "id" are mapped to "iw",
+     * "ji", and "in" respectively. (This is the same canonicalization
+     * that's done in Locale's constructors.)
+     *
+     * <li>The portion of a private use subtag prefixed by "lvariant",
+     * if any, is removed and appended to the variant field in the
+     * result locale (without case normalization).  If it is then
+     * empty, the private use subtag is discarded:
+     *
+     * <pre>
+     *     Locale loc;
+     *     loc = Locale.forLanguageTag("en-US-x-lvariant-POSIX");
+     *     loc.getVariant(); // returns "POSIX"
+     *     loc.getExtension('x'); // returns null
+     *
+     *     loc = Locale.forLanguageTag("de-POSIX-x-URP-lvariant-Abc-Def");
+     *     loc.getVariant(); // returns "POSIX_Abc_Def"
+     *     loc.getExtension('x'); // returns "urp"
+     * </pre>
+     *
+     * <li>When the languageTag argument contains an extlang subtag,
+     * the first such subtag is used as the language, and the primary
+     * language subtag and other extlang subtags are ignored:
+     *
+     * <pre>
+     *     Locale.forLanguageTag("ar-aao").getLanguage(); // returns "aao"
+     *     Locale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US"
+     * </pre>
+     *
+     * <li>Case is normalized except for variant tags, which are left
+     * unchanged.  Language is normalized to lower case, script to
+     * title case, country to upper case, and extensions to lower
+     * case.
+     *
+     * <li>If, after processing, the locale would exactly match either
+     * ja_JP_JP or th_TH_TH with no extensions, the appropriate
+     * extensions are added as though the constructor had been called:
+     *
+     * <pre>
+     *    Locale.forLanguageTag("ja-JP-x-lvariant-JP").toLanguageTag();
+     *    // returns "ja-JP-u-ca-japanese-x-lvariant-JP"
+     *    Locale.forLanguageTag("th-TH-x-lvariant-TH").toLanguageTag();
+     *    // returns "th-TH-u-nu-thai-x-lvariant-TH"
+     * </pre></ul>
+     *
+     * <p>This implements the 'Language-Tag' production of BCP47, and
+     * so supports grandfathered (regular and irregular) as well as
+     * private use language tags.  Stand alone private use tags are
+     * represented as empty language and extension 'x-whatever',
+     * and grandfathered tags are converted to their canonical replacements
+     * where they exist.
+     *
+     * <p>Grandfathered tags with canonical replacements are as follows:
+     *
+     * <table summary="Grandfathered tags with canonical replacements">
+     * <tbody align="center">
+     * <tr><th>grandfathered tag</th><th>&nbsp;</th><th>modern replacement</th></tr>
+     * <tr><td>art-lojban</td><td>&nbsp;</td><td>jbo</td></tr>
+     * <tr><td>i-ami</td><td>&nbsp;</td><td>ami</td></tr>
+     * <tr><td>i-bnn</td><td>&nbsp;</td><td>bnn</td></tr>
+     * <tr><td>i-hak</td><td>&nbsp;</td><td>hak</td></tr>
+     * <tr><td>i-klingon</td><td>&nbsp;</td><td>tlh</td></tr>
+     * <tr><td>i-lux</td><td>&nbsp;</td><td>lb</td></tr>
+     * <tr><td>i-navajo</td><td>&nbsp;</td><td>nv</td></tr>
+     * <tr><td>i-pwn</td><td>&nbsp;</td><td>pwn</td></tr>
+     * <tr><td>i-tao</td><td>&nbsp;</td><td>tao</td></tr>
+     * <tr><td>i-tay</td><td>&nbsp;</td><td>tay</td></tr>
+     * <tr><td>i-tsu</td><td>&nbsp;</td><td>tsu</td></tr>
+     * <tr><td>no-bok</td><td>&nbsp;</td><td>nb</td></tr>
+     * <tr><td>no-nyn</td><td>&nbsp;</td><td>nn</td></tr>
+     * <tr><td>sgn-BE-FR</td><td>&nbsp;</td><td>sfb</td></tr>
+     * <tr><td>sgn-BE-NL</td><td>&nbsp;</td><td>vgt</td></tr>
+     * <tr><td>sgn-CH-DE</td><td>&nbsp;</td><td>sgg</td></tr>
+     * <tr><td>zh-guoyu</td><td>&nbsp;</td><td>cmn</td></tr>
+     * <tr><td>zh-hakka</td><td>&nbsp;</td><td>hak</td></tr>
+     * <tr><td>zh-min-nan</td><td>&nbsp;</td><td>nan</td></tr>
+     * <tr><td>zh-xiang</td><td>&nbsp;</td><td>hsn</td></tr>
+     * </tbody>
+     * </table>
+     *
+     * <p>Grandfathered tags with no modern replacement will be
+     * converted as follows:
+     *
+     * <table summary="Grandfathered tags with no modern replacement">
+     * <tbody align="center">
+     * <tr><th>grandfathered tag</th><th>&nbsp;</th><th>converts to</th></tr>
+     * <tr><td>cel-gaulish</td><td>&nbsp;</td><td>xtg-x-cel-gaulish</td></tr>
+     * <tr><td>en-GB-oed</td><td>&nbsp;</td><td>en-GB-x-oed</td></tr>
+     * <tr><td>i-default</td><td>&nbsp;</td><td>en-x-i-default</td></tr>
+     * <tr><td>i-enochian</td><td>&nbsp;</td><td>und-x-i-enochian</td></tr>
+     * <tr><td>i-mingo</td><td>&nbsp;</td><td>see-x-i-mingo</td></tr>
+     * <tr><td>zh-min</td><td>&nbsp;</td><td>nan-x-zh-min</td></tr>
+     * </tbody>
+     * </table>
+     *
+     * <p>For a list of all grandfathered tags, see the
+     * IANA Language Subtag Registry (search for "Type: grandfathered").
+     *
+     * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code>
+     * and <code>forLanguageTag</code> will round-trip.
+     *
+     * @param languageTag the language tag
+     * @return The locale that best represents the language tag.
+     * @throws NullPointerException if <code>languageTag</code> is <code>null</code>
+     * @see #toLanguageTag()
+     * @see java.util.Locale.Builder#setLanguageTag(String)
+     * @since 1.7
+     */
+    public static Locale forLanguageTag(String languageTag) {
+        LanguageTag tag = LanguageTag.parse(languageTag, null);
+        InternalLocaleBuilder bldr = new InternalLocaleBuilder();
+        bldr.setLanguageTag(tag);
+        BaseLocale base = bldr.getBaseLocale();
+        LocaleExtensions exts = bldr.getLocaleExtensions();
+        if (exts == null && base.getVariant().length() > 0) {
+            exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),
+                                              base.getRegion(), base.getVariant());
+        }
+        return getInstance(base, exts);
+    }
+
+    /**
+     * Returns a three-letter abbreviation of this locale's language.
+     * If the language matches an ISO 639-1 two-letter code, the
+     * corresponding ISO 639-2/T three-letter lowercase code is
+     * returned.  The ISO 639-2 language codes can be found on-line,
+     * see "Codes for the Representation of Names of Languages Part 2:
+     * Alpha-3 Code".  If the locale specifies a three-letter
+     * language, the language is returned as is.  If the locale does
+     * not specify a language the empty string is returned.
+     *
+     * @return A three-letter abbreviation of this locale's language.
+     * @exception MissingResourceException Throws MissingResourceException if
+     * three-letter language abbreviation is not available for this locale.
+     */
+    public String getISO3Language() throws MissingResourceException {
+        String lang = baseLocale.getLanguage();
+        if (lang.length() == 3) {
+            return lang;
+        }
+        // BEGIN Android-added: app compat: Use "" as ISO3 for empty languages.
+        else if (lang.isEmpty()) {
+            return "";
+        }
+        // END Android-added: app compat: Use "" as ISO3 for empty languages.
+
+        // BEGIN Android-changed: Use ICU.
+        // String language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);
+        // if (language3 == null) {
+        String language3 = ICU.getISO3Language(lang);
+        if (!lang.isEmpty() && language3.isEmpty()) {
+        // END Android-changed: Use ICU.
+            throw new MissingResourceException("Couldn't find 3-letter language code for "
+                    + lang, "FormatData_" + toString(), "ShortLanguage");
+        }
+        return language3;
+    }
+
+    /**
+     * Returns a three-letter abbreviation for this locale's country.
+     * If the country matches an ISO 3166-1 alpha-2 code, the
+     * corresponding ISO 3166-1 alpha-3 uppercase code is returned.
+     * If the locale doesn't specify a country, this will be the empty
+     * string.
+     *
+     * <p>The ISO 3166-1 codes can be found on-line.
+     *
+     * @return A three-letter abbreviation of this locale's country.
+     * @exception MissingResourceException Throws MissingResourceException if the
+     * three-letter country abbreviation is not available for this locale.
+     */
+    public String getISO3Country() throws MissingResourceException {
+        // BEGIN Android-changed: Use ICU. Also, use "" as ISO3 for missing regions.
+        // String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable);
+        // if (country3 == null) {
+        final String region = baseLocale.getRegion();
+        // Note that this will return an UN.M49 region code
+        if (region.length() == 3) {
+            return baseLocale.getRegion();
+        } else if (region.isEmpty()) {
+            return "";
+        }
+
+        // Prefix "en-" because ICU doesn't really care about what the language is.
+        String country3 = ICU.getISO3Country("en-" + region);
+        if (!region.isEmpty() && country3.isEmpty()) {
+        // END Android-changed: Use ICU. Also, use "" as ISO3 for missing regions.
+            throw new MissingResourceException("Couldn't find 3-letter country code for "
+                    + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
+        }
+        return country3;
+    }
+
+    // Android-removed: Use ICU.
+    // getISO3Code() is unused on Android.
+    /*
+    private static String getISO3Code(String iso2Code, String table) {
+        int codeLength = iso2Code.length();
+        if (codeLength == 0) {
+            return "";
+        }
+
+        int tableLength = table.length();
+        int index = tableLength;
+        if (codeLength == 2) {
+            char c1 = iso2Code.charAt(0);
+            char c2 = iso2Code.charAt(1);
+            for (index = 0; index < tableLength; index += 5) {
+                if (table.charAt(index) == c1
+                    && table.charAt(index + 1) == c2) {
+                    break;
+                }
+            }
+        }
+        return index < tableLength ? table.substring(index + 2, index + 5) : null;
+    }
+    */
+
+    /**
+     * Returns a name for the locale's language that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * For example, if the locale is fr_FR and the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale
+     * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
+     * the default {@link Locale.Category#DISPLAY DISPLAY} locale is fr_FR,
+     * getDisplayLanguage() will return "anglais".
+     * If the name returned cannot be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale,
+     * (say, we don't have a Japanese name for Croatian),
+     * this function falls back on the English name, and uses the ISO code as a last-resort
+     * value.  If the locale doesn't specify a language, this function returns the empty string.
+     *
+     * @return The name of the display language.
+     */
+    public final String getDisplayLanguage() {
+        return getDisplayLanguage(getDefault(Category.DISPLAY));
+    }
+
+    // BEGIN Android-changed: Documentation and behavior of getDisplay*().
+    // Use ICU; documentation; backwards compatibility hacks; added private helper methods.
+    /*
+    /**
+     * Returns a name for the locale's language that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized according to inLocale.
+     * For example, if the locale is fr_FR and inLocale
+     * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
+     * inLocale is fr_FR, getDisplayLanguage() will return "anglais".
+     * If the name returned cannot be localized according to inLocale,
+     * (say, we don't have a Japanese name for Croatian),
+     * this function falls back on the English name, and finally
+     * on the ISO code as a last-resort value.  If the locale doesn't specify a language,
+     * this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display language.
+     * @return The name of the display language appropriate to the given locale.
+     * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
+     *
+    public String getDisplayLanguage(Locale inLocale) {
+        return getDisplayString(baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE);
+    }
+    */
+    /**
+     * Returns the name of this locale's language, localized to {@code locale}.
+     * If the language name is unknown, the language code is returned.
+     */
+    public String getDisplayLanguage(Locale locale) {
+        String languageCode = baseLocale.getLanguage();
+        if (languageCode.isEmpty()) {
+            return "";
+        }
+
+        // Hacks for backward compatibility.
+        //
+        // Our language tag will contain "und" if the languageCode is invalid
+        // or missing. ICU will then return "langue indéterminée" or the equivalent
+        // display language for the indeterminate language code.
+        //
+        // Sigh... ugh... and what not.
+        final String normalizedLanguage = normalizeAndValidateLanguage(
+                languageCode, false /* strict */);
+        if (UNDETERMINED_LANGUAGE.equals(normalizedLanguage)) {
+            return languageCode;
+        }
+
+        // TODO: We need a new hack or a complete fix for http://b/8049507 --- We would
+        // cover the frameworks' tracks when they were using "tl" instead of "fil".
+        String result = LocaleNative.getDisplayLanguage(this, locale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayLanguage(this, Locale.getDefault());
+        }
+        return result;
+    }
+
+    private static String normalizeAndValidateLanguage(String language, boolean strict) {
+        if (language == null || language.isEmpty()) {
+            return "";
+        }
+
+        final String lowercaseLanguage = language.toLowerCase(Locale.ROOT);
+        if (!isValidBcp47Alpha(lowercaseLanguage, 2, 3)) {
+            if (strict) {
+                throw new IllformedLocaleException("Invalid language: " + language);
+            } else {
+                return UNDETERMINED_LANGUAGE;
+            }
+        }
+
+        return lowercaseLanguage;
+    }
+
+    /*
+     * Checks whether a given string is an ASCII alphanumeric string.
+     */
+    private static boolean isAsciiAlphaNum(String string) {
+        for (int i = 0; i < string.length(); i++) {
+            final char character = string.charAt(i);
+            if (!(character >= 'a' && character <= 'z' ||
+                    character >= 'A' && character <= 'Z' ||
+                    character >= '0' && character <= '9')) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    // END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Returns a name for the the locale's script that is appropriate for display to
+     * the user. If possible, the name will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.  Returns
+     * the empty string if this locale doesn't specify a script code.
+     *
+     * @return the display name of the script code for the current default
+     *     {@link Locale.Category#DISPLAY DISPLAY} locale
+     * @since 1.7
+     */
+    public String getDisplayScript() {
+        return getDisplayScript(getDefault(Category.DISPLAY));
+    }
+
+    /**
+     * Returns a name for the locale's script that is appropriate
+     * for display to the user. If possible, the name will be
+     * localized for the given locale. Returns the empty string if
+     * this locale doesn't specify a script code.
+     *
+     * @param inLocale The locale for which to retrieve the display script.
+     * @return the display name of the script code for the current default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale
+     * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
+     * @since 1.7
+     */
+    public String getDisplayScript(Locale inLocale) {
+        // BEGIN Android-changed: Use ICU.
+        // return getDisplayString(baseLocale.getScript(), inLocale, DISPLAY_SCRIPT);
+        String scriptCode = baseLocale.getScript();
+        if (scriptCode.isEmpty()) {
+            return "";
+        }
+
+        String result = LocaleNative.getDisplayScript(this, inLocale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayScript(this, Locale.getDefault(Category.DISPLAY));
+        }
+
+        return result;
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Returns a name for the locale's country that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * For example, if the locale is fr_FR and the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale
+     * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
+     * the default {@link Locale.Category#DISPLAY DISPLAY} locale is fr_FR,
+     * getDisplayCountry() will return "Etats-Unis".
+     * If the name returned cannot be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale,
+     * (say, we don't have a Japanese name for Croatia),
+     * this function falls back on the English name, and uses the ISO code as a last-resort
+     * value.  If the locale doesn't specify a country, this function returns the empty string.
+     *
+     * @return The name of the country appropriate to the locale.
+     */
+    public final String getDisplayCountry() {
+        return getDisplayCountry(getDefault(Category.DISPLAY));
+    }
+
+    // BEGIN Android-changed: Documentation and behavior of getDisplay*().
+    // Use ICU; documentation; added private helper methods.
+    /*
+    /**
+     * Returns a name for the locale's country that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized according to inLocale.
+     * For example, if the locale is fr_FR and inLocale
+     * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
+     * inLocale is fr_FR, getDisplayCountry() will return "Etats-Unis".
+     * If the name returned cannot be localized according to inLocale.
+     * (say, we don't have a Japanese name for Croatia),
+     * this function falls back on the English name, and finally
+     * on the ISO code as a last-resort value.  If the locale doesn't specify a country,
+     * this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display country.
+     * @return The name of the country appropriate to the given locale.
+     * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
+     *
+    public String getDisplayCountry(Locale inLocale) {
+        return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY);
+    }
+
+    private String getDisplayString(String code, Locale inLocale, int type) {
+        if (code.length() == 0) {
+            return "";
+        }
+
+        if (inLocale == null) {
+            throw new NullPointerException();
+        }
+
+        LocaleServiceProviderPool pool =
+            LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
+        String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
+        String result = pool.getLocalizedObject(
+                                LocaleNameGetter.INSTANCE,
+                                inLocale, key, type, code);
+            if (result != null) {
+                return result;
+            }
+
+        return code;
+    }
+    */
+    /**
+     * Returns the name of this locale's country, localized to {@code locale}.
+     * Returns the empty string if this locale does not correspond to a specific
+     * country.
+     */
+    public String getDisplayCountry(Locale locale) {
+        String countryCode = baseLocale.getRegion();
+        if (countryCode.isEmpty()) {
+            return "";
+        }
+
+        final String normalizedRegion = normalizeAndValidateRegion(
+                countryCode, false /* strict */);
+        if (normalizedRegion.isEmpty()) {
+            return countryCode;
+        }
+
+        String result = LocaleNative.getDisplayCountry(this, locale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayCountry(this, Locale.getDefault());
+        }
+        return result;
+    }
+
+    private static String normalizeAndValidateRegion(String region, boolean strict) {
+        if (region == null || region.isEmpty()) {
+            return "";
+        }
+
+        final String uppercaseRegion = region.toUpperCase(Locale.ROOT);
+        if (!isValidBcp47Alpha(uppercaseRegion, 2, 2) &&
+                !isUnM49AreaCode(uppercaseRegion)) {
+            if (strict) {
+                throw new IllformedLocaleException("Invalid region: " + region);
+            } else {
+                return "";
+            }
+        }
+
+        return uppercaseRegion;
+    }
+
+    private static boolean isValidBcp47Alpha(String string, int lowerBound, int upperBound) {
+        final int length = string.length();
+        if (length < lowerBound || length > upperBound) {
+            return false;
+        }
+
+        for (int i = 0; i < length; ++i) {
+            final char character = string.charAt(i);
+            if (!(character >= 'a' && character <= 'z' ||
+                    character >= 'A' && character <= 'Z')) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * A UN M.49 is a 3 digit numeric code.
+     */
+    private static boolean isUnM49AreaCode(String code) {
+        if (code.length() != 3) {
+            return false;
+        }
+
+        for (int i = 0; i < 3; ++i) {
+            final char character = code.charAt(i);
+            if (!(character >= '0' && character <= '9')) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    // END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Returns a name for the locale's variant code that is appropriate for display to the
+     * user.  If possible, the name will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.  If the locale
+     * doesn't specify a variant code, this function returns the empty string.
+     *
+     * @return The name of the display variant code appropriate to the locale.
+     */
+    public final String getDisplayVariant() {
+        return getDisplayVariant(getDefault(Category.DISPLAY));
+    }
+
+    /**
+     * Returns a name for the locale's variant code that is appropriate for display to the
+     * user.  If possible, the name will be localized for inLocale.  If the locale
+     * doesn't specify a variant code, this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display variant code.
+     * @return The name of the display variant code appropriate to the given locale.
+     * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
+     */
+    public String getDisplayVariant(Locale inLocale) {
+// BEGIN Android-changed: Documentation and behavior of getDisplay*().
+// Use ICU; added private helper methods.
+/*
+        if (baseLocale.getVariant().length() == 0)
+            return "";
+
+        LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale);
+
+        String names[] = getDisplayVariantArray(inLocale);
+
+        // Get the localized patterns for formatting a list, and use
+        // them to format the list.
+        return formatList(names,
+                          lr.getLocaleName("ListPattern"),
+                          lr.getLocaleName("ListCompositionPattern"));
+    }
+*/
+        String variantCode = baseLocale.getVariant();
+        if (variantCode.isEmpty()) {
+            return "";
+        }
+
+        try {
+            normalizeAndValidateVariant(variantCode);
+        } catch (IllformedLocaleException ilfe) {
+            return variantCode;
+        }
+
+        String result = LocaleNative.getDisplayVariant(this, inLocale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayVariant(this, Locale.getDefault());
+        }
+
+        // The "old style" locale constructors allow us to pass in variants that aren't
+        // valid BCP-47 variant subtags. When that happens, toLanguageTag will not emit
+        // them. Note that we know variantCode.length() > 0 due to the isEmpty check at
+        // the beginning of this function.
+        if (result.isEmpty()) {
+            return variantCode;
+        }
+        return result;
+    }
+
+    private static String normalizeAndValidateVariant(String variant) {
+        if (variant == null || variant.isEmpty()) {
+            return "";
+        }
+
+        // Note that unlike extensions, we canonicalize to lower case alphabets
+        // and underscores instead of hyphens.
+        final String normalizedVariant = variant.replace('-', '_');
+        String[] subTags = normalizedVariant.split("_");
+
+        for (String subTag : subTags) {
+            if (!isValidVariantSubtag(subTag)) {
+                throw new IllformedLocaleException("Invalid variant: " + variant);
+            }
+        }
+
+        return normalizedVariant;
+    }
+
+    private static boolean isValidVariantSubtag(String subTag) {
+        // The BCP-47 spec states that :
+        // - Subtags can be between [5, 8] alphanumeric chars in length.
+        // - Subtags that start with a number are allowed to be 4 chars in length.
+        if (subTag.length() >= 5 && subTag.length() <= 8) {
+            if (isAsciiAlphaNum(subTag)) {
+                return true;
+            }
+        } else if (subTag.length() == 4) {
+            final char firstChar = subTag.charAt(0);
+            if ((firstChar >= '0' && firstChar <= '9') && isAsciiAlphaNum(subTag)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+// END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Returns a name for the locale that is appropriate for display to the
+     * user. This will be the values returned by getDisplayLanguage(),
+     * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled
+     * into a single string. The the non-empty values are used in order,
+     * with the second and subsequent names in parentheses.  For example:
+     * <blockquote>
+     * language (script, country, variant)<br>
+     * language (country)<br>
+     * language (variant)<br>
+     * script (country)<br>
+     * country<br>
+     * </blockquote>
+     * depending on which fields are specified in the locale.  If the
+     * language, script, country, and variant fields are all empty,
+     * this function returns the empty string.
+     *
+     * @return The name of the locale appropriate to display.
+     */
+    public final String getDisplayName() {
+        return getDisplayName(getDefault(Category.DISPLAY));
+    }
+
+    // BEGIN Android-changed: Documentation and behavior of getDisplay*().
+    /*
+    /**
+     * Returns a name for the locale that is appropriate for display
+     * to the user.  This will be the values returned by
+     * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(),
+     * and getDisplayVariant() assembled into a single string.
+     * The non-empty values are used in order,
+     * with the second and subsequent names in parentheses.  For example:
+     * <blockquote>
+     * language (script, country, variant)<br>
+     * language (country)<br>
+     * language (variant)<br>
+     * script (country)<br>
+     * country<br>
+     * </blockquote>
+     * depending on which fields are specified in the locale.  If the
+     * language, script, country, and variant fields are all empty,
+     * this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display name.
+     * @return The name of the locale appropriate to display.
+     * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
+     *
+    public String getDisplayName(Locale inLocale) {
+        LocaleResources lr =  LocaleProviderAdapter.forJRE().getLocaleResources(inLocale);
+
+        String languageName = getDisplayLanguage(inLocale);
+        String scriptName = getDisplayScript(inLocale);
+        String countryName = getDisplayCountry(inLocale);
+        String[] variantNames = getDisplayVariantArray(inLocale);
+
+        // Get the localized patterns for formatting a display name.
+        String displayNamePattern = lr.getLocaleName("DisplayNamePattern");
+        String listPattern = lr.getLocaleName("ListPattern");
+        String listCompositionPattern = lr.getLocaleName("ListCompositionPattern");
+
+        // The display name consists of a main name, followed by qualifiers.
+        // Typically, the format is "MainName (Qualifier, Qualifier)" but this
+        // depends on what pattern is stored in the display locale.
+        String   mainName       = null;
+        String[] qualifierNames = null;
+
+        // The main name is the language, or if there is no language, the script,
+        // then if no script, the country. If there is no language/script/country
+        // (an anomalous situation) then the display name is simply the variant's
+        // display name.
+        if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
+            if (variantNames.length == 0) {
+                return "";
+            } else {
+                return formatList(variantNames, listPattern, listCompositionPattern);
+            }
+        }
+        ArrayList<String> names = new ArrayList<>(4);
+        if (languageName.length() != 0) {
+            names.add(languageName);
+        }
+        if (scriptName.length() != 0) {
+            names.add(scriptName);
+        }
+        if (countryName.length() != 0) {
+            names.add(countryName);
+        }
+        if (variantNames.length != 0) {
+            names.addAll(Arrays.asList(variantNames));
+        }
+
+        // The first one in the main name
+        mainName = names.get(0);
+
+        // Others are qualifiers
+        int numNames = names.size();
+        qualifierNames = (numNames > 1) ?
+                names.subList(1, numNames).toArray(new String[numNames - 1]) : new String[0];
+
+        // Create an array whose first element is the number of remaining
+        // elements.  This serves as a selector into a ChoiceFormat pattern from
+        // the resource.  The second and third elements are the main name and
+        // the qualifier; if there are no qualifiers, the third element is
+        // unused by the format pattern.
+        Object[] displayNames = {
+            new Integer(qualifierNames.length != 0 ? 2 : 1),
+            mainName,
+            // We could also just call formatList() and have it handle the empty
+            // list case, but this is more efficient, and we want it to be
+            // efficient since all the language-only locales will not have any
+            // qualifiers.
+            qualifierNames.length != 0 ? formatList(qualifierNames, listPattern, listCompositionPattern) : null
+        };
+
+        if (displayNamePattern != null) {
+            return new MessageFormat(displayNamePattern).format(displayNames);
+        }
+        else {
+            // If we cannot get the message format pattern, then we use a simple
+            // hard-coded pattern.  This should not occur in practice unless the
+            // installation is missing some core files (FormatData etc.).
+            StringBuilder result = new StringBuilder();
+            result.append((String)displayNames[1]);
+            if (displayNames.length > 2) {
+                result.append(" (");
+                result.append((String)displayNames[2]);
+                result.append(')');
+            }
+            return result.toString();
+        }
+    }
+    */
+    /**
+     * Returns this locale's language name, country name, and variant, localized
+     * to {@code locale}. The exact output form depends on whether this locale
+     * corresponds to a specific language, script, country and variant.
+     *
+     * <p>For example:
+     * <ul>
+     * <li>{@code new Locale("en").getDisplayName(Locale.US)} -> {@code English}
+     * <li>{@code new Locale("en", "US").getDisplayName(Locale.US)} -> {@code English (United States)}
+     * <li>{@code new Locale("en", "US", "POSIX").getDisplayName(Locale.US)} -> {@code English (United States,Computer)}
+     * <li>{@code Locale.forLanguageTag("zh-Hant-CN").getDisplayName(Locale.US)} -> {@code Chinese (Traditional Han,China)}
+     * <li>{@code new Locale("en").getDisplayName(Locale.FRANCE)} -> {@code anglais}
+     * <li>{@code new Locale("en", "US").getDisplayName(Locale.FRANCE)} -> {@code anglais (États-Unis)}
+     * <li>{@code new Locale("en", "US", "POSIX").getDisplayName(Locale.FRANCE)} -> {@code anglais (États-Unis,informatique)}.
+     * </ul>
+     */
+    public String getDisplayName(Locale locale) {
+        int count = 0;
+        StringBuilder buffer = new StringBuilder();
+        String languageCode = baseLocale.getLanguage();
+        if (!languageCode.isEmpty()) {
+            String displayLanguage = getDisplayLanguage(locale);
+            buffer.append(displayLanguage.isEmpty() ? languageCode : displayLanguage);
+            ++count;
+        }
+        String scriptCode = baseLocale.getScript();
+        if (!scriptCode.isEmpty()) {
+            if (count == 1) {
+                buffer.append(" (");
+            }
+            String displayScript = getDisplayScript(locale);
+            buffer.append(displayScript.isEmpty() ? scriptCode : displayScript);
+            ++count;
+        }
+        String countryCode = baseLocale.getRegion();
+        if (!countryCode.isEmpty()) {
+            if (count == 1) {
+                buffer.append(" (");
+            } else if (count == 2) {
+                buffer.append(",");
+            }
+            String displayCountry = getDisplayCountry(locale);
+            buffer.append(displayCountry.isEmpty() ? countryCode : displayCountry);
+            ++count;
+        }
+        String variantCode = baseLocale.getVariant();
+        if (!variantCode.isEmpty()) {
+            if (count == 1) {
+                buffer.append(" (");
+            } else if (count == 2 || count == 3) {
+                buffer.append(",");
+            }
+            String displayVariant = getDisplayVariant(locale);
+            buffer.append(displayVariant.isEmpty() ? variantCode : displayVariant);
+            ++count;
+        }
+        if (count > 1) {
+            buffer.append(")");
+        }
+        return buffer.toString();
+    }
+    // END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Overrides Cloneable.
+     */
+    @Override
+    public Object clone()
+    {
+        try {
+            Locale that = (Locale)super.clone();
+            return that;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Override hashCode.
+     * Since Locales are often used in hashtables, caches the value
+     * for speed.
+     */
+    @Override
+    public int hashCode() {
+        int hc = hashCodeValue;
+        if (hc == 0) {
+            hc = baseLocale.hashCode();
+            if (localeExtensions != null) {
+                hc ^= localeExtensions.hashCode();
+            }
+            hashCodeValue = hc;
+        }
+        return hc;
+    }
+
+    // Overrides
+
+    /**
+     * Returns true if this Locale is equal to another object.  A Locale is
+     * deemed equal to another Locale with identical language, script, country,
+     * variant and extensions, and unequal to all other objects.
+     *
+     * @return true if this Locale is equal to the specified object.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)                      // quick check
+            return true;
+        if (!(obj instanceof Locale))
+            return false;
+        BaseLocale otherBase = ((Locale)obj).baseLocale;
+        if (!baseLocale.equals(otherBase)) {
+            return false;
+        }
+        if (localeExtensions == null) {
+            return ((Locale)obj).localeExtensions == null;
+        }
+        return localeExtensions.equals(((Locale)obj).localeExtensions);
+    }
+
+    // ================= privates =====================================
+
+    private transient BaseLocale baseLocale;
+    private transient LocaleExtensions localeExtensions;
+
+    /**
+     * Calculated hashcode
+     */
+    private transient volatile int hashCodeValue = 0;
+
+    // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+    // private volatile static Locale defaultLocale = initDefault();
+    private static class NoImagePreloadHolder {
+        public volatile static Locale defaultLocale = initDefault();
+    }
+    private volatile static Locale defaultDisplayLocale = null;
+    private volatile static Locale defaultFormatLocale = null;
+
+    private transient volatile String languageTag;
+
+    // BEGIN Android-removed: Private helper getDisplayVariantArray() unused on Android.
+    /*
+    /**
+     * Return an array of the display names of the variant.
+     * @param bundle the ResourceBundle to use to get the display names
+     * @return an array of display names, possible of zero length.
+     *
+    private String[] getDisplayVariantArray(Locale inLocale) {
+        // Split the variant name into tokens separated by '_'.
+        StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_");
+        String[] names = new String[tokenizer.countTokens()];
+
+        // For each variant token, lookup the display name.  If
+        // not found, use the variant name itself.
+        for (int i=0; i<names.length; ++i) {
+            names[i] = getDisplayString(tokenizer.nextToken(),
+                                inLocale, DISPLAY_VARIANT);
+        }
+
+        return names;
+    }
+    */
+    // END Android-removed: Private helper getDisplayVariantArray() unused on Android.
+
+    /**
+     * Format a list using given pattern strings.
+     * If either of the patterns is null, then a the list is
+     * formatted by concatenation with the delimiter ','.
+     * @param stringList the list of strings to be formatted.
+     * @param listPattern should create a MessageFormat taking 0-3 arguments
+     * and formatting them into a list.
+     * @param listCompositionPattern should take 2 arguments
+     * and is used by composeList.
+     * @return a string representing the list.
+     */
+    private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) {
+        // If we have no list patterns, compose the list in a simple,
+        // non-localized way.
+        if (listPattern == null || listCompositionPattern == null) {
+            StringBuilder result = new StringBuilder();
+            for (int i = 0; i < stringList.length; ++i) {
+                if (i > 0) {
+                    result.append(',');
+                }
+                result.append(stringList[i]);
+            }
+            return result.toString();
+        }
+
+        // Compose the list down to three elements if necessary
+        if (stringList.length > 3) {
+            MessageFormat format = new MessageFormat(listCompositionPattern);
+            stringList = composeList(format, stringList);
+        }
+
+        // Rebuild the argument list with the list length as the first element
+        Object[] args = new Object[stringList.length + 1];
+        System.arraycopy(stringList, 0, args, 1, stringList.length);
+        args[0] = new Integer(stringList.length);
+
+        // Format it using the pattern in the resource
+        MessageFormat format = new MessageFormat(listPattern);
+        return format.format(args);
+    }
+
+    /**
+     * Given a list of strings, return a list shortened to three elements.
+     * Shorten it by applying the given format to the first two elements
+     * recursively.
+     * @param format a format which takes two arguments
+     * @param list a list of strings
+     * @return if the list is three elements or shorter, the same list;
+     * otherwise, a new list of three elements.
+     */
+    private static String[] composeList(MessageFormat format, String[] list) {
+        if (list.length <= 3) return list;
+
+        // Use the given format to compose the first two elements into one
+        String[] listItems = { list[0], list[1] };
+        String newItem = format.format(listItems);
+
+        // Form a new list one element shorter
+        String[] newList = new String[list.length-1];
+        System.arraycopy(list, 2, newList, 1, newList.length-1);
+        newList[0] = newItem;
+
+        // Recurse
+        return composeList(format, newList);
+    }
+
+    // Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to
+    // avoid its class loading.
+    private static boolean isUnicodeExtensionKey(String s) {
+        // 2alphanum
+        return (s.length() == 2) && LocaleUtils.isAlphaNumericString(s);
+    }
+
+    /**
+     * @serialField language    String
+     *      language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>)
+     * @serialField country     String
+     *      country subtag in upper case. (See <a href="java/util/Locale.html#getCountry()">getCountry()</a>)
+     * @serialField variant     String
+     *      variant subtags separated by LOWLINE characters. (See <a href="java/util/Locale.html#getVariant()">getVariant()</a>)
+     * @serialField hashcode    int
+     *      deprecated, for forward compatibility only
+     * @serialField script      String
+     *      script subtag in title case (See <a href="java/util/Locale.html#getScript()">getScript()</a>)
+     * @serialField extensions  String
+     *      canonical representation of extensions, that is,
+     *      BCP47 extensions in alphabetical order followed by
+     *      BCP47 private use subtags, all in lower case letters
+     *      separated by HYPHEN-MINUS characters.
+     *      (See <a href="java/util/Locale.html#getExtensionKeys()">getExtensionKeys()</a>,
+     *      <a href="java/util/Locale.html#getExtension(char)">getExtension(char)</a>)
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("language", String.class),
+        new ObjectStreamField("country", String.class),
+        new ObjectStreamField("variant", String.class),
+        new ObjectStreamField("hashcode", int.class),
+        new ObjectStreamField("script", String.class),
+        new ObjectStreamField("extensions", String.class),
+    };
+
+    /**
+     * Serializes this <code>Locale</code> to the specified <code>ObjectOutputStream</code>.
+     * @param out the <code>ObjectOutputStream</code> to write
+     * @throws IOException
+     * @since 1.7
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        ObjectOutputStream.PutField fields = out.putFields();
+        fields.put("language", baseLocale.getLanguage());
+        fields.put("script", baseLocale.getScript());
+        fields.put("country", baseLocale.getRegion());
+        fields.put("variant", baseLocale.getVariant());
+        fields.put("extensions", localeExtensions == null ? "" : localeExtensions.getID());
+        fields.put("hashcode", -1); // place holder just for backward support
+        out.writeFields();
+    }
+
+    /**
+     * Deserializes this <code>Locale</code>.
+     * @param in the <code>ObjectInputStream</code> to read
+     * @throws IOException
+     * @throws ClassNotFoundException
+     * @throws IllformedLocaleException
+     * @since 1.7
+     */
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        ObjectInputStream.GetField fields = in.readFields();
+        String language = (String)fields.get("language", "");
+        String script = (String)fields.get("script", "");
+        String country = (String)fields.get("country", "");
+        String variant = (String)fields.get("variant", "");
+        String extStr = (String)fields.get("extensions", "");
+        baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
+        // Android-changed: Handle null for backwards compatible deserialization. http://b/26387905
+        // if (extStr.length() > 0) {
+        if (extStr != null && extStr.length() > 0) {
+            try {
+                InternalLocaleBuilder bldr = new InternalLocaleBuilder();
+                bldr.setExtensions(extStr);
+                localeExtensions = bldr.getLocaleExtensions();
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage());
+            }
+        } else {
+            localeExtensions = null;
+        }
+    }
+
+    /**
+     * Returns a cached <code>Locale</code> instance equivalent to
+     * the deserialized <code>Locale</code>. When serialized
+     * language, country and variant fields read from the object data stream
+     * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions
+     * fields are empty, this method supplies <code>UNICODE_LOCALE_EXTENSION</code>
+     * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script
+     * type is "thai"). See <a href="Locale.html#special_cases_constructor">Special Cases</a>
+     * for more information.
+     *
+     * @return an instance of <code>Locale</code> equivalent to
+     * the deserialized <code>Locale</code>.
+     * @throws java.io.ObjectStreamException
+     */
+    private Object readResolve() throws java.io.ObjectStreamException {
+        return getInstance(baseLocale.getLanguage(), baseLocale.getScript(),
+                baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions);
+    }
+
+    private static volatile String[] isoLanguages = null;
+
+    private static volatile String[] isoCountries = null;
+
+    private static String convertOldISOCodes(String language) {
+        // we accept both the old and the new ISO codes for the languages whose ISO
+        // codes have changed, but we always store the OLD code, for backward compatibility
+        language = LocaleUtils.toLowerString(language).intern();
+        if (language == "he") {
+            return "iw";
+        } else if (language == "yi") {
+            return "ji";
+        } else if (language == "id") {
+            return "in";
+        } else {
+            return language;
+        }
+    }
+
+    private static LocaleExtensions getCompatibilityExtensions(String language,
+                                                               String script,
+                                                               String country,
+                                                               String variant) {
+        LocaleExtensions extensions = null;
+        // Special cases for backward compatibility support
+        if (LocaleUtils.caseIgnoreMatch(language, "ja")
+                && script.length() == 0
+                && LocaleUtils.caseIgnoreMatch(country, "jp")
+                && "JP".equals(variant)) {
+            // ja_JP_JP -> u-ca-japanese (calendar = japanese)
+            extensions = LocaleExtensions.CALENDAR_JAPANESE;
+        } else if (LocaleUtils.caseIgnoreMatch(language, "th")
+                && script.length() == 0
+                && LocaleUtils.caseIgnoreMatch(country, "th")
+                && "TH".equals(variant)) {
+            // th_TH_TH -> u-nu-thai (numbersystem = thai)
+            extensions = LocaleExtensions.NUMBER_THAI;
+        }
+        return extensions;
+    }
+
+    // Android-removed: Drop nested private class LocaleNameGetter.
+    /*
+    /**
+     * Obtains a localized locale names from a LocaleNameProvider
+     * implementation.
+     *
+    private static class LocaleNameGetter
+        implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
+        private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
+
+        @Override
+        public String getObject(LocaleNameProvider localeNameProvider,
+                                Locale locale,
+                                String key,
+                                Object... params) {
+            assert params.length == 2;
+            int type = (Integer)params[0];
+            String code = (String)params[1];
+
+            switch(type) {
+            case DISPLAY_LANGUAGE:
+                return localeNameProvider.getDisplayLanguage(code, locale);
+            case DISPLAY_COUNTRY:
+                return localeNameProvider.getDisplayCountry(code, locale);
+            case DISPLAY_VARIANT:
+                return localeNameProvider.getDisplayVariant(code, locale);
+            case DISPLAY_SCRIPT:
+                return localeNameProvider.getDisplayScript(code, locale);
+            default:
+                assert false; // shouldn't happen
+            }
+
+            return null;
+        }
+    }
+    */
+
+    // BEGIN Android-added: adjustLanguageCode(), for internal use only.
+    /** @hide for internal use only. */
+    public static String adjustLanguageCode(String languageCode) {
+        String adjusted = languageCode.toLowerCase(Locale.US);
+        // Map new language codes to the obsolete language
+        // codes so the correct resource bundles will be used.
+        if (languageCode.equals("he")) {
+            adjusted = "iw";
+        } else if (languageCode.equals("id")) {
+            adjusted = "in";
+        } else if (languageCode.equals("yi")) {
+            adjusted = "ji";
+        }
+
+        return adjusted;
+    }
+    // END Android-added: adjustLanguageCode(), for internal use only.
+
+    /**
+     * Enum for locale categories.  These locale categories are used to get/set
+     * the default locale for the specific functionality represented by the
+     * category.
+     *
+     * @see #getDefault(Locale.Category)
+     * @see #setDefault(Locale.Category, Locale)
+     * @since 1.7
+     */
+    public enum Category {
+
+        /**
+         * Category used to represent the default locale for
+         * displaying user interfaces.
+         */
+        DISPLAY("user.language.display",
+                "user.script.display",
+                "user.country.display",
+                "user.variant.display"),
+
+        /**
+         * Category used to represent the default locale for
+         * formatting dates, numbers, and/or currencies.
+         */
+        FORMAT("user.language.format",
+               "user.script.format",
+               "user.country.format",
+               "user.variant.format");
+
+        Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
+            this.languageKey = languageKey;
+            this.scriptKey = scriptKey;
+            this.countryKey = countryKey;
+            this.variantKey = variantKey;
+        }
+
+        final String languageKey;
+        final String scriptKey;
+        final String countryKey;
+        final String variantKey;
+    }
+
+    /**
+     * <code>Builder</code> is used to build instances of <code>Locale</code>
+     * from values configured by the setters.  Unlike the <code>Locale</code>
+     * constructors, the <code>Builder</code> checks if a value configured by a
+     * setter satisfies the syntax requirements defined by the <code>Locale</code>
+     * class.  A <code>Locale</code> object created by a <code>Builder</code> is
+     * well-formed and can be transformed to a well-formed IETF BCP 47 language tag
+     * without losing information.
+     *
+     * <p><b>Note:</b> The <code>Locale</code> class does not provide any
+     * syntactic restrictions on variant, while BCP 47 requires each variant
+     * subtag to be 5 to 8 alphanumerics or a single numeric followed by 3
+     * alphanumerics.  The method <code>setVariant</code> throws
+     * <code>IllformedLocaleException</code> for a variant that does not satisfy
+     * this restriction. If it is necessary to support such a variant, use a
+     * Locale constructor.  However, keep in mind that a <code>Locale</code>
+     * object created this way might lose the variant information when
+     * transformed to a BCP 47 language tag.
+     *
+     * <p>The following example shows how to create a <code>Locale</code> object
+     * with the <code>Builder</code>.
+     * <blockquote>
+     * <pre>
+     *     Locale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();
+     * </pre>
+     * </blockquote>
+     *
+     * <p>Builders can be reused; <code>clear()</code> resets all
+     * fields to their default values.
+     *
+     * @see Locale#forLanguageTag
+     * @since 1.7
+     */
+    public static final class Builder {
+        private final InternalLocaleBuilder localeBuilder;
+
+        /**
+         * Constructs an empty Builder. The default value of all
+         * fields, extensions, and private use information is the
+         * empty string.
+         */
+        public Builder() {
+            localeBuilder = new InternalLocaleBuilder();
+        }
+
+        /**
+         * Resets the <code>Builder</code> to match the provided
+         * <code>locale</code>.  Existing state is discarded.
+         *
+         * <p>All fields of the locale must be well-formed, see {@link Locale}.
+         *
+         * <p>Locales with any ill-formed fields cause
+         * <code>IllformedLocaleException</code> to be thrown, except for the
+         * following three cases which are accepted for compatibility
+         * reasons:<ul>
+         * <li>Locale("ja", "JP", "JP") is treated as "ja-JP-u-ca-japanese"
+         * <li>Locale("th", "TH", "TH") is treated as "th-TH-u-nu-thai"
+         * <li>Locale("no", "NO", "NY") is treated as "nn-NO"</ul>
+         *
+         * @param locale the locale
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>locale</code> has
+         * any ill-formed fields.
+         * @throws NullPointerException if <code>locale</code> is null.
+         */
+        public Builder setLocale(Locale locale) {
+            try {
+                localeBuilder.setLocale(locale.baseLocale, locale.localeExtensions);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Resets the Builder to match the provided IETF BCP 47
+         * language tag.  Discards the existing state.  Null and the
+         * empty string cause the builder to be reset, like {@link
+         * #clear}.  Grandfathered tags (see {@link
+         * Locale#forLanguageTag}) are converted to their canonical
+         * form before being processed.  Otherwise, the language tag
+         * must be well-formed (see {@link Locale}) or an exception is
+         * thrown (unlike <code>Locale.forLanguageTag</code>, which
+         * just discards ill-formed and following portions of the
+         * tag).
+         *
+         * @param languageTag the language tag
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>languageTag</code> is ill-formed
+         * @see Locale#forLanguageTag(String)
+         */
+        public Builder setLanguageTag(String languageTag) {
+            ParseStatus sts = new ParseStatus();
+            LanguageTag tag = LanguageTag.parse(languageTag, sts);
+            if (sts.isError()) {
+                throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex());
+            }
+            localeBuilder.setLanguageTag(tag);
+            return this;
+        }
+
+        /**
+         * Sets the language.  If <code>language</code> is the empty string or
+         * null, the language in this <code>Builder</code> is removed.  Otherwise,
+         * the language must be <a href="./Locale.html#def_language">well-formed</a>
+         * or an exception is thrown.
+         *
+         * <p>The typical language value is a two or three-letter language
+         * code as defined in ISO639.
+         *
+         * @param language the language
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>language</code> is ill-formed
+         */
+        public Builder setLanguage(String language) {
+            try {
+                localeBuilder.setLanguage(language);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the script. If <code>script</code> is null or the empty string,
+         * the script in this <code>Builder</code> is removed.
+         * Otherwise, the script must be <a href="./Locale.html#def_script">well-formed</a> or an
+         * exception is thrown.
+         *
+         * <p>The typical script value is a four-letter script code as defined by ISO 15924.
+         *
+         * @param script the script
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>script</code> is ill-formed
+         */
+        public Builder setScript(String script) {
+            try {
+                localeBuilder.setScript(script);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the region.  If region is null or the empty string, the region
+         * in this <code>Builder</code> is removed.  Otherwise,
+         * the region must be <a href="./Locale.html#def_region">well-formed</a> or an
+         * exception is thrown.
+         *
+         * <p>The typical region value is a two-letter ISO 3166 code or a
+         * three-digit UN M.49 area code.
+         *
+         * <p>The country value in the <code>Locale</code> created by the
+         * <code>Builder</code> is always normalized to upper case.
+         *
+         * @param region the region
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>region</code> is ill-formed
+         */
+        public Builder setRegion(String region) {
+            try {
+                localeBuilder.setRegion(region);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the variant.  If variant is null or the empty string, the
+         * variant in this <code>Builder</code> is removed.  Otherwise, it
+         * must consist of one or more <a href="./Locale.html#def_variant">well-formed</a>
+         * subtags, or an exception is thrown.
+         *
+         * <p><b>Note:</b> This method checks if <code>variant</code>
+         * satisfies the IETF BCP 47 variant subtag's syntax requirements,
+         * and normalizes the value to lowercase letters.  However,
+         * the <code>Locale</code> class does not impose any syntactic
+         * restriction on variant, and the variant value in
+         * <code>Locale</code> is case sensitive.  To set such a variant,
+         * use a Locale constructor.
+         *
+         * @param variant the variant
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>variant</code> is ill-formed
+         */
+        public Builder setVariant(String variant) {
+            try {
+                localeBuilder.setVariant(variant);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the extension for the given key. If the value is null or the
+         * empty string, the extension is removed.  Otherwise, the extension
+         * must be <a href="./Locale.html#def_extensions">well-formed</a> or an exception
+         * is thrown.
+         *
+         * <p><b>Note:</b> The key {@link Locale#UNICODE_LOCALE_EXTENSION
+         * UNICODE_LOCALE_EXTENSION} ('u') is used for the Unicode locale extension.
+         * Setting a value for this key replaces any existing Unicode locale key/type
+         * pairs with those defined in the extension.
+         *
+         * <p><b>Note:</b> The key {@link Locale#PRIVATE_USE_EXTENSION
+         * PRIVATE_USE_EXTENSION} ('x') is used for the private use code. To be
+         * well-formed, the value for this key needs only to have subtags of one to
+         * eight alphanumeric characters, not two to eight as in the general case.
+         *
+         * @param key the extension key
+         * @param value the extension value
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>key</code> is illegal
+         * or <code>value</code> is ill-formed
+         * @see #setUnicodeLocaleKeyword(String, String)
+         */
+        public Builder setExtension(char key, String value) {
+            try {
+                localeBuilder.setExtension(key, value);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the Unicode locale keyword type for the given key.  If the type
+         * is null, the Unicode keyword is removed.  Otherwise, the key must be
+         * non-null and both key and type must be <a
+         * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
+         * is thrown.
+         *
+         * <p>Keys and types are converted to lower case.
+         *
+         * <p><b>Note</b>:Setting the 'u' extension via {@link #setExtension}
+         * replaces all Unicode locale keywords with those defined in the
+         * extension.
+         *
+         * @param key the Unicode locale key
+         * @param type the Unicode locale type
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>key</code> or <code>type</code>
+         * is ill-formed
+         * @throws NullPointerException if <code>key</code> is null
+         * @see #setExtension(char, String)
+         */
+        public Builder setUnicodeLocaleKeyword(String key, String type) {
+            try {
+                localeBuilder.setUnicodeLocaleKeyword(key, type);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Adds a unicode locale attribute, if not already present, otherwise
+         * has no effect.  The attribute must not be null and must be <a
+         * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
+         * is thrown.
+         *
+         * @param attribute the attribute
+         * @return This builder.
+         * @throws NullPointerException if <code>attribute</code> is null
+         * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
+         * @see #setExtension(char, String)
+         */
+        public Builder addUnicodeLocaleAttribute(String attribute) {
+            try {
+                localeBuilder.addUnicodeLocaleAttribute(attribute);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Removes a unicode locale attribute, if present, otherwise has no
+         * effect.  The attribute must not be null and must be <a
+         * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
+         * is thrown.
+         *
+         * <p>Attribute comparision for removal is case-insensitive.
+         *
+         * @param attribute the attribute
+         * @return This builder.
+         * @throws NullPointerException if <code>attribute</code> is null
+         * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
+         * @see #setExtension(char, String)
+         */
+        public Builder removeUnicodeLocaleAttribute(String attribute) {
+            // BEGIN Android-added: removeUnicodeLocaleAttribute(null) is documented to throw NPE.
+            // This could probably be contributed back to upstream. http://b/110752069
+            if (attribute == null) {
+                throw new NullPointerException("attribute == null");
+            }
+            // END Android-added: removeUnicodeLocaleAttribute(null) is documented to throw NPE.
+
+            try {
+                localeBuilder.removeUnicodeLocaleAttribute(attribute);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Resets the builder to its initial, empty state.
+         *
+         * @return This builder.
+         */
+        public Builder clear() {
+            localeBuilder.clear();
+            return this;
+        }
+
+        /**
+         * Resets the extensions to their initial, empty state.
+         * Language, script, region and variant are unchanged.
+         *
+         * @return This builder.
+         * @see #setExtension(char, String)
+         */
+        public Builder clearExtensions() {
+            localeBuilder.clearExtensions();
+            return this;
+        }
+
+        /**
+         * Returns an instance of <code>Locale</code> created from the fields set
+         * on this builder.
+         *
+         * <p>This applies the conversions listed in {@link Locale#forLanguageTag}
+         * when constructing a Locale. (Grandfathered tags are handled in
+         * {@link #setLanguageTag}.)
+         *
+         * @return A Locale.
+         */
+        public Locale build() {
+            BaseLocale baseloc = localeBuilder.getBaseLocale();
+            LocaleExtensions extensions = localeBuilder.getLocaleExtensions();
+            if (extensions == null && baseloc.getVariant().length() > 0) {
+                extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),
+                        baseloc.getRegion(), baseloc.getVariant());
+            }
+            return Locale.getInstance(baseloc, extensions);
+        }
+    }
+
+    /**
+     * This enum provides constants to select a filtering mode for locale
+     * matching. Refer to <a href="http://tools.ietf.org/html/rfc4647">RFC 4647
+     * Matching of Language Tags</a> for details.
+     *
+     * <p>As an example, think of two Language Priority Lists each of which
+     * includes only one language range and a set of following language tags:
+     *
+     * <pre>
+     *    de (German)
+     *    de-DE (German, Germany)
+     *    de-Deva (German, in Devanagari script)
+     *    de-Deva-DE (German, in Devanagari script, Germany)
+     *    de-DE-1996 (German, Germany, orthography of 1996)
+     *    de-Latn-DE (German, in Latin script, Germany)
+     *    de-Latn-DE-1996 (German, in Latin script, Germany, orthography of 1996)
+     * </pre>
+     *
+     * The filtering method will behave as follows:
+     *
+     * <table cellpadding=2 summary="Filtering method behavior">
+     * <tr>
+     * <th>Filtering Mode</th>
+     * <th>Language Priority List: {@code "de-DE"}</th>
+     * <th>Language Priority List: {@code "de-*-DE"}</th>
+     * </tr>
+     * <tr>
+     * <td valign=top>
+     * {@link FilteringMode#AUTOSELECT_FILTERING AUTOSELECT_FILTERING}
+     * </td>
+     * <td valign=top>
+     * Performs <em>basic</em> filtering and returns {@code "de-DE"} and
+     * {@code "de-DE-1996"}.
+     * </td>
+     * <td valign=top>
+     * Performs <em>extended</em> filtering and returns {@code "de-DE"},
+     * {@code "de-Deva-DE"}, {@code "de-DE-1996"}, {@code "de-Latn-DE"}, and
+     * {@code "de-Latn-DE-1996"}.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td valign=top>
+     * {@link FilteringMode#EXTENDED_FILTERING EXTENDED_FILTERING}
+     * </td>
+     * <td valign=top>
+     * Performs <em>extended</em> filtering and returns {@code "de-DE"},
+     * {@code "de-Deva-DE"}, {@code "de-DE-1996"}, {@code "de-Latn-DE"}, and
+     * {@code "de-Latn-DE-1996"}.
+     * </td>
+     * <td valign=top>Same as above.</td>
+     * </tr>
+     * <tr>
+     * <td valign=top>
+     * {@link FilteringMode#IGNORE_EXTENDED_RANGES IGNORE_EXTENDED_RANGES}
+     * </td>
+     * <td valign=top>
+     * Performs <em>basic</em> filtering and returns {@code "de-DE"} and
+     * {@code "de-DE-1996"}.
+     * </td>
+     * <td valign=top>
+     * Performs <em>basic</em> filtering and returns {@code null} because
+     * nothing matches.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td valign=top>
+     * {@link FilteringMode#MAP_EXTENDED_RANGES MAP_EXTENDED_RANGES}
+     * </td>
+     * <td valign=top>Same as above.</td>
+     * <td valign=top>
+     * Performs <em>basic</em> filtering and returns {@code "de-DE"} and
+     * {@code "de-DE-1996"} because {@code "de-*-DE"} is mapped to
+     * {@code "de-DE"}.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td valign=top>
+     * {@link FilteringMode#REJECT_EXTENDED_RANGES REJECT_EXTENDED_RANGES}
+     * </td>
+     * <td valign=top>Same as above.</td>
+     * <td valign=top>
+     * Throws {@link IllegalArgumentException} because {@code "de-*-DE"} is
+     * not a valid basic language range.
+     * </td>
+     * </tr>
+     * </table>
+     *
+     * @see #filter(List, Collection, FilteringMode)
+     * @see #filterTags(List, Collection, FilteringMode)
+     *
+     * @since 1.8
+     */
+    public static enum FilteringMode {
+        /**
+         * Specifies automatic filtering mode based on the given Language
+         * Priority List consisting of language ranges. If all of the ranges
+         * are basic, basic filtering is selected. Otherwise, extended
+         * filtering is selected.
+         */
+        AUTOSELECT_FILTERING,
+
+        /**
+         * Specifies extended filtering.
+         */
+        EXTENDED_FILTERING,
+
+        /**
+         * Specifies basic filtering: Note that any extended language ranges
+         * included in the given Language Priority List are ignored.
+         */
+        IGNORE_EXTENDED_RANGES,
+
+        /**
+         * Specifies basic filtering: If any extended language ranges are
+         * included in the given Language Priority List, they are mapped to the
+         * basic language range. Specifically, a language range starting with a
+         * subtag {@code "*"} is treated as a language range {@code "*"}. For
+         * example, {@code "*-US"} is treated as {@code "*"}. If {@code "*"} is
+         * not the first subtag, {@code "*"} and extra {@code "-"} are removed.
+         * For example, {@code "ja-*-JP"} is mapped to {@code "ja-JP"}.
+         */
+        MAP_EXTENDED_RANGES,
+
+        /**
+         * Specifies basic filtering: If any extended language ranges are
+         * included in the given Language Priority List, the list is rejected
+         * and the filtering method throws {@link IllegalArgumentException}.
+         */
+        REJECT_EXTENDED_RANGES
+    };
+
+    /**
+     * This class expresses a <em>Language Range</em> defined in
+     * <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 Matching of
+     * Language Tags</a>. A language range is an identifier which is used to
+     * select language tag(s) meeting specific requirements by using the
+     * mechanisms described in <a href="Locale.html#LocaleMatching">Locale
+     * Matching</a>. A list which represents a user's preferences and consists
+     * of language ranges is called a <em>Language Priority List</em>.
+     *
+     * <p>There are two types of language ranges: basic and extended. In RFC
+     * 4647, the syntax of language ranges is expressed in
+     * <a href="http://tools.ietf.org/html/rfc4234">ABNF</a> as follows:
+     * <blockquote>
+     * <pre>
+     *     basic-language-range    = (1*8ALPHA *("-" 1*8alphanum)) / "*"
+     *     extended-language-range = (1*8ALPHA / "*")
+     *                               *("-" (1*8alphanum / "*"))
+     *     alphanum                = ALPHA / DIGIT
+     * </pre>
+     * </blockquote>
+     * For example, {@code "en"} (English), {@code "ja-JP"} (Japanese, Japan),
+     * {@code "*"} (special language range which matches any language tag) are
+     * basic language ranges, whereas {@code "*-CH"} (any languages,
+     * Switzerland), {@code "es-*"} (Spanish, any regions), and
+     * {@code "zh-Hant-*"} (Traditional Chinese, any regions) are extended
+     * language ranges.
+     *
+     * @see #filter
+     * @see #filterTags
+     * @see #lookup
+     * @see #lookupTag
+     *
+     * @since 1.8
+     */
+    public static final class LanguageRange {
+
+       /**
+        * A constant holding the maximum value of weight, 1.0, which indicates
+        * that the language range is a good fit for the user.
+        */
+        public static final double MAX_WEIGHT = 1.0;
+
+       /**
+        * A constant holding the minimum value of weight, 0.0, which indicates
+        * that the language range is not a good fit for the user.
+        */
+        public static final double MIN_WEIGHT = 0.0;
+
+        private final String range;
+        private final double weight;
+
+        private volatile int hash = 0;
+
+        /**
+         * Constructs a {@code LanguageRange} using the given {@code range}.
+         * Note that no validation is done against the IANA Language Subtag
+         * Registry at time of construction.
+         *
+         * <p>This is equivalent to {@code LanguageRange(range, MAX_WEIGHT)}.
+         *
+         * @param range a language range
+         * @throws NullPointerException if the given {@code range} is
+         *     {@code null}
+         */
+        public LanguageRange(String range) {
+            this(range, MAX_WEIGHT);
+        }
+
+        /**
+         * Constructs a {@code LanguageRange} using the given {@code range} and
+         * {@code weight}. Note that no validation is done against the IANA
+         * Language Subtag Registry at time of construction.
+         *
+         * @param range  a language range
+         * @param weight a weight value between {@code MIN_WEIGHT} and
+         *     {@code MAX_WEIGHT}
+         * @throws NullPointerException if the given {@code range} is
+         *     {@code null}
+         * @throws IllegalArgumentException if the given {@code weight} is less
+         *     than {@code MIN_WEIGHT} or greater than {@code MAX_WEIGHT}
+         */
+        public LanguageRange(String range, double weight) {
+            if (range == null) {
+                throw new NullPointerException();
+            }
+            if (weight < MIN_WEIGHT || weight > MAX_WEIGHT) {
+                throw new IllegalArgumentException("weight=" + weight);
+            }
+
+            range = range.toLowerCase();
+
+            // Do syntax check.
+            boolean isIllFormed = false;
+            String[] subtags = range.split("-");
+            if (isSubtagIllFormed(subtags[0], true)
+                || range.endsWith("-")) {
+                isIllFormed = true;
+            } else {
+                for (int i = 1; i < subtags.length; i++) {
+                    if (isSubtagIllFormed(subtags[i], false)) {
+                        isIllFormed = true;
+                        break;
+                    }
+                }
+            }
+            if (isIllFormed) {
+                throw new IllegalArgumentException("range=" + range);
+            }
+
+            this.range = range;
+            this.weight = weight;
+        }
+
+        private static boolean isSubtagIllFormed(String subtag,
+                                                 boolean isFirstSubtag) {
+            if (subtag.equals("") || subtag.length() > 8) {
+                return true;
+            } else if (subtag.equals("*")) {
+                return false;
+            }
+            char[] charArray = subtag.toCharArray();
+            if (isFirstSubtag) { // ALPHA
+                for (char c : charArray) {
+                    if (c < 'a' || c > 'z') {
+                        return true;
+                    }
+                }
+            } else { // ALPHA / DIGIT
+                for (char c : charArray) {
+                    if (c < '0' || (c > '9' && c < 'a') || c > 'z') {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Returns the language range of this {@code LanguageRange}.
+         *
+         * @return the language range.
+         */
+        public String getRange() {
+            return range;
+        }
+
+        /**
+         * Returns the weight of this {@code LanguageRange}.
+         *
+         * @return the weight value.
+         */
+        public double getWeight() {
+            return weight;
+        }
+
+        /**
+         * Parses the given {@code ranges} to generate a Language Priority List.
+         *
+         * <p>This method performs a syntactic check for each language range in
+         * the given {@code ranges} but doesn't do validation using the IANA
+         * Language Subtag Registry.
+         *
+         * <p>The {@code ranges} to be given can take one of the following
+         * forms:
+         *
+         * <pre>
+         *   "Accept-Language: ja,en;q=0.4"  (weighted list with Accept-Language prefix)
+         *   "ja,en;q=0.4"                   (weighted list)
+         *   "ja,en"                         (prioritized list)
+         * </pre>
+         *
+         * In a weighted list, each language range is given a weight value.
+         * The weight value is identical to the "quality value" in
+         * <a href="http://tools.ietf.org/html/rfc2616">RFC 2616</a>, and it
+         * expresses how much the user prefers  the language. A weight value is
+         * specified after a corresponding language range followed by
+         * {@code ";q="}, and the default weight value is {@code MAX_WEIGHT}
+         * when it is omitted.
+         *
+         * <p>Unlike a weighted list, language ranges in a prioritized list
+         * are sorted in the descending order based on its priority. The first
+         * language range has the highest priority and meets the user's
+         * preference most.
+         *
+         * <p>In either case, language ranges are sorted in descending order in
+         * the Language Priority List based on priority or weight. If a
+         * language range appears in the given {@code ranges} more than once,
+         * only the first one is included on the Language Priority List.
+         *
+         * <p>The returned list consists of language ranges from the given
+         * {@code ranges} and their equivalents found in the IANA Language
+         * Subtag Registry. For example, if the given {@code ranges} is
+         * {@code "Accept-Language: iw,en-us;q=0.7,en;q=0.3"}, the elements in
+         * the list to be returned are:
+         *
+         * <pre>
+         *  <b>Range</b>                                   <b>Weight</b>
+         *    "iw" (older tag for Hebrew)             1.0
+         *    "he" (new preferred code for Hebrew)    1.0
+         *    "en-us" (English, United States)        0.7
+         *    "en" (English)                          0.3
+         * </pre>
+         *
+         * Two language ranges, {@code "iw"} and {@code "he"}, have the same
+         * highest priority in the list. By adding {@code "he"} to the user's
+         * Language Priority List, locale-matching method can find Hebrew as a
+         * matching locale (or language tag) even if the application or system
+         * offers only {@code "he"} as a supported locale (or language tag).
+         *
+         * @param ranges a list of comma-separated language ranges or a list of
+         *     language ranges in the form of the "Accept-Language" header
+         *     defined in <a href="http://tools.ietf.org/html/rfc2616">RFC
+         *     2616</a>
+         * @return a Language Priority List consisting of language ranges
+         *     included in the given {@code ranges} and their equivalent
+         *     language ranges if available. The list is modifiable.
+         * @throws NullPointerException if {@code ranges} is null
+         * @throws IllegalArgumentException if a language range or a weight
+         *     found in the given {@code ranges} is ill-formed
+         */
+        public static List<LanguageRange> parse(String ranges) {
+            return LocaleMatcher.parse(ranges);
+        }
+
+        /**
+         * Parses the given {@code ranges} to generate a Language Priority
+         * List, and then customizes the list using the given {@code map}.
+         * This method is equivalent to
+         * {@code mapEquivalents(parse(ranges), map)}.
+         *
+         * @param ranges a list of comma-separated language ranges or a list
+         *     of language ranges in the form of the "Accept-Language" header
+         *     defined in <a href="http://tools.ietf.org/html/rfc2616">RFC
+         *     2616</a>
+         * @param map a map containing information to customize language ranges
+         * @return a Language Priority List with customization. The list is
+         *     modifiable.
+         * @throws NullPointerException if {@code ranges} is null
+         * @throws IllegalArgumentException if a language range or a weight
+         *     found in the given {@code ranges} is ill-formed
+         * @see #parse(String)
+         * @see #mapEquivalents
+         */
+        public static List<LanguageRange> parse(String ranges,
+                                                Map<String, List<String>> map) {
+            return mapEquivalents(parse(ranges), map);
+        }
+
+        /**
+         * Generates a new customized Language Priority List using the given
+         * {@code priorityList} and {@code map}. If the given {@code map} is
+         * empty, this method returns a copy of the given {@code priorityList}.
+         *
+         * <p>In the map, a key represents a language range whereas a value is
+         * a list of equivalents of it. {@code '*'} cannot be used in the map.
+         * Each equivalent language range has the same weight value as its
+         * original language range.
+         *
+         * <pre>
+         *  An example of map:
+         *    <b>Key</b>                            <b>Value</b>
+         *      "zh" (Chinese)                 "zh",
+         *                                     "zh-Hans"(Simplified Chinese)
+         *      "zh-HK" (Chinese, Hong Kong)   "zh-HK"
+         *      "zh-TW" (Chinese, Taiwan)      "zh-TW"
+         * </pre>
+         *
+         * The customization is performed after modification using the IANA
+         * Language Subtag Registry.
+         *
+         * <p>For example, if a user's Language Priority List consists of five
+         * language ranges ({@code "zh"}, {@code "zh-CN"}, {@code "en"},
+         * {@code "zh-TW"}, and {@code "zh-HK"}), the newly generated Language
+         * Priority List which is customized using the above map example will
+         * consists of {@code "zh"}, {@code "zh-Hans"}, {@code "zh-CN"},
+         * {@code "zh-Hans-CN"}, {@code "en"}, {@code "zh-TW"}, and
+         * {@code "zh-HK"}.
+         *
+         * <p>{@code "zh-HK"} and {@code "zh-TW"} aren't converted to
+         * {@code "zh-Hans-HK"} nor {@code "zh-Hans-TW"} even if they are
+         * included in the Language Priority List. In this example, mapping
+         * is used to clearly distinguish Simplified Chinese and Traditional
+         * Chinese.
+         *
+         * <p>If the {@code "zh"}-to-{@code "zh"} mapping isn't included in the
+         * map, a simple replacement will be performed and the customized list
+         * won't include {@code "zh"} and {@code "zh-CN"}.
+         *
+         * @param priorityList user's Language Priority List
+         * @param map a map containing information to customize language ranges
+         * @return a new Language Priority List with customization. The list is
+         *     modifiable.
+         * @throws NullPointerException if {@code priorityList} is {@code null}
+         * @see #parse(String, Map)
+         */
+        public static List<LanguageRange> mapEquivalents(
+                                              List<LanguageRange>priorityList,
+                                              Map<String, List<String>> map) {
+            return LocaleMatcher.mapEquivalents(priorityList, map);
+        }
+
+        /**
+         * Returns a hash code value for the object.
+         *
+         * @return  a hash code value for this object.
+         */
+        @Override
+        public int hashCode() {
+            if (hash == 0) {
+                int result = 17;
+                result = 37*result + range.hashCode();
+                long bitsWeight = Double.doubleToLongBits(weight);
+                result = 37*result + (int)(bitsWeight ^ (bitsWeight >>> 32));
+                hash = result;
+            }
+            return hash;
+        }
+
+        /**
+         * Compares this object to the specified object. The result is true if
+         * and only if the argument is not {@code null} and is a
+         * {@code LanguageRange} object that contains the same {@code range}
+         * and {@code weight} values as this object.
+         *
+         * @param obj the object to compare with
+         * @return  {@code true} if this object's {@code range} and
+         *     {@code weight} are the same as the {@code obj}'s; {@code false}
+         *     otherwise.
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof LanguageRange)) {
+                return false;
+            }
+            LanguageRange other = (LanguageRange)obj;
+            return hash == other.hash
+                   && range.equals(other.range)
+                   && weight == other.weight;
+        }
+    }
+
+    /**
+     * Returns a list of matching {@code Locale} instances using the filtering
+     * mechanism defined in RFC 4647.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param locales {@code Locale} instances used for matching
+     * @param mode filtering mode
+     * @return a list of {@code Locale} instances for matching language tags
+     *     sorted in descending order based on priority or weight, or an empty
+     *     list if nothing matches. The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code locales}
+     *     is {@code null}
+     * @throws IllegalArgumentException if one or more extended language ranges
+     *     are included in the given list when
+     *     {@link FilteringMode#REJECT_EXTENDED_RANGES} is specified
+     *
+     * @since 1.8
+     */
+    public static List<Locale> filter(List<LanguageRange> priorityList,
+                                      Collection<Locale> locales,
+                                      FilteringMode mode) {
+        return LocaleMatcher.filter(priorityList, locales, mode);
+    }
+
+    /**
+     * Returns a list of matching {@code Locale} instances using the filtering
+     * mechanism defined in RFC 4647. This is equivalent to
+     * {@link #filter(List, Collection, FilteringMode)} when {@code mode} is
+     * {@link FilteringMode#AUTOSELECT_FILTERING}.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param locales {@code Locale} instances used for matching
+     * @return a list of {@code Locale} instances for matching language tags
+     *     sorted in descending order based on priority or weight, or an empty
+     *     list if nothing matches. The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code locales}
+     *     is {@code null}
+     *
+     * @since 1.8
+     */
+    public static List<Locale> filter(List<LanguageRange> priorityList,
+                                      Collection<Locale> locales) {
+        return filter(priorityList, locales, FilteringMode.AUTOSELECT_FILTERING);
+    }
+
+    /**
+     * Returns a list of matching languages tags using the basic filtering
+     * mechanism defined in RFC 4647.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param tags language tags
+     * @param mode filtering mode
+     * @return a list of matching language tags sorted in descending order
+     *     based on priority or weight, or an empty list if nothing matches.
+     *     The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     * @throws IllegalArgumentException if one or more extended language ranges
+     *     are included in the given list when
+     *     {@link FilteringMode#REJECT_EXTENDED_RANGES} is specified
+     *
+     * @since 1.8
+     */
+    public static List<String> filterTags(List<LanguageRange> priorityList,
+                                          Collection<String> tags,
+                                          FilteringMode mode) {
+        return LocaleMatcher.filterTags(priorityList, tags, mode);
+    }
+
+    /**
+     * Returns a list of matching languages tags using the basic filtering
+     * mechanism defined in RFC 4647. This is equivalent to
+     * {@link #filterTags(List, Collection, FilteringMode)} when {@code mode}
+     * is {@link FilteringMode#AUTOSELECT_FILTERING}.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param tags language tags
+     * @return a list of matching language tags sorted in descending order
+     *     based on priority or weight, or an empty list if nothing matches.
+     *     The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     *
+     * @since 1.8
+     */
+    public static List<String> filterTags(List<LanguageRange> priorityList,
+                                          Collection<String> tags) {
+        return filterTags(priorityList, tags, FilteringMode.AUTOSELECT_FILTERING);
+    }
+
+    /**
+     * Returns a {@code Locale} instance for the best-matching language
+     * tag using the lookup mechanism defined in RFC 4647.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param locales {@code Locale} instances used for matching
+     * @return the best matching <code>Locale</code> instance chosen based on
+     *     priority or weight, or {@code null} if nothing matches.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     *
+     * @since 1.8
+     */
+    public static Locale lookup(List<LanguageRange> priorityList,
+                                Collection<Locale> locales) {
+        return LocaleMatcher.lookup(priorityList, locales);
+    }
+
+    /**
+     * Returns the best-matching language tag using the lookup mechanism
+     * defined in RFC 4647.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param tags language tangs used for matching
+     * @return the best matching language tag chosen based on priority or
+     *     weight, or {@code null} if nothing matches.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     *
+     * @since 1.8
+     */
+    public static String lookupTag(List<LanguageRange> priorityList,
+                                   Collection<String> tags) {
+        return LocaleMatcher.lookupTag(priorityList, tags);
+    }
+
+}
diff --git a/java/util/LongSummaryStatistics.java b/java/util/LongSummaryStatistics.java
new file mode 100644
index 0000000..085aa29
--- /dev/null
+++ b/java/util/LongSummaryStatistics.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.stream.Collector;
+
+/**
+ * A state object for collecting statistics such as count, min, max, sum, and
+ * average.
+ *
+ * <p>This class is designed to work with (though does not require)
+ * {@linkplain java.util.stream streams}. For example, you can compute
+ * summary statistics on a stream of longs with:
+ * <pre> {@code
+ * LongSummaryStatistics stats = longStream.collect(LongSummaryStatistics::new,
+ *                                                  LongSummaryStatistics::accept,
+ *                                                  LongSummaryStatistics::combine);
+ * }</pre>
+ *
+ * <p>{@code LongSummaryStatistics} can be used as a
+ * {@linkplain java.util.stream.Stream#collect(Collector)} reduction}
+ * target for a {@linkplain java.util.stream.Stream stream}. For example:
+ *
+ * <pre> {@code
+ * LongSummaryStatistics stats = people.stream()
+ *                                     .collect(Collectors.summarizingLong(Person::getAge));
+ *}</pre>
+ *
+ * This computes, in a single pass, the count of people, as well as the minimum,
+ * maximum, sum, and average of their ages.
+ *
+ * @implNote This implementation is not thread safe. However, it is safe to use
+ * {@link java.util.stream.Collectors#summarizingLong(java.util.function.ToLongFunction)
+ * Collectors.toLongStatistics()} on a parallel stream, because the parallel
+ * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
+ * provides the necessary partitioning, isolation, and merging of results for
+ * safe and efficient parallel execution.
+ *
+ * <p>This implementation does not check for overflow of the sum.
+ * @since 1.8
+ */
+public class LongSummaryStatistics implements LongConsumer, IntConsumer {
+    private long count;
+    private long sum;
+    private long min = Long.MAX_VALUE;
+    private long max = Long.MIN_VALUE;
+
+    /**
+     * Construct an empty instance with zero count, zero sum,
+     * {@code Long.MAX_VALUE} min, {@code Long.MIN_VALUE} max and zero
+     * average.
+     */
+    public LongSummaryStatistics() { }
+
+    /**
+     * Records a new {@code int} value into the summary information.
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(int value) {
+        accept((long) value);
+    }
+
+    /**
+     * Records a new {@code long} value into the summary information.
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(long value) {
+        ++count;
+        sum += value;
+        min = Math.min(min, value);
+        max = Math.max(max, value);
+    }
+
+    /**
+     * Combines the state of another {@code LongSummaryStatistics} into this
+     * one.
+     *
+     * @param other another {@code LongSummaryStatistics}
+     * @throws NullPointerException if {@code other} is null
+     */
+    public void combine(LongSummaryStatistics other) {
+        count += other.count;
+        sum += other.sum;
+        min = Math.min(min, other.min);
+        max = Math.max(max, other.max);
+    }
+
+    /**
+     * Returns the count of values recorded.
+     *
+     * @return the count of values
+     */
+    public final long getCount() {
+        return count;
+    }
+
+    /**
+     * Returns the sum of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return the sum of values, or zero if none
+     */
+    public final long getSum() {
+        return sum;
+    }
+
+    /**
+     * Returns the minimum value recorded, or {@code Long.MAX_VALUE} if no
+     * values have been recorded.
+     *
+     * @return the minimum value, or {@code Long.MAX_VALUE} if none
+     */
+    public final long getMin() {
+        return min;
+    }
+
+    /**
+     * Returns the maximum value recorded, or {@code Long.MIN_VALUE} if no
+     * values have been recorded
+     *
+     * @return the maximum value, or {@code Long.MIN_VALUE} if none
+     */
+    public final long getMax() {
+        return max;
+    }
+
+    /**
+     * Returns the arithmetic mean of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return The arithmetic mean of values, or zero if none
+     */
+    public final double getAverage() {
+        return getCount() > 0 ? (double) getSum() / getCount() : 0.0d;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     */
+    public String toString() {
+        return String.format(
+            "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}",
+            this.getClass().getSimpleName(),
+            getCount(),
+            getSum(),
+            getMin(),
+            getAverage(),
+            getMax());
+    }
+}
diff --git a/java/util/Map.annotated.java b/java/util/Map.annotated.java
new file mode 100644
index 0000000..c19add2
--- /dev/null
+++ b/java/util/Map.annotated.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.util.function.Function;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Map<K, V> {
+
+public int size();
+
+public boolean isEmpty();
+
+public boolean containsKey(@libcore.util.Nullable java.lang.Object key);
+
+public boolean containsValue(@libcore.util.Nullable java.lang.Object value);
+
[email protected] public V get(@libcore.util.Nullable java.lang.Object key);
+
[email protected] public V put(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value);
+
[email protected] public V remove(@libcore.util.Nullable java.lang.Object key);
+
+public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m);
+
+public void clear();
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet();
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values();
+
[email protected] public java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet();
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o);
+
+public int hashCode();
+
[email protected] public default V getOrDefault(@libcore.util.Nullable java.lang.Object key, @libcore.util.Nullable V defaultValue) { throw new RuntimeException("Stub!"); }
+
+public default void forEach(@libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V> action) { throw new RuntimeException("Stub!"); }
+
+public default void replaceAll(@libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V,? extends @libcore.util.NullFromTypeParam V> function) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V putIfAbsent(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public default boolean remove(@libcore.util.Nullable java.lang.Object key, @libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public default boolean replace(@libcore.util.NullFromTypeParam K key, @libcore.util.Nullable V oldValue, @libcore.util.NullFromTypeParam V newValue) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V replace(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V computeIfAbsent(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NullFromTypeParam K,? extends @libcore.util.Nullable V> mappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V computeIfPresent(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V compute(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.Nullable V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V merge(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull V value, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull V,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8, @libcore.util.NonNull K k9, @libcore.util.NonNull V v9) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8, @libcore.util.NonNull K k9, @libcore.util.NonNull V v9, @libcore.util.NonNull K k10, @libcore.util.NonNull V v10) { throw new RuntimeException("Stub!"); }
+
[email protected]
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> ofEntries(@libcore.util.NonNull java.util.Map.Entry<? extends @libcore.util.NonNull K,? extends @libcore.util.NonNull V>... entries) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map.Entry<@libcore.util.NonNull K, @libcore.util.NonNull V> entry(@libcore.util.NonNull K k, @libcore.util.NonNull V v) { throw new RuntimeException("Stub!"); }
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static interface Entry<K, V> {
+
[email protected] public K getKey();
+
[email protected] public V getValue();
+
[email protected] public V setValue(@libcore.util.NullFromTypeParam V value);
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o);
+
+public int hashCode();
+
[email protected] public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.Nullable V>> comparingByKey() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<[email protected] Entry<@libcore.util.Nullable K, @libcore.util.NonNull V>> comparingByValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Comparator<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.Nullable V>> comparingByKey(@libcore.util.NonNull java.util.Comparator<? super @libcore.util.NullFromTypeParam K> cmp) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Comparator<[email protected] Entry<@libcore.util.Nullable K, @libcore.util.NullFromTypeParam V>> comparingByValue(@libcore.util.NonNull java.util.Comparator<? super @libcore.util.NullFromTypeParam V> cmp) { throw new RuntimeException("Stub!"); }
+}
+
+}
diff --git a/java/util/Map.java b/java/util/Map.java
new file mode 100644
index 0000000..ed365ec
--- /dev/null
+++ b/java/util/Map.java
@@ -0,0 +1,1656 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.io.Serializable;
+
+// Android-changed: removed link to collections framework docs
+/**
+ * An object that maps keys to values.  A map cannot contain duplicate keys;
+ * each key can map to at most one value.
+ *
+ * <p>This interface takes the place of the {@code Dictionary} class, which
+ * was a totally abstract class rather than an interface.
+ *
+ * <p>The {@code Map} interface provides three <i>collection views</i>, which
+ * allow a map's contents to be viewed as a set of keys, collection of values,
+ * or set of key-value mappings.  The <i>order</i> of a map is defined as
+ * the order in which the iterators on the map's collection views return their
+ * elements.  Some map implementations, like the {@code TreeMap} class, make
+ * specific guarantees as to their order; others, like the {@code HashMap}
+ * class, do not.
+ *
+ * <p>Note: great care must be exercised if mutable objects are used as map
+ * keys.  The behavior of a map is not specified if the value of an object is
+ * changed in a manner that affects {@code equals} comparisons while the
+ * object is a key in the map.  A special case of this prohibition is that it
+ * is not permissible for a map to contain itself as a key.  While it is
+ * permissible for a map to contain itself as a value, extreme caution is
+ * advised: the {@code equals} and {@code hashCode} methods are no longer
+ * well defined on such a map.
+ *
+ * <p>All general-purpose map implementation classes should provide two
+ * "standard" constructors: a void (no arguments) constructor which creates an
+ * empty map, and a constructor with a single argument of type {@code Map},
+ * which creates a new map with the same key-value mappings as its argument.
+ * In effect, the latter constructor allows the user to copy any map,
+ * producing an equivalent map of the desired class.  There is no way to
+ * enforce this recommendation (as interfaces cannot contain constructors) but
+ * all of the general-purpose map implementations in the JDK comply.
+ *
+ * <p>The "destructive" methods contained in this interface, that is, the
+ * methods that modify the map on which they operate, are specified to throw
+ * {@code UnsupportedOperationException} if this map does not support the
+ * operation.  If this is the case, these methods may, but are not required
+ * to, throw an {@code UnsupportedOperationException} if the invocation would
+ * have no effect on the map.  For example, invoking the {@link #putAll(Map)}
+ * method on an unmodifiable map may, but is not required to, throw the
+ * exception if the map whose mappings are to be "superimposed" is empty.
+ *
+ * <p>Some map implementations have restrictions on the keys and values they
+ * may contain.  For example, some implementations prohibit null keys and
+ * values, and some have restrictions on the types of their keys.  Attempting
+ * to insert an ineligible key or value throws an unchecked exception,
+ * typically {@code NullPointerException} or {@code ClassCastException}.
+ * Attempting to query the presence of an ineligible key or value may throw an
+ * exception, or it may simply return false; some implementations will exhibit
+ * the former behavior and some will exhibit the latter.  More generally,
+ * attempting an operation on an ineligible key or value whose completion
+ * would not result in the insertion of an ineligible element into the map may
+ * throw an exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <p>Many methods in Collections Framework interfaces are defined
+ * in terms of the {@link Object#equals(Object) equals} method.  For
+ * example, the specification for the {@link #containsKey(Object)
+ * containsKey(Object key)} method says: "returns {@code true} if and
+ * only if this map contains a mapping for a key {@code k} such that
+ * {@code (key==null ? k==null : key.equals(k))}." This specification should
+ * <i>not</i> be construed to imply that invoking {@code Map.containsKey}
+ * with a non-null argument {@code key} will cause {@code key.equals(k)} to
+ * be invoked for any key {@code k}.  Implementations are free to
+ * implement optimizations whereby the {@code equals} invocation is avoided,
+ * for example, by first comparing the hash codes of the two keys.  (The
+ * {@link Object#hashCode()} specification guarantees that two objects with
+ * unequal hash codes cannot be equal.)  More generally, implementations of
+ * the various Collections Framework interfaces are free to take advantage of
+ * the specified behavior of underlying {@link Object} methods wherever the
+ * implementor deems it appropriate.
+ *
+ * <p>Some map operations which perform recursive traversal of the map may fail
+ * with an exception for self-referential instances where the map directly or
+ * indirectly contains itself. This includes the {@code clone()},
+ * {@code equals()}, {@code hashCode()} and {@code toString()} methods.
+ * Implementations may optionally handle the self-referential scenario, however
+ * most current implementations do not do so.
+ *
+ * <h2><a id="immutable">Immutable Map Static Factory Methods</a></h2>
+ * <p>The {@link Map#of() Map.of()} and
+ * {@link Map#ofEntries(Map.Entry...) Map.ofEntries()}
+ * static factory methods provide a convenient way to create immutable maps.
+ * The {@code Map}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Keys and values cannot be added,
+ * removed, or updated. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained keys or values are themselves mutable, this may cause the
+ * Map to behave inconsistently or its contents to appear to change.
+ * <li>They disallow {@code null} keys and values. Attempts to create them with
+ * {@code null} keys or values result in {@code NullPointerException}.
+ * <li>They are serializable if all keys and values are serializable.
+ * <li>They reject duplicate keys at creation time. Duplicate keys
+ * passed to a static factory method result in {@code IllegalArgumentException}.
+ * <li>The iteration order of mappings is unspecified and is subject to change.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @see HashMap
+ * @see TreeMap
+ * @see Hashtable
+ * @see SortedMap
+ * @see Collection
+ * @see Set
+ * @since 1.2
+ */
+// Android-changed: fix doc links to Collection#optional-restrictions
+public interface Map<K, V> {
+    // Query Operations
+
+    /**
+     * Returns the number of key-value mappings in this map.  If the
+     * map contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this map contains no key-value mappings.
+     *
+     * @return {@code true} if this map contains no key-value mappings
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the specified
+     * key.  More formally, returns {@code true} if and only if
+     * this map contains a mapping for a key {@code k} such that
+     * {@code Objects.equals(key, k)}.  (There can be
+     * at most one such mapping.)
+     *
+     * @param key key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the specified
+     *         key
+     * @throws ClassCastException if the key is of an inappropriate type for
+     *         this map
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     *         does not permit null keys
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean containsKey(Object key);
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.  More formally, returns {@code true} if and only if
+     * this map contains at least one mapping to a value {@code v} such that
+     * {@code Objects.equals(value, v)}.  This operation
+     * will probably require time linear in the map size for most
+     * implementations of the {@code Map} interface.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified value
+     * @throws ClassCastException if the value is of an inappropriate type for
+     *         this map
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified value is null and this
+     *         map does not permit null values
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean containsValue(Object value);
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that
+     * {@code Objects.equals(key, k)},
+     * then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>If this map permits null values, then a return value of
+     * {@code null} 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 {@code null}.  The {@link #containsKey
+     * containsKey} operation may be used to distinguish these two cases.
+     *
+     * @param key the key whose associated value is to be returned
+     * @return the value to which the specified key is mapped, or
+     *         {@code null} if this map contains no mapping for the key
+     * @throws ClassCastException if the key is of an inappropriate type for
+     *         this map
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     *         does not permit null keys
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    V get(Object key);
+
+    // Modification Operations
+
+    /**
+     * Associates the specified value with the specified key in this map
+     * (optional operation).  If the map previously contained a mapping for
+     * the key, the old value is replaced by the specified value.  (A map
+     * {@code m} is said to contain a mapping for a key {@code k} if and only
+     * if {@link #containsKey(Object) m.containsKey(k)} would return
+     * {@code true}.)
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key},
+     *         if the implementation supports {@code null} values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if the specified key or value is null
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     */
+    V put(K key, V value);
+
+    /**
+     * Removes the mapping for a key from this map if it is present
+     * (optional operation).   More formally, if this map contains a mapping
+     * from key {@code k} to value {@code v} such that
+     * {@code Objects.equals(key, k)}, that mapping
+     * is removed.  (The map can contain at most one such mapping.)
+     *
+     * <p>Returns the value to which this map previously associated the key,
+     * or {@code null} if the map contained no mapping for the key.
+     *
+     * <p>If this map permits null values, then a return value of
+     * {@code null} does not <i>necessarily</i> indicate that the map
+     * contained no mapping for the key; it's also possible that the map
+     * explicitly mapped the key to {@code null}.
+     *
+     * <p>The map will not contain a mapping for the specified key once the
+     * call returns.
+     *
+     * @param key key whose mapping is to be removed from the map
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the key is of an inappropriate type for
+     *         this map
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this
+     *         map does not permit null keys
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    V remove(Object key);
+
+
+    // Bulk Operations
+
+    /**
+     * Copies all of the mappings from the specified map to this map
+     * (optional operation).  The effect of this call is equivalent to that
+     * of calling {@link #put(Object,Object) put(k, v)} on this map once
+     * for each mapping from key {@code k} to value {@code v} in the
+     * specified map.  The behavior of this operation is undefined if the
+     * specified map is modified while the operation is in progress.
+     *
+     * @param m mappings to be stored in this map
+     * @throws UnsupportedOperationException if the {@code putAll} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of a key or value in the
+     *         specified map prevents it from being stored in this map
+     * @throws NullPointerException if the specified map is null, or if
+     *         this map does not permit null keys or values, and the
+     *         specified map contains null keys or values
+     * @throws IllegalArgumentException if some property of a key or value in
+     *         the specified map prevents it from being stored in this map
+     */
+    void putAll(Map<? extends K, ? extends V> m);
+
+    /**
+     * Removes all of the mappings from this map (optional operation).
+     * The map will be empty after this call returns.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} operation
+     *         is not supported by this map
+     */
+    void clear();
+
+
+    // Views
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * @return a set view of the keys contained in this map
+     */
+    Set<K> keySet();
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * @return a collection view of the values contained in this map
+     */
+    Collection<V> values();
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     *
+     * @return a set view of the mappings contained in this map
+     */
+    Set<Map.Entry<K, V>> entrySet();
+
+    /**
+     * A map entry (key-value pair).  The {@code Map.entrySet} method returns
+     * a collection-view of the map, whose elements are of this class.  The
+     * <i>only</i> way to obtain a reference to a map entry is from the
+     * iterator of this collection-view.  These {@code Map.Entry} objects are
+     * valid <i>only</i> for the duration of the iteration; more formally,
+     * the behavior of a map entry is undefined if the backing map has been
+     * modified after the entry was returned by the iterator, except through
+     * the {@code setValue} operation on the map entry.
+     *
+     * @see Map#entrySet()
+     * @since 1.2
+     */
+    interface Entry<K, V> {
+        /**
+         * Returns the key corresponding to this entry.
+         *
+         * @return the key corresponding to this entry
+         * @throws IllegalStateException implementations may, but are not
+         *         required to, throw this exception if the entry has been
+         *         removed from the backing map.
+         */
+        K getKey();
+
+        /**
+         * Returns the value corresponding to this entry.  If the mapping
+         * has been removed from the backing map (by the iterator's
+         * {@code remove} operation), the results of this call are undefined.
+         *
+         * @return the value corresponding to this entry
+         * @throws IllegalStateException implementations may, but are not
+         *         required to, throw this exception if the entry has been
+         *         removed from the backing map.
+         */
+        V getValue();
+
+        /**
+         * 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 {@code remove} operation).
+         *
+         * @param value new value to be stored in this entry
+         * @return old value corresponding to the entry
+         * @throws UnsupportedOperationException if the {@code put} 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 NullPointerException if the backing map does not permit
+         *         null values, and the specified value is null
+         * @throws IllegalArgumentException if some property of this value
+         *         prevents it from being stored in the backing map
+         * @throws IllegalStateException implementations may, but are not
+         *         required to, throw this exception if the entry has been
+         *         removed from the backing map.
+         */
+        V setValue(V value);
+
+        /**
+         * Compares the specified object with this entry for equality.
+         * Returns {@code true} if the given object is also a map entry and
+         * the two entries represent the same mapping.  More formally, two
+         * entries {@code e1} and {@code e2} represent the same mapping
+         * if<pre>
+         *     (e1.getKey()==null ?
+         *      e2.getKey()==null : e1.getKey().equals(e2.getKey()))  &amp;&amp;
+         *     (e1.getValue()==null ?
+         *      e2.getValue()==null : e1.getValue().equals(e2.getValue()))
+         * </pre>
+         * This ensures that the {@code equals} method works properly across
+         * different implementations of the {@code Map.Entry} interface.
+         *
+         * @param o object to be compared for equality with this map entry
+         * @return {@code true} if the specified object is equal to this map
+         *         entry
+         */
+        boolean equals(Object o);
+
+        /**
+         * Returns the hash code value for this map entry.  The hash code
+         * of a map entry {@code e} is defined to be: <pre>
+         *     (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *     (e.getValue()==null ? 0 : e.getValue().hashCode())
+         * </pre>
+         * This ensures that {@code e1.equals(e2)} implies that
+         * {@code e1.hashCode()==e2.hashCode()} for any two Entries
+         * {@code e1} and {@code e2}, as required by the general
+         * contract of {@code Object.hashCode}.
+         *
+         * @return the hash code value for this map entry
+         * @see Object#hashCode()
+         * @see Object#equals(Object)
+         * @see #equals(Object)
+         */
+        int hashCode();
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} in natural order on key.
+         *
+         * <p>The returned comparator is serializable and throws {@link
+         * NullPointerException} when comparing an entry with a null key.
+         *
+         * @param  <K> the {@link Comparable} type of then map keys
+         * @param  <V> the type of the map values
+         * @return a comparator that compares {@link Map.Entry} in natural order on key.
+         * @see Comparable
+         * @since 1.8
+         */
+        public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> comparingByKey() {
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> c1.getKey().compareTo(c2.getKey());
+        }
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} in natural order on value.
+         *
+         * <p>The returned comparator is serializable and throws {@link
+         * NullPointerException} when comparing an entry with null values.
+         *
+         * @param <K> the type of the map keys
+         * @param <V> the {@link Comparable} type of the map values
+         * @return a comparator that compares {@link Map.Entry} in natural order on value.
+         * @see Comparable
+         * @since 1.8
+         */
+        public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K, V>> comparingByValue() {
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> c1.getValue().compareTo(c2.getValue());
+        }
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} by key using the given
+         * {@link Comparator}.
+         *
+         * <p>The returned comparator is serializable if the specified comparator
+         * is also serializable.
+         *
+         * @param  <K> the type of the map keys
+         * @param  <V> the type of the map values
+         * @param  cmp the key {@link Comparator}
+         * @return a comparator that compares {@link Map.Entry} by the key.
+         * @since 1.8
+         */
+        public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
+            Objects.requireNonNull(cmp);
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
+        }
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} by value using the given
+         * {@link Comparator}.
+         *
+         * <p>The returned comparator is serializable if the specified comparator
+         * is also serializable.
+         *
+         * @param  <K> the type of the map keys
+         * @param  <V> the type of the map values
+         * @param  cmp the value {@link Comparator}
+         * @return a comparator that compares {@link Map.Entry} by the value.
+         * @since 1.8
+         */
+        public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
+            Objects.requireNonNull(cmp);
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
+        }
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * {@code true} if the given object is also a map and the two maps
+     * represent the same mappings.  More formally, two maps {@code m1} and
+     * {@code m2} represent the same mappings if
+     * {@code m1.entrySet().equals(m2.entrySet())}.  This ensures that the
+     * {@code equals} method works properly across different implementations
+     * of the {@code Map} interface.
+     *
+     * @param o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map's
+     * {@code entrySet()} view.  This ensures that {@code m1.equals(m2)}
+     * implies that {@code m1.hashCode()==m2.hashCode()} for any two maps
+     * {@code m1} and {@code m2}, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * @return the hash code value for this map
+     * @see Map.Entry#hashCode()
+     * @see Object#equals(Object)
+     * @see #equals(Object)
+     */
+    int hashCode();
+
+    // Defaultable methods
+
+    /**
+     * Returns the value to which the specified key is mapped, or
+     * {@code defaultValue} if this map contains no mapping for the key.
+     *
+     * @implSpec
+     * The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key the key whose associated value is to be returned
+     * @param defaultValue the default mapping of the key
+     * @return the value to which the specified key is mapped, or
+     * {@code defaultValue} if this map contains no mapping for the key
+     * @throws ClassCastException if the key is of an inappropriate type for
+     * this map
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     * does not permit null keys
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return (((v = get(key)) != null) || containsKey(key))
+            ? v
+            : defaultValue;
+    }
+
+    /**
+     * Performs the given action for each entry in this map until all entries
+     * have been processed or the action throws an exception.   Unless
+     * otherwise specified by the implementing class, actions are performed in
+     * the order of entry set iteration (if an iteration order is specified.)
+     * Exceptions thrown by the action are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K, V> entry : map.entrySet())
+     *     action.accept(entry.getKey(), entry.getValue());
+     * }</pre>
+     *
+     * The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param action The action to be performed for each entry
+     * @throws NullPointerException if the specified action is null
+     * @throws ConcurrentModificationException if an entry is found to be
+     * removed during iteration
+     * @since 1.8
+     */
+    default void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        for (Map.Entry<K, V> entry : entrySet()) {
+            K k;
+            V v;
+            try {
+                k = entry.getKey();
+                v = entry.getValue();
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                throw new ConcurrentModificationException(ise);
+            }
+            action.accept(k, v);
+        }
+    }
+
+    /**
+     * Replaces each entry's value with the result of invoking the given
+     * function on that entry until all entries have been processed or the
+     * function throws an exception.  Exceptions thrown by the function are
+     * relayed to the caller.
+     *
+     * @implSpec
+     * <p>The default implementation is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K, V> entry : map.entrySet())
+     *     entry.setValue(function.apply(entry.getKey(), entry.getValue()));
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param function the function to apply to each entry
+     * @throws UnsupportedOperationException if the {@code set} operation
+     * is not supported by this map's entry set iterator.
+     * @throws ClassCastException if the class of a replacement value
+     * prevents it from being stored in this map
+     * @throws NullPointerException if the specified function is null, or the
+     * specified replacement value is null, and this map does not permit null
+     * values
+     * @throws ClassCastException if a replacement value is of an inappropriate
+     *         type for this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if function or a replacement value is null,
+     *         and this map does not permit null keys or values
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of a replacement value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ConcurrentModificationException if an entry is found to be
+     * removed during iteration
+     * @since 1.8
+     */
+    default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        for (Map.Entry<K, V> entry : entrySet()) {
+            K k;
+            V v;
+            try {
+                k = entry.getKey();
+                v = entry.getValue();
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                throw new ConcurrentModificationException(ise);
+            }
+
+            // ise thrown from function is not a cme.
+            v = function.apply(k, v);
+
+            try {
+                entry.setValue(v);
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                throw new ConcurrentModificationException(ise);
+            }
+        }
+    }
+
+    /**
+     * If the specified key is not already associated with a value (or is mapped
+     * to {@code null}) associates it with the given value and returns
+     * {@code null}, else returns the current value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code
+     * map}:
+     *
+     * <pre> {@code
+     * V v = map.get(key);
+     * if (v == null)
+     *     v = map.put(key, value);
+     *
+     * return v;
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the key or value is of an inappropriate
+     *         type for this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V putIfAbsent(K key, V value) {
+        V v = get(key);
+        if (v == null) {
+            v = put(key, value);
+        }
+
+        return v;
+    }
+
+    /**
+     * Removes the entry for the specified key only if it is currently
+     * mapped to the specified value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     *
+     * <pre> {@code
+     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+     *     map.remove(key);
+     *     return true;
+     * } else
+     *     return false;
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value expected to be associated with the specified key
+     * @return {@code true} if the value was removed
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the key or value is of an inappropriate
+     *         type for this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default boolean remove(Object key, Object value) {
+        Object curValue = get(key);
+        if (!Objects.equals(curValue, value) ||
+            (curValue == null && !containsKey(key))) {
+            return false;
+        }
+        remove(key);
+        return true;
+    }
+
+    /**
+     * Replaces the entry for the specified key only if currently
+     * mapped to the specified value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     *
+     * <pre> {@code
+     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+     *     map.put(key, newValue);
+     *     return true;
+     * } else
+     *     return false;
+     * }</pre>
+     *
+     * The default implementation does not throw NullPointerException
+     * for maps that do not support null values if oldValue is null unless
+     * newValue is also null.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is associated
+     * @param oldValue value expected to be associated with the specified key
+     * @param newValue value to be associated with the specified key
+     * @return {@code true} if the value was replaced
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of a specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if a specified key or newValue is null,
+     *         and this map does not permit null keys or values
+     * @throws NullPointerException if oldValue is null and this map does not
+     *         permit null values
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of a specified key
+     *         or value prevents it from being stored in this map
+     * @since 1.8
+     */
+    default boolean replace(K key, V oldValue, V newValue) {
+        Object curValue = get(key);
+        if (!Objects.equals(curValue, oldValue) ||
+            (curValue == null && !containsKey(key))) {
+            return false;
+        }
+        put(key, newValue);
+        return true;
+    }
+
+    /**
+     * Replaces the entry for the specified key only if it is
+     * currently mapped to some value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     *
+     * <pre> {@code
+     * if (map.containsKey(key)) {
+     *     return map.put(key, value);
+     * } else
+     *     return null;
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     * @since 1.8
+     */
+    default V replace(K key, V value) {
+        V curValue;
+        if (((curValue = get(key)) != null) || containsKey(key)) {
+            curValue = put(key, value);
+        }
+        return curValue;
+    }
+
+    /**
+     * If the specified key is not already associated with a value (or is mapped
+     * to {@code null}), attempts to compute its value using the given mapping
+     * function and enters it into this map unless {@code null}.
+     *
+     * <p>If the mapping function returns {@code null}, no mapping is recorded.
+     * If the mapping function itself throws an (unchecked) exception, the
+     * exception is rethrown, and no mapping is recorded.  The most
+     * common usage is to construct a new object serving as an initial
+     * mapped value or memoized result, as in:
+     *
+     * <pre> {@code
+     * map.computeIfAbsent(key, k -> new Value(f(k)));
+     * }</pre>
+     *
+     * <p>Or to implement a multi-value map, {@code Map<K,Collection<V>>},
+     * supporting multiple values per key:
+     *
+     * <pre> {@code
+     * map.computeIfAbsent(key, k -> new HashSet<V>()).add(v);
+     * }</pre>
+     *
+     * <p>The mapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to the following steps for this
+     * {@code map}, then returning the current value or {@code null} if now
+     * absent:
+     *
+     * <pre> {@code
+     * if (map.get(key) == null) {
+     *     V newValue = mappingFunction.apply(key);
+     *     if (newValue != null)
+     *         map.put(key, newValue);
+     * }
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * mapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * mapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * mapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the mapping function is applied once atomically only if the value
+     * is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param mappingFunction the mapping function to compute a value
+     * @return the current (existing or computed) value associated with
+     *         the specified key, or null if the computed value is null
+     * @throws NullPointerException if the specified key is null and
+     *         this map does not support null keys, or the mappingFunction
+     *         is null
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V computeIfAbsent(K key,
+            Function<? super K, ? extends V> mappingFunction) {
+        Objects.requireNonNull(mappingFunction);
+        V v;
+        if ((v = get(key)) == null) {
+            V newValue;
+            if ((newValue = mappingFunction.apply(key)) != null) {
+                put(key, newValue);
+                return newValue;
+            }
+        }
+
+        return v;
+    }
+
+    /**
+     * If the value for the specified key is present and non-null, attempts to
+     * compute a new mapping given the key and its current mapped value.
+     *
+     * <p>If the remapping function returns {@code null}, the mapping is removed.
+     * If the remapping function itself throws an (unchecked) exception, the
+     * exception is rethrown, and the current mapping is left unchanged.
+     *
+     * <p>The remapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}, then returning the current value or
+     * {@code null} if now absent:
+     *
+     * <pre> {@code
+     * if (map.get(key) != null) {
+     *     V oldValue = map.get(key);
+     *     V newValue = remappingFunction.apply(key, oldValue);
+     *     if (newValue != null)
+     *         map.put(key, newValue);
+     *     else
+     *         map.remove(key);
+     * }
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * remapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * remapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the remapping function is applied once atomically only if the
+     * value is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the remapping function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null and
+     *         this map does not support null keys, or the
+     *         remappingFunction is null
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V computeIfPresent(K key,
+            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        V oldValue;
+        if ((oldValue = get(key)) != null) {
+            V newValue = remappingFunction.apply(key, oldValue);
+            if (newValue != null) {
+                put(key, newValue);
+                return newValue;
+            } else {
+                remove(key);
+                return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Attempts to compute a mapping for the specified key and its current
+     * mapped value (or {@code null} if there is no current mapping). For
+     * example, to either create or append a {@code String} msg to a value
+     * mapping:
+     *
+     * <pre> {@code
+     * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}</pre>
+     * (Method {@link #merge merge()} is often simpler to use for such purposes.)
+     *
+     * <p>If the remapping function returns {@code null}, the mapping is removed
+     * (or remains absent if initially absent).  If the remapping function
+     * itself throws an (unchecked) exception, the exception is rethrown, and
+     * the current mapping is left unchanged.
+     *
+     * <p>The remapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}, then returning the current value or
+     * {@code null} if absent:
+     *
+     * <pre> {@code
+     * V oldValue = map.get(key);
+     * V newValue = remappingFunction.apply(key, oldValue);
+     * if (oldValue != null) {
+     *    if (newValue != null)
+     *       map.put(key, newValue);
+     *    else
+     *       map.remove(key);
+     * } else {
+     *    if (newValue != null)
+     *       map.put(key, newValue);
+     *    else
+     *       return null;
+     * }
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * remapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * remapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the remapping function is applied once atomically only if the
+     * value is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the remapping function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null and
+     *         this map does not support null keys, or the
+     *         remappingFunction is null
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V compute(K key,
+            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        V oldValue = get(key);
+
+        V newValue = remappingFunction.apply(key, oldValue);
+        if (newValue == null) {
+            // delete mapping
+            if (oldValue != null || containsKey(key)) {
+                // something to remove
+                remove(key);
+                return null;
+            } else {
+                // nothing to do. Leave things as they were.
+                return null;
+            }
+        } else {
+            // add or replace old mapping
+            put(key, newValue);
+            return newValue;
+        }
+    }
+
+    /**
+     * If the specified key is not already associated with a value or is
+     * associated with null, associates it with the given non-null value.
+     * Otherwise, replaces the associated value with the results of the given
+     * remapping function, or removes if the result is {@code null}. This
+     * method may be of use when combining multiple mapped values for a key.
+     * For example, to either create or append a {@code String msg} to a
+     * value mapping:
+     *
+     * <pre> {@code
+     * map.merge(key, msg, String::concat)
+     * }</pre>
+     *
+     * <p>If the remapping function returns {@code null}, the mapping is removed.
+     * If the remapping function itself throws an (unchecked) exception, the
+     * exception is rethrown, and the current mapping is left unchanged.
+     *
+     * <p>The remapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}, then returning the current value or
+     * {@code null} if absent:
+     *
+     * <pre> {@code
+     * V oldValue = map.get(key);
+     * V newValue = (oldValue == null) ? value :
+     *              remappingFunction.apply(oldValue, value);
+     * if (newValue == null)
+     *     map.remove(key);
+     * else
+     *     map.put(key, newValue);
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * remapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * remapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the remapping function is applied once atomically only if the
+     * value is not present.
+     *
+     * @param key key with which the resulting value is to be associated
+     * @param value the non-null value to be merged with the existing value
+     *        associated with the key or, if no existing value or a null value
+     *        is associated with the key, to be associated with the key
+     * @param remappingFunction the remapping function to recompute a value if
+     *        present
+     * @return the new value associated with the specified key, or null if no
+     *         value is associated with the key
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     *         does not support null keys or the value or remappingFunction is
+     *         null
+     * @since 1.8
+     */
+    default V merge(K key, V value,
+            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        Objects.requireNonNull(value);
+        V oldValue = get(key);
+        V newValue = (oldValue == null) ? value :
+                   remappingFunction.apply(oldValue, value);
+        if (newValue == null) {
+            remove(key);
+        } else {
+            put(key, newValue);
+        }
+        return newValue;
+    }
+
+    /**
+     * Returns an immutable map containing zero mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @return an empty {@code Map}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of() {
+        return ImmutableCollections.Map0.instance();
+    }
+
+    /**
+     * Returns an immutable map containing a single mapping.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the mapping's key
+     * @param v1 the mapping's value
+     * @return a {@code Map} containing the specified mapping
+     * @throws NullPointerException if the key or the value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1) {
+        return new ImmutableCollections.Map1<>(k1, v1);
+    }
+
+    /**
+     * Returns an immutable map containing two mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if the keys are duplicates
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
+    }
+
+    /**
+     * Returns an immutable map containing three mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3);
+    }
+
+    /**
+     * Returns an immutable map containing four mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4);
+    }
+
+    /**
+     * Returns an immutable map containing five mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
+    }
+
+    /**
+     * Returns an immutable map containing six mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6);
+    }
+
+    /**
+     * Returns an immutable map containing seven mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7);
+    }
+
+    /**
+     * Returns an immutable map containing eight mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8);
+    }
+
+    /**
+     * Returns an immutable map containing nine mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8, k9, v9);
+    }
+
+    /**
+     * Returns an immutable map containing ten mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @param k10 the tenth mapping's key
+     * @param v10 the tenth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
+    }
+
+    /**
+     * Returns an immutable map containing keys and values extracted from the given entries.
+     * The entries themselves are not stored in the map.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * It is convenient to create the map entries using the {@link Map#entry Map.entry()} method.
+     * For example,
+     *
+     * <pre>{@code
+     *     import static java.util.Map.entry;
+     *
+     *     Map<Integer,String> map = Map.ofEntries(
+     *         entry(1, "a"),
+     *         entry(2, "b"),
+     *         entry(3, "c"),
+     *         ...
+     *         entry(26, "z"));
+     * }</pre>
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param entries {@code Map.Entry}s containing the keys and values from which the map is populated
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any entry, key, or value is {@code null}, or if
+     *         the {@code entries} array is {@code null}
+     *
+     * @see Map#entry Map.entry()
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
+        if (entries.length == 0) { // implicit null check of entries
+            return ImmutableCollections.Map0.instance();
+        } else if (entries.length == 1) {
+            return new ImmutableCollections.Map1<>(entries[0].getKey(),
+                                                   entries[0].getValue());
+        } else {
+            Object[] kva = new Object[entries.length << 1];
+            int a = 0;
+            for (Entry<? extends K, ? extends V> entry : entries) {
+                kva[a++] = entry.getKey();
+                kva[a++] = entry.getValue();
+            }
+            return new ImmutableCollections.MapN<>(kva);
+        }
+    }
+
+    /**
+     * Returns an immutable {@link Entry} containing the given key and value.
+     * These entries are suitable for populating {@code Map} instances using the
+     * {@link Map#ofEntries Map.ofEntries()} method.
+     * The {@code Entry} instances created by this method have the following characteristics:
+     *
+     * <ul>
+     * <li>They disallow {@code null} keys and values. Attempts to create them using a {@code null}
+     * key or value result in {@code NullPointerException}.
+     * <li>They are immutable. Calls to {@link Entry#setValue Entry.setValue()}
+     * on a returned {@code Entry} result in {@code UnsupportedOperationException}.
+     * <li>They are not serializable.
+     * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+     * Callers should make no assumptions about the identity of the returned instances.
+     * This method is free to create new instances or reuse existing ones. Therefore,
+     * identity-sensitive operations on these instances (reference equality ({@code ==}),
+     * identity hash code, and synchronization) are unreliable and should be avoided.
+     * </ul>
+     *
+     * @apiNote
+     * For a serializable {@code Entry}, see {@link AbstractMap.SimpleEntry} or
+     * {@link AbstractMap.SimpleImmutableEntry}.
+     *
+     * @param <K> the key's type
+     * @param <V> the value's type
+     * @param k the key
+     * @param v the value
+     * @return an {@code Entry} containing the specified key and value
+     * @throws NullPointerException if the key or value is {@code null}
+     *
+     * @see Map#ofEntries Map.ofEntries()
+     * @since 9
+     */
+    static <K, V> Entry<K, V> entry(K k, V v) {
+        // KeyValueHolder checks for nulls
+        return new KeyValueHolder<>(k, v);
+    }
+}
diff --git a/java/util/MissingFormatArgumentException.java b/java/util/MissingFormatArgumentException.java
new file mode 100644
index 0000000..79b04a3
--- /dev/null
+++ b/java/util/MissingFormatArgumentException.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when there is a format specifier which does not
+ * have a corresponding argument or if an argument index refers to an argument
+ * that does not exist.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class MissingFormatArgumentException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 19190115L;
+
+    private String s;
+
+    /**
+     * Constructs an instance of this class with the unmatched format
+     * specifier.
+     *
+     * @param  s
+     *         Format specifier which does not have a corresponding argument
+     */
+    public MissingFormatArgumentException(String s) {
+        if (s == null)
+            throw new NullPointerException();
+        this.s = s;
+    }
+
+    /**
+     * Returns the unmatched format specifier.
+     *
+     * @return  The unmatched format specifier
+     */
+    public String getFormatSpecifier() {
+        return s;
+    }
+
+    public String getMessage() {
+        return "Format specifier '" + s + "'";
+    }
+}
diff --git a/java/util/MissingFormatWidthException.java b/java/util/MissingFormatWidthException.java
new file mode 100644
index 0000000..9650fe2
--- /dev/null
+++ b/java/util/MissingFormatWidthException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the format width is required.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class MissingFormatWidthException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 15560123L;
+
+    private String s;
+
+    /**
+     * Constructs an instance of this class with the specified format
+     * specifier.
+     *
+     * @param  s
+     *         The format specifier which does not have a width
+     */
+    public MissingFormatWidthException(String s) {
+        if (s == null)
+            throw new NullPointerException();
+        this.s = s;
+    }
+
+    /**
+     * Returns the format specifier which does not have a width.
+     *
+     * @return  The format specifier which does not have a width
+     */
+    public String getFormatSpecifier() {
+        return s;
+    }
+
+    public String getMessage() {
+        return s;
+    }
+}
diff --git a/java/util/MissingResourceException.java b/java/util/MissingResourceException.java
new file mode 100644
index 0000000..4586480
--- /dev/null
+++ b/java/util/MissingResourceException.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+/**
+ * Signals that a resource is missing.
+ * @see java.lang.Exception
+ * @see ResourceBundle
+ * @author      Mark Davis
+ * @since       JDK1.1
+ */
+public
+class MissingResourceException extends RuntimeException {
+
+    /**
+     * Constructs a MissingResourceException with the specified information.
+     * A detail message is a String that describes this particular exception.
+     * @param s the detail message
+     * @param className the name of the resource class
+     * @param key the key for the missing resource.
+     */
+    public MissingResourceException(String s, String className, String key) {
+        super(s);
+        this.className = className;
+        this.key = key;
+    }
+
+    /**
+     * Constructs a <code>MissingResourceException</code> with
+     * <code>message</code>, <code>className</code>, <code>key</code>,
+     * and <code>cause</code>. This constructor is package private for
+     * use by <code>ResourceBundle.getBundle</code>.
+     *
+     * @param message
+     *        the detail message
+     * @param className
+     *        the name of the resource class
+     * @param key
+     *        the key for the missing resource.
+     * @param cause
+     *        the cause (which is saved for later retrieval by the
+     *        {@link Throwable.getCause()} method). (A null value is
+     *        permitted, and indicates that the cause is nonexistent
+     *        or unknown.)
+     */
+    MissingResourceException(String message, String className, String key, Throwable cause) {
+        super(message, cause);
+        this.className = className;
+        this.key = key;
+    }
+
+    /**
+     * Gets parameter passed by constructor.
+     *
+     * @return the name of the resource class
+     */
+    public String getClassName() {
+        return className;
+    }
+
+    /**
+     * Gets parameter passed by constructor.
+     *
+     * @return the key for the missing resource
+     */
+    public String getKey() {
+        return key;
+    }
+
+    //============ privates ============
+
+    // serialization compatibility with JDK1.1
+    private static final long serialVersionUID = -4876345176062000401L;
+
+    /**
+     * The class name of the resource bundle requested by the user.
+     * @serial
+     */
+    private String className;
+
+    /**
+     * The name of the specific resource requested by the user.
+     * @serial
+     */
+    private String key;
+}
diff --git a/java/util/NavigableMap.annotated.java b/java/util/NavigableMap.annotated.java
new file mode 100644
index 0000000..e3f4afb
--- /dev/null
+++ b/java/util/NavigableMap.annotated.java
@@ -0,0 +1,84 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Josh Bloch with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface NavigableMap<K, V> extends java.util.SortedMap<K,V> {
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> lowerEntry(@libcore.util.NullFromTypeParam K key);
+
[email protected] public K lowerKey(@libcore.util.NullFromTypeParam K key);
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> floorEntry(@libcore.util.NullFromTypeParam K key);
+
[email protected] public K floorKey(@libcore.util.NullFromTypeParam K key);
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> ceilingEntry(@libcore.util.NullFromTypeParam K key);
+
[email protected] public K ceilingKey(@libcore.util.NullFromTypeParam K key);
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> higherEntry(@libcore.util.NullFromTypeParam K key);
+
[email protected] public K higherKey(@libcore.util.NullFromTypeParam K key);
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> firstEntry();
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> lastEntry();
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> pollFirstEntry();
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> pollLastEntry();
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> descendingMap();
+
[email protected] public java.util.NavigableSet<@libcore.util.NullFromTypeParam K> navigableKeySet();
+
[email protected] public java.util.NavigableSet<@libcore.util.NullFromTypeParam K> descendingKeySet();
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> subMap(@libcore.util.NullFromTypeParam K fromKey, boolean fromInclusive, @libcore.util.NullFromTypeParam K toKey, boolean toInclusive);
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> headMap(@libcore.util.NullFromTypeParam K toKey, boolean inclusive);
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> tailMap(@libcore.util.NullFromTypeParam K fromKey, boolean inclusive);
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> subMap(@libcore.util.NullFromTypeParam K fromKey, @libcore.util.NullFromTypeParam K toKey);
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> headMap(@libcore.util.NullFromTypeParam K toKey);
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> tailMap(@libcore.util.NullFromTypeParam K fromKey);
+}
diff --git a/java/util/NavigableMap.java b/java/util/NavigableMap.java
new file mode 100644
index 0000000..66b57c7
--- /dev/null
+++ b/java/util/NavigableMap.java
@@ -0,0 +1,426 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Josh Bloch with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A {@link SortedMap} extended with navigation methods returning the
+ * closest matches for given search targets. Methods
+ * {@link #lowerEntry}, {@link #floorEntry}, {@link #ceilingEntry},
+ * and {@link #higherEntry} return {@code Map.Entry} objects
+ * associated with keys respectively less than, less than or equal,
+ * greater than or equal, and greater than a given key, returning
+ * {@code null} if there is no such key.  Similarly, methods
+ * {@link #lowerKey}, {@link #floorKey}, {@link #ceilingKey}, and
+ * {@link #higherKey} return only the associated keys. All of these
+ * methods are designed for locating, not traversing entries.
+ *
+ * <p>A {@code NavigableMap} may be accessed and traversed in either
+ * ascending or descending key order.  The {@link #descendingMap}
+ * method returns a view of the map with the senses of all relational
+ * and directional methods inverted. The performance of ascending
+ * operations and views is likely to be faster than that of descending
+ * ones.  Methods
+ * {@link #subMap(Object, boolean, Object, boolean) subMap(K, boolean, K, boolean)},
+ * {@link #headMap(Object, boolean) headMap(K, boolean)}, and
+ * {@link #tailMap(Object, boolean) tailMap(K, boolean)}
+ * differ from the like-named {@code SortedMap} methods in accepting
+ * additional arguments describing whether lower and upper bounds are
+ * inclusive versus exclusive.  Submaps of any {@code NavigableMap}
+ * must implement the {@code NavigableMap} interface.
+ *
+ * <p>This interface additionally defines methods {@link #firstEntry},
+ * {@link #pollFirstEntry}, {@link #lastEntry}, and
+ * {@link #pollLastEntry} that return and/or remove the least and
+ * greatest mappings, if any exist, else returning {@code null}.
+ *
+ * <p>Implementations of entry-returning methods are expected to
+ * return {@code Map.Entry} pairs representing snapshots of mappings
+ * at the time they were produced, and thus generally do <em>not</em>
+ * support the optional {@code Entry.setValue} method. Note however
+ * that it is possible to change mappings in the associated map using
+ * method {@code put}.
+ *
+ * <p>Methods
+ * {@link #subMap(Object, Object) subMap(K, K)},
+ * {@link #headMap(Object) headMap(K)}, and
+ * {@link #tailMap(Object) tailMap(K)}
+ * are specified to return {@code SortedMap} to allow existing
+ * implementations of {@code SortedMap} to be compatibly retrofitted to
+ * implement {@code NavigableMap}, but extensions and implementations
+ * of this interface are encouraged to override these methods to return
+ * {@code NavigableMap}.  Similarly,
+ * {@link #keySet()} can be overridden to return {@link NavigableSet}.
+ *
+ * @author Doug Lea
+ * @author Josh Bloch
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 1.6
+ */
+public interface NavigableMap<K,V> extends SortedMap<K,V> {
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * strictly less than the given key, or {@code null} if there is
+     * no such key.
+     *
+     * @param key the key
+     * @return an entry with the greatest key less than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> lowerEntry(K key);
+
+    /**
+     * Returns the greatest key strictly less than the given key, or
+     * {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the greatest key less than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K lowerKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * less than or equal to the given key, or {@code null} if there
+     * is no such key.
+     *
+     * @param key the key
+     * @return an entry with the greatest key less than or equal to
+     *         {@code key}, or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> floorEntry(K key);
+
+    /**
+     * Returns the greatest key less than or equal to the given key,
+     * or {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the greatest key less than or equal to {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K floorKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * greater than or equal to the given key, or {@code null} if
+     * there is no such key.
+     *
+     * @param key the key
+     * @return an entry with the least key greater than or equal to
+     *         {@code key}, or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> ceilingEntry(K key);
+
+    /**
+     * Returns the least key greater than or equal to the given key,
+     * or {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the least key greater than or equal to {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K ceilingKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * strictly greater than the given key, or {@code null} if there
+     * is no such key.
+     *
+     * @param key the key
+     * @return an entry with the least key greater than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> higherEntry(K key);
+
+    /**
+     * Returns the least key strictly greater than the given key, or
+     * {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the least key greater than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K higherKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the least
+     * key in this map, or {@code null} if the map is empty.
+     *
+     * @return an entry with the least key,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> firstEntry();
+
+    /**
+     * Returns a key-value mapping associated with the greatest
+     * key in this map, or {@code null} if the map is empty.
+     *
+     * @return an entry with the greatest key,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> lastEntry();
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the least key in this map, or {@code null} if the map is empty.
+     *
+     * @return the removed first entry of this map,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> pollFirstEntry();
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the greatest key in this map, or {@code null} if the map is empty.
+     *
+     * @return the removed last entry of this map,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> pollLastEntry();
+
+    /**
+     * Returns a reverse order view of the mappings contained in this map.
+     * The descending map is backed by this map, so changes to the map are
+     * reflected in the descending map, and vice-versa.  If either map is
+     * modified while an iteration over a collection view of either map
+     * is in progress (except through the iterator's own {@code remove}
+     * operation), the results of the iteration are undefined.
+     *
+     * <p>The returned map has an ordering equivalent to
+     * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code m.descendingMap().descendingMap()} returns a
+     * view of {@code m} essentially equivalent to {@code m}.
+     *
+     * @return a reverse order view of this map
+     */
+    NavigableMap<K,V> descendingMap();
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are reflected in
+     * the set, and vice-versa.  If the map is modified while an iteration
+     * over the set is in progress (except through the iterator's own {@code
+     * remove} operation), the results of the iteration are undefined.  The
+     * set supports element removal, which removes the corresponding mapping
+     * from the map, via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear} operations.
+     * It does not support the {@code add} or {@code addAll} operations.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    NavigableSet<K> navigableKeySet();
+
+    /**
+     * Returns a reverse order {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in descending order.
+     * The set is backed by the map, so changes to the map are reflected in
+     * the set, and vice-versa.  If the map is modified while an iteration
+     * over the set is in progress (except through the iterator's own {@code
+     * remove} operation), the results of the iteration are undefined.  The
+     * set supports element removal, which removes the corresponding mapping
+     * from the map, via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear} operations.
+     * It does not support the {@code add} or {@code addAll} operations.
+     *
+     * @return a reverse order navigable set view of the keys in this map
+     */
+    NavigableSet<K> descendingKeySet();
+
+    /**
+     * Returns a view of the portion of this map whose keys range from
+     * {@code fromKey} to {@code toKey}.  If {@code fromKey} and
+     * {@code toKey} are equal, the returned map is empty unless
+     * {@code fromInclusive} and {@code toInclusive} are both true.  The
+     * returned map is backed by this map, so changes in the returned map are
+     * reflected in this map, and vice-versa.  The returned map supports all
+     * optional map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside of its range, or to construct a
+     * submap either of whose endpoints lie outside its range.
+     *
+     * @param fromKey low endpoint of the keys in the returned map
+     * @param fromInclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @param toKey high endpoint of the keys in the returned map
+     * @param toInclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this map whose keys range from
+     *         {@code fromKey} to {@code toKey}
+     * @throws ClassCastException if {@code fromKey} and {@code toKey}
+     *         cannot be compared to one another using this map's comparator
+     *         (or, if the map has no comparator, using natural ordering).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} or {@code toKey}
+     *         cannot be compared to keys currently in the map.
+     * @throws NullPointerException if {@code fromKey} or {@code toKey}
+     *         is null and this map does not permit null keys
+     * @throws IllegalArgumentException if {@code fromKey} is greater than
+     *         {@code toKey}; or if this map itself has a restricted
+     *         range, and {@code fromKey} or {@code toKey} lies
+     *         outside the bounds of the range
+     */
+    NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                             K toKey,   boolean toInclusive);
+
+    /**
+     * Returns a view of the portion of this map whose keys are less than (or
+     * equal to, if {@code inclusive} is true) {@code toKey}.  The returned
+     * map is backed by this map, so changes in the returned map are reflected
+     * in this map, and vice-versa.  The returned map supports all optional
+     * map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param toKey high endpoint of the keys in the returned map
+     * @param inclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this map whose keys are less than
+     *         (or equal to, if {@code inclusive} is true) {@code toKey}
+     * @throws ClassCastException if {@code toKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code toKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code toKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code toKey} is null
+     *         and this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code toKey} lies outside the
+     *         bounds of the range
+     */
+    NavigableMap<K,V> headMap(K toKey, boolean inclusive);
+
+    /**
+     * Returns a view of the portion of this map whose keys are greater than (or
+     * equal to, if {@code inclusive} is true) {@code fromKey}.  The returned
+     * map is backed by this map, so changes in the returned map are reflected
+     * in this map, and vice-versa.  The returned map supports all optional
+     * map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param fromKey low endpoint of the keys in the returned map
+     * @param inclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this map whose keys are greater than
+     *         (or equal to, if {@code inclusive} is true) {@code fromKey}
+     * @throws ClassCastException if {@code fromKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code fromKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code fromKey} is null
+     *         and this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code fromKey} lies outside the
+     *         bounds of the range
+     */
+    NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code subMap(fromKey, true, toKey, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedMap<K,V> subMap(K fromKey, K toKey);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code headMap(toKey, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedMap<K,V> headMap(K toKey);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code tailMap(fromKey, true)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedMap<K,V> tailMap(K fromKey);
+}
diff --git a/java/util/NavigableSet.java b/java/util/NavigableSet.java
new file mode 100644
index 0000000..71d8dba
--- /dev/null
+++ b/java/util/NavigableSet.java
@@ -0,0 +1,323 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Josh Bloch with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+package java.util;
+
+/**
+ * A {@link SortedSet} extended with navigation methods reporting
+ * closest matches for given search targets. Methods {@link #lower},
+ * {@link #floor}, {@link #ceiling}, and {@link #higher} return elements
+ * respectively less than, less than or equal, greater than or equal,
+ * and greater than a given element, returning {@code null} if there
+ * is no such element.
+ *
+ * <p>A {@code NavigableSet} may be accessed and traversed in either
+ * ascending or descending order.  The {@link #descendingSet} method
+ * returns a view of the set with the senses of all relational and
+ * directional methods inverted. The performance of ascending
+ * operations and views is likely to be faster than that of descending
+ * ones.  This interface additionally defines methods {@link
+ * #pollFirst} and {@link #pollLast} that return and remove the lowest
+ * and highest element, if one exists, else returning {@code null}.
+ * Methods
+ * {@link #subSet(Object, boolean, Object, boolean) subSet(E, boolean, E, boolean)},
+ * {@link #headSet(Object, boolean) headSet(E, boolean)}, and
+ * {@link #tailSet(Object, boolean) tailSet(E, boolean)}
+ * differ from the like-named {@code SortedSet} methods in accepting
+ * additional arguments describing whether lower and upper bounds are
+ * inclusive versus exclusive.  Subsets of any {@code NavigableSet}
+ * must implement the {@code NavigableSet} interface.
+ *
+ * <p>The return values of navigation methods may be ambiguous in
+ * implementations that permit {@code null} elements. However, even
+ * in this case the result can be disambiguated by checking
+ * {@code contains(null)}. To avoid such issues, implementations of
+ * this interface are encouraged to <em>not</em> permit insertion of
+ * {@code null} elements. (Note that sorted sets of {@link
+ * Comparable} elements intrinsically do not permit {@code null}.)
+ *
+ * <p>Methods
+ * {@link #subSet(Object, Object) subSet(E, E)},
+ * {@link #headSet(Object) headSet(E)}, and
+ * {@link #tailSet(Object) tailSet(E)}
+ * are specified to return {@code SortedSet} to allow existing
+ * implementations of {@code SortedSet} to be compatibly retrofitted to
+ * implement {@code NavigableSet}, but extensions and implementations
+ * of this interface are encouraged to override these methods to return
+ * {@code NavigableSet}.
+ *
+ * @author Doug Lea
+ * @author Josh Bloch
+ * @param <E> the type of elements maintained by this set
+ * @since 1.6
+ */
+public interface NavigableSet<E> extends SortedSet<E> {
+    /**
+     * Returns the greatest element in this set strictly less than the
+     * given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the greatest element less than {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E lower(E e);
+
+    /**
+     * Returns the greatest element in this set less than or equal to
+     * the given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the greatest element less than or equal to {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E floor(E e);
+
+    /**
+     * Returns the least element in this set greater than or equal to
+     * the given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the least element greater than or equal to {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E ceiling(E e);
+
+    /**
+     * Returns the least element in this set strictly greater than the
+     * given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the least element greater than {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E higher(E e);
+
+    /**
+     * Retrieves and removes the first (lowest) element,
+     * or returns {@code null} if this set is empty.
+     *
+     * @return the first element, or {@code null} if this set is empty
+     */
+    E pollFirst();
+
+    /**
+     * Retrieves and removes the last (highest) element,
+     * or returns {@code null} if this set is empty.
+     *
+     * @return the last element, or {@code null} if this set is empty
+     */
+    E pollLast();
+
+    /**
+     * Returns an iterator over the elements in this set, in ascending order.
+     *
+     * @return an iterator over the elements in this set, in ascending order
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns a reverse order view of the elements contained in this set.
+     * The descending set is backed by this set, so changes to the set are
+     * reflected in the descending set, and vice-versa.  If either set is
+     * modified while an iteration over either set is in progress (except
+     * through the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.
+     *
+     * <p>The returned set has an ordering equivalent to
+     * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code s.descendingSet().descendingSet()} returns a
+     * view of {@code s} essentially equivalent to {@code s}.
+     *
+     * @return a reverse order view of this set
+     */
+    NavigableSet<E> descendingSet();
+
+    /**
+     * Returns an iterator over the elements in this set, in descending order.
+     * Equivalent in effect to {@code descendingSet().iterator()}.
+     *
+     * @return an iterator over the elements in this set, in descending order
+     */
+    Iterator<E> descendingIterator();
+
+    /**
+     * Returns a view of the portion of this set whose elements range from
+     * {@code fromElement} to {@code toElement}.  If {@code fromElement} and
+     * {@code toElement} are equal, the returned set is empty unless {@code
+     * fromInclusive} and {@code toInclusive} are both true.  The returned set
+     * is backed by this set, so changes in the returned set are reflected in
+     * this set, and vice-versa.  The returned set supports all optional set
+     * operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint of the returned set
+     * @param fromInclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @param toElement high endpoint of the returned set
+     * @param toInclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this set whose elements range from
+     *         {@code fromElement}, inclusive, to {@code toElement}, exclusive
+     * @throws ClassCastException if {@code fromElement} and
+     *         {@code toElement} cannot be compared to one another using this
+     *         set's comparator (or, if the set has no comparator, using
+     *         natural ordering).  Implementations may, but are not required
+     *         to, throw this exception if {@code fromElement} or
+     *         {@code toElement} cannot be compared to elements currently in
+     *         the set.
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null and this set does
+     *         not permit null elements
+     * @throws IllegalArgumentException if {@code fromElement} is
+     *         greater than {@code toElement}; or if this set itself
+     *         has a restricted range, and {@code fromElement} or
+     *         {@code toElement} lies outside the bounds of the range.
+     */
+    NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
+                           E toElement,   boolean toInclusive);
+
+    /**
+     * Returns a view of the portion of this set whose elements are less than
+     * (or equal to, if {@code inclusive} is true) {@code toElement}.  The
+     * returned set is backed by this set, so changes in the returned set are
+     * reflected in this set, and vice-versa.  The returned set supports all
+     * optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param toElement high endpoint of the returned set
+     * @param inclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this set whose elements are less than
+     *         (or equal to, if {@code inclusive} is true) {@code toElement}
+     * @throws ClassCastException if {@code toElement} is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if {@code toElement} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code toElement} cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if {@code toElement} is null and
+     *         this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and {@code toElement} lies outside the
+     *         bounds of the range
+     */
+    NavigableSet<E> headSet(E toElement, boolean inclusive);
+
+    /**
+     * Returns a view of the portion of this set whose elements are greater
+     * than (or equal to, if {@code inclusive} is true) {@code fromElement}.
+     * The returned set is backed by this set, so changes in the returned set
+     * are reflected in this set, and vice-versa.  The returned set supports
+     * all optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint of the returned set
+     * @param inclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this set whose elements are greater
+     *         than or equal to {@code fromElement}
+     * @throws ClassCastException if {@code fromElement} is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if {@code fromElement} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromElement} cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if {@code fromElement} is null
+     *         and this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and {@code fromElement} lies outside the
+     *         bounds of the range
+     */
+    NavigableSet<E> tailSet(E fromElement, boolean inclusive);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code subSet(fromElement, true, toElement, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedSet<E> subSet(E fromElement, E toElement);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code headSet(toElement, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedSet<E> headSet(E toElement);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code tailSet(fromElement, true)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedSet<E> tailSet(E fromElement);
+}
diff --git a/java/util/NoSuchElementException.java b/java/util/NoSuchElementException.java
new file mode 100644
index 0000000..15e1aad
--- /dev/null
+++ b/java/util/NoSuchElementException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Thrown by various accessor methods to indicate that the element being requested
+ * does not exist.
+ *
+ * @author  unascribed
+ * @see     java.util.Enumeration#nextElement()
+ * @see     java.util.Iterator#next()
+ * @since   JDK1.0
+ */
+public
+class NoSuchElementException extends RuntimeException {
+    private static final long serialVersionUID = 6769829250639411880L;
+
+    /**
+     * Constructs a <code>NoSuchElementException</code> with <tt>null</tt>
+     * as its error message string.
+     */
+    public NoSuchElementException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>NoSuchElementException</code>, saving a reference
+     * to the error message string <tt>s</tt> for later retrieval by the
+     * <tt>getMessage</tt> method.
+     *
+     * @param   s   the detail message.
+     */
+    public NoSuchElementException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/Objects.annotated.java b/java/util/Objects.annotated.java
new file mode 100644
index 0000000..ee1b692
--- /dev/null
+++ b/java/util/Objects.annotated.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.util.function.Supplier;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Objects {
+
+Objects() { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(@libcore.util.Nullable java.lang.Object a, @libcore.util.Nullable java.lang.Object b) { throw new RuntimeException("Stub!"); }
+
+public static boolean deepEquals(@libcore.util.Nullable java.lang.Object a, @libcore.util.Nullable java.lang.Object b) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public static int hash([email protected] Object @libcore.util.Nullable ... values) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(@libcore.util.Nullable java.lang.Object o, @libcore.util.NonNull java.lang.String nullDefault) { throw new RuntimeException("Stub!"); }
+
+public static <T> int compare(@libcore.util.NullFromTypeParam T a, @libcore.util.NullFromTypeParam T b, @libcore.util.NonNull java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T requireNonNull(@libcore.util.Nullable T obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T requireNonNull(@libcore.util.Nullable T obj, @libcore.util.NonNull java.lang.String message) { throw new RuntimeException("Stub!"); }
+
+public static boolean isNull(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public static boolean nonNull(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T requireNonNullElse(@libcore.util.Nullable T obj, @libcore.util.NonNull T defaultObj) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T requireNonNullElseGet(@libcore.util.Nullable T obj, @libcore.util.NonNull java.util.function.Supplier<? extends @libcore.util.NonNull T> supplier) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T requireNonNull(@libcore.util.Nullable T obj, @libcore.util.NonNull java.util.function.Supplier<@libcore.util.NonNull java.lang.String> messageSupplier) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/Objects.java b/java/util/Objects.java
new file mode 100644
index 0000000..1f76487
--- /dev/null
+++ b/java/util/Objects.java
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import jdk.internal.util.Preconditions;
+
+import java.util.function.Supplier;
+
+/**
+ * This class consists of {@code static} utility methods for operating
+ * on objects, or checking certain conditions before operation.  These utilities
+ * include {@code null}-safe or {@code null}-tolerant methods for computing the
+ * hash code of an object, returning a string for an object, comparing two
+ * objects, and checking if indexes or sub-range values are out-of-bounds.
+ *
+ * @apiNote
+ * Static methods such as {@link Objects#checkIndex},
+ * {@link Objects#checkFromToIndex}, and {@link Objects#checkFromIndexSize} are
+ * provided for the convenience of checking if values corresponding to indexes
+ * and sub-ranges are out-of-bounds.
+ * Variations of these static methods support customization of the runtime
+ * exception, and corresponding exception detail message, that is thrown when
+ * values are out-of-bounds.  Such methods accept a functional interface
+ * argument, instances of {@code BiFunction}, that maps out-of-bound values to a
+ * runtime exception.  Care should be taken when using such methods in
+ * combination with an argument that is a lambda expression, method reference or
+ * class that capture values.  In such cases the cost of capture, related to
+ * functional interface allocation, may exceed the cost of checking bounds.
+ *
+ * @since 1.7
+ */
+public final class Objects {
+    private Objects() {
+        throw new AssertionError("No java.util.Objects instances for you!");
+    }
+
+    /**
+     * Returns {@code true} if the arguments are equal to each other
+     * and {@code false} otherwise.
+     * Consequently, if both arguments are {@code null}, {@code true}
+     * is returned and if exactly one argument is {@code null}, {@code
+     * false} is returned.  Otherwise, equality is determined by using
+     * the {@link Object#equals equals} method of the first
+     * argument.
+     *
+     * @param a an object
+     * @param b an object to be compared with {@code a} for equality
+     * @return {@code true} if the arguments are equal to each other
+     * and {@code false} otherwise
+     * @see Object#equals(Object)
+     */
+    public static boolean equals(Object a, Object b) {
+        return (a == b) || (a != null && a.equals(b));
+    }
+
+   /**
+    * Returns {@code true} if the arguments are deeply equal to each other
+    * and {@code false} otherwise.
+    *
+    * Two {@code null} values are deeply equal.  If both arguments are
+    * arrays, the algorithm in {@link Arrays#deepEquals(Object[],
+    * Object[]) Arrays.deepEquals} is used to determine equality.
+    * Otherwise, equality is determined by using the {@link
+    * Object#equals equals} method of the first argument.
+    *
+    * @param a an object
+    * @param b an object to be compared with {@code a} for deep equality
+    * @return {@code true} if the arguments are deeply equal to each other
+    * and {@code false} otherwise
+    * @see Arrays#deepEquals(Object[], Object[])
+    * @see Objects#equals(Object, Object)
+    */
+    public static boolean deepEquals(Object a, Object b) {
+        if (a == b)
+            return true;
+        else if (a == null || b == null)
+            return false;
+        else
+            return Arrays.deepEquals0(a, b);
+    }
+
+    /**
+     * Returns the hash code of a non-{@code null} argument and 0 for
+     * a {@code null} argument.
+     *
+     * @param o an object
+     * @return the hash code of a non-{@code null} argument and 0 for
+     * a {@code null} argument
+     * @see Object#hashCode
+     */
+    public static int hashCode(Object o) {
+        return o != null ? o.hashCode() : 0;
+    }
+
+   /**
+    * Generates a hash code for a sequence of input values. The hash
+    * code is generated as if all the input values were placed into an
+    * array, and that array were hashed by calling {@link
+    * Arrays#hashCode(Object[])}.
+    *
+    * <p>This method is useful for implementing {@link
+    * Object#hashCode()} on objects containing multiple fields. For
+    * example, if an object that has three fields, {@code x}, {@code
+    * y}, and {@code z}, one could write:
+    *
+    * <blockquote><pre>
+    * &#064;Override public int hashCode() {
+    *     return Objects.hash(x, y, z);
+    * }
+    * </pre></blockquote>
+    *
+    * <b>Warning: When a single object reference is supplied, the returned
+    * value does not equal the hash code of that object reference.</b> This
+    * value can be computed by calling {@link #hashCode(Object)}.
+    *
+    * @param values the values to be hashed
+    * @return a hash value of the sequence of input values
+    * @see Arrays#hashCode(Object[])
+    * @see List#hashCode
+    */
+    public static int hash(Object... values) {
+        return Arrays.hashCode(values);
+    }
+
+    /**
+     * Returns the result of calling {@code toString} for a non-{@code
+     * null} argument and {@code "null"} for a {@code null} argument.
+     *
+     * @param o an object
+     * @return the result of calling {@code toString} for a non-{@code
+     * null} argument and {@code "null"} for a {@code null} argument
+     * @see Object#toString
+     * @see String#valueOf(Object)
+     */
+    public static String toString(Object o) {
+        return String.valueOf(o);
+    }
+
+    /**
+     * Returns the result of calling {@code toString} on the first
+     * argument if the first argument is not {@code null} and returns
+     * the second argument otherwise.
+     *
+     * @param o an object
+     * @param nullDefault string to return if the first argument is
+     *        {@code null}
+     * @return the result of calling {@code toString} on the first
+     * argument if it is not {@code null} and the second argument
+     * otherwise.
+     * @see Objects#toString(Object)
+     */
+    public static String toString(Object o, String nullDefault) {
+        return (o != null) ? o.toString() : nullDefault;
+    }
+
+    /**
+     * Returns 0 if the arguments are identical and {@code
+     * c.compare(a, b)} otherwise.
+     * Consequently, if both arguments are {@code null} 0
+     * is returned.
+     *
+     * <p>Note that if one of the arguments is {@code null}, a {@code
+     * NullPointerException} may or may not be thrown depending on
+     * what ordering policy, if any, the {@link Comparator Comparator}
+     * chooses to have for {@code null} values.
+     *
+     * @param <T> the type of the objects being compared
+     * @param a an object
+     * @param b an object to be compared with {@code a}
+     * @param c the {@code Comparator} to compare the first two arguments
+     * @return 0 if the arguments are identical and {@code
+     * c.compare(a, b)} otherwise.
+     * @see Comparable
+     * @see Comparator
+     */
+    public static <T> int compare(T a, T b, Comparator<? super T> c) {
+        return (a == b) ? 0 :  c.compare(a, b);
+    }
+
+    /**
+     * Checks that the specified object reference is not {@code null}. This
+     * method is designed primarily for doing parameter validation in methods
+     * and constructors, as demonstrated below:
+     * <blockquote><pre>
+     * public Foo(Bar bar) {
+     *     this.bar = Objects.requireNonNull(bar);
+     * }
+     * </pre></blockquote>
+     *
+     * @param obj the object reference to check for nullity
+     * @param <T> the type of the reference
+     * @return {@code obj} if not {@code null}
+     * @throws NullPointerException if {@code obj} is {@code null}
+     */
+    public static <T> T requireNonNull(T obj) {
+        if (obj == null)
+            throw new NullPointerException();
+        return obj;
+    }
+
+    /**
+     * Checks that the specified object reference is not {@code null} and
+     * throws a customized {@link NullPointerException} if it is. This method
+     * is designed primarily for doing parameter validation in methods and
+     * constructors with multiple parameters, as demonstrated below:
+     * <blockquote><pre>
+     * public Foo(Bar bar, Baz baz) {
+     *     this.bar = Objects.requireNonNull(bar, "bar must not be null");
+     *     this.baz = Objects.requireNonNull(baz, "baz must not be null");
+     * }
+     * </pre></blockquote>
+     *
+     * @param obj     the object reference to check for nullity
+     * @param message detail message to be used in the event that a {@code
+     *                NullPointerException} is thrown
+     * @param <T> the type of the reference
+     * @return {@code obj} if not {@code null}
+     * @throws NullPointerException if {@code obj} is {@code null}
+     */
+    public static <T> T requireNonNull(T obj, String message) {
+        if (obj == null)
+            throw new NullPointerException(message);
+        return obj;
+    }
+
+    /**
+     * Returns {@code true} if the provided reference is {@code null} otherwise
+     * returns {@code false}.
+     *
+     * @apiNote This method exists to be used as a
+     * {@link java.util.function.Predicate}, {@code filter(Objects::isNull)}
+     *
+     * @param obj a reference to be checked against {@code null}
+     * @return {@code true} if the provided reference is {@code null} otherwise
+     * {@code false}
+     *
+     * @see java.util.function.Predicate
+     * @since 1.8
+     */
+    public static boolean isNull(Object obj) {
+        return obj == null;
+    }
+
+    /**
+     * Returns {@code true} if the provided reference is non-{@code null}
+     * otherwise returns {@code false}.
+     *
+     * @apiNote This method exists to be used as a
+     * {@link java.util.function.Predicate}, {@code filter(Objects::nonNull)}
+     *
+     * @param obj a reference to be checked against {@code null}
+     * @return {@code true} if the provided reference is non-{@code null}
+     * otherwise {@code false}
+     *
+     * @see java.util.function.Predicate
+     * @since 1.8
+     */
+    public static boolean nonNull(Object obj) {
+        return obj != null;
+    }
+
+    /**
+     * Returns the first argument if it is non-{@code null} and
+     * otherwise returns the non-{@code null} second argument.
+     *
+     * @param obj an object
+     * @param defaultObj a non-{@code null} object to return if the first argument
+     *                   is {@code null}
+     * @param <T> the type of the reference
+     * @return the first argument if it is non-{@code null} and
+     *        otherwise the second argument if it is non-{@code null}
+     * @throws NullPointerException if both {@code obj} is null and
+     *        {@code defaultObj} is {@code null}
+     * @since 9
+     */
+    public static <T> T requireNonNullElse(T obj, T defaultObj) {
+        return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj");
+    }
+
+    /**
+     * Returns the first argument if it is non-{@code null} and otherwise
+     * returns the non-{@code null} value of {@code supplier.get()}.
+     *
+     * @param obj an object
+     * @param supplier of a non-{@code null} object to return if the first argument
+     *                 is {@code null}
+     * @param <T> the type of the first argument and return type
+     * @return the first argument if it is non-{@code null} and otherwise
+     *         the value from {@code supplier.get()} if it is non-{@code null}
+     * @throws NullPointerException if both {@code obj} is null and
+     *        either the {@code supplier} is {@code null} or
+     *        the {@code supplier.get()} value is {@code null}
+     * @since 9
+     */
+    public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier) {
+        return (obj != null) ? obj
+                : requireNonNull(requireNonNull(supplier, "supplier").get(), "supplier.get()");
+    }
+
+    /**
+     * Checks that the specified object reference is not {@code null} and
+     * throws a customized {@link NullPointerException} if it is.
+     *
+     * <p>Unlike the method {@link #requireNonNull(Object, String)},
+     * this method allows creation of the message to be deferred until
+     * after the null check is made. While this may confer a
+     * performance advantage in the non-null case, when deciding to
+     * call this method care should be taken that the costs of
+     * creating the message supplier are less than the cost of just
+     * creating the string message directly.
+     *
+     * @param obj     the object reference to check for nullity
+     * @param messageSupplier supplier of the detail message to be
+     * used in the event that a {@code NullPointerException} is thrown
+     * @param <T> the type of the reference
+     * @return {@code obj} if not {@code null}
+     * @throws NullPointerException if {@code obj} is {@code null}
+     * @since 1.8
+     */
+    public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
+        if (obj == null)
+            throw new NullPointerException(messageSupplier == null ?
+                                           null : messageSupplier.get());
+        return obj;
+    }
+
+    /**
+     * Checks if the {@code index} is within the bounds of the range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The {@code index} is defined to be out-of-bounds if any of the
+     * following inequalities is true:
+     * <ul>
+     *  <li>{@code index < 0}</li>
+     *  <li>{@code index >= length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param index the index
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code index} if it is within bounds of the range
+     * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds
+     * @since 9
+     */
+    // Android-removed: @ForceInline is an unsupported attribute.
+    //@ForceInline
+    public static
+    int checkIndex(int index, int length) {
+        return Preconditions.checkIndex(index, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
+     * (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code fromIndex > toIndex}</li>
+     *  <li>{@code toIndex > length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-range
+     * @param toIndex the upper-bound (exclusive) of the sub-range
+     * @param length the upper-bound (exclusive) the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds
+     * @since 9
+     */
+    public static
+    int checkFromToIndex(int fromIndex, int toIndex, int length) {
+        return Preconditions.checkFromToIndex(fromIndex, toIndex, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code fromIndex + size} (exclusive) is within the bounds of range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code size < 0}</li>
+     *  <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-interval
+     * @param size the size of the sub-range
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds
+     * @since 9
+     */
+    public static
+    int checkFromIndexSize(int fromIndex, int size, int length) {
+        return Preconditions.checkFromIndexSize(fromIndex, size, length, null);
+    }
+
+}
diff --git a/java/util/Observable.java b/java/util/Observable.java
new file mode 100644
index 0000000..be01640
--- /dev/null
+++ b/java/util/Observable.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class represents an observable object, or "data"
+ * in the model-view paradigm. It can be subclassed to represent an
+ * object that the application wants to have observed.
+ * <p>
+ * An observable object can have one or more observers. An observer
+ * may be any object that implements interface <tt>Observer</tt>. After an
+ * observable instance changes, an application calling the
+ * <code>Observable</code>'s <code>notifyObservers</code> method
+ * causes all of its observers to be notified of the change by a call
+ * to their <code>update</code> method.
+ * <p>
+ * The order in which notifications will be delivered is unspecified.
+ * The default implementation provided in the Observable class will
+ * notify Observers in the order in which they registered interest, but
+ * subclasses may change this order, use no guaranteed order, deliver
+ * notifications on separate threads, or may guarantee that their
+ * subclass follows this order, as they choose.
+ * <p>
+ * Note that this notification mechanism has nothing to do with threads
+ * and is completely separate from the <tt>wait</tt> and <tt>notify</tt>
+ * mechanism of class <tt>Object</tt>.
+ * <p>
+ * When an observable object is newly created, its set of observers is
+ * empty. Two observers are considered the same if and only if the
+ * <tt>equals</tt> method returns true for them.
+ *
+ * @author  Chris Warth
+ * @see     java.util.Observable#notifyObservers()
+ * @see     java.util.Observable#notifyObservers(java.lang.Object)
+ * @see     java.util.Observer
+ * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
+ * @since   JDK1.0
+ */
+public class Observable {
+    private boolean changed = false;
+    private Vector<Observer> obs;
+
+    /** Construct an Observable with zero Observers. */
+
+    public Observable() {
+        obs = new Vector<>();
+    }
+
+    /**
+     * Adds an observer to the set of observers for this object, provided
+     * that it is not the same as some observer already in the set.
+     * The order in which notifications will be delivered to multiple
+     * observers is not specified. See the class comment.
+     *
+     * @param   o   an observer to be added.
+     * @throws NullPointerException   if the parameter o is null.
+     */
+    public synchronized void addObserver(Observer o) {
+        if (o == null)
+            throw new NullPointerException();
+        if (!obs.contains(o)) {
+            obs.addElement(o);
+        }
+    }
+
+    /**
+     * Deletes an observer from the set of observers of this object.
+     * Passing <CODE>null</CODE> to this method will have no effect.
+     * @param   o   the observer to be deleted.
+     */
+    public synchronized void deleteObserver(Observer o) {
+        obs.removeElement(o);
+    }
+
+    /**
+     * If this object has changed, as indicated by the
+     * <code>hasChanged</code> method, then notify all of its observers
+     * and then call the <code>clearChanged</code> method to
+     * indicate that this object has no longer changed.
+     * <p>
+     * Each observer has its <code>update</code> method called with two
+     * arguments: this observable object and <code>null</code>. In other
+     * words, this method is equivalent to:
+     * <blockquote><tt>
+     * notifyObservers(null)</tt></blockquote>
+     *
+     * @see     java.util.Observable#clearChanged()
+     * @see     java.util.Observable#hasChanged()
+     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
+     */
+    public void notifyObservers() {
+        notifyObservers(null);
+    }
+
+    /**
+     * If this object has changed, as indicated by the
+     * <code>hasChanged</code> method, then notify all of its observers
+     * and then call the <code>clearChanged</code> method to indicate
+     * that this object has no longer changed.
+     * <p>
+     * Each observer has its <code>update</code> method called with two
+     * arguments: this observable object and the <code>arg</code> argument.
+     *
+     * @param   arg   any object.
+     * @see     java.util.Observable#clearChanged()
+     * @see     java.util.Observable#hasChanged()
+     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
+     */
+    public void notifyObservers(Object arg) {
+        /*
+         * a temporary array buffer, used as a snapshot of the state of
+         * current Observers.
+         */
+        Object[] arrLocal;
+
+        synchronized (this) {
+            /* We don't want the Observer doing callbacks into
+             * arbitrary code while holding its own Monitor.
+             * The code where we extract each Observable from
+             * the Vector and store the state of the Observer
+             * needs synchronization, but notifying observers
+             * does not (should not).  The worst result of any
+             * potential race-condition here is that:
+             * 1) a newly-added Observer will miss a
+             *   notification in progress
+             * 2) a recently unregistered Observer will be
+             *   wrongly notified when it doesn't care
+             */
+            // Android-changed: Call out to hasChanged() to figure out if something changes.
+            // Upstream code avoids calling the nonfinal hasChanged() from the synchronized block,
+            // but that would break compatibility for apps that override that method.
+            // if (!changed)
+            if (!hasChanged())
+                return;
+            arrLocal = obs.toArray();
+            clearChanged();
+        }
+
+        for (int i = arrLocal.length-1; i>=0; i--)
+            ((Observer)arrLocal[i]).update(this, arg);
+    }
+
+    /**
+     * Clears the observer list so that this object no longer has any observers.
+     */
+    public synchronized void deleteObservers() {
+        obs.removeAllElements();
+    }
+
+    /**
+     * Marks this <tt>Observable</tt> object as having been changed; the
+     * <tt>hasChanged</tt> method will now return <tt>true</tt>.
+     */
+    protected synchronized void setChanged() {
+        changed = true;
+    }
+
+    /**
+     * Indicates that this object has no longer changed, or that it has
+     * already notified all of its observers of its most recent change,
+     * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.
+     * This method is called automatically by the
+     * <code>notifyObservers</code> methods.
+     *
+     * @see     java.util.Observable#notifyObservers()
+     * @see     java.util.Observable#notifyObservers(java.lang.Object)
+     */
+    protected synchronized void clearChanged() {
+        changed = false;
+    }
+
+    /**
+     * Tests if this object has changed.
+     *
+     * @return  <code>true</code> if and only if the <code>setChanged</code>
+     *          method has been called more recently than the
+     *          <code>clearChanged</code> method on this object;
+     *          <code>false</code> otherwise.
+     * @see     java.util.Observable#clearChanged()
+     * @see     java.util.Observable#setChanged()
+     */
+    public synchronized boolean hasChanged() {
+        return changed;
+    }
+
+    /**
+     * Returns the number of observers of this <tt>Observable</tt> object.
+     *
+     * @return  the number of observers of this object.
+     */
+    public synchronized int countObservers() {
+        return obs.size();
+    }
+}
diff --git a/java/util/Observer.java b/java/util/Observer.java
new file mode 100644
index 0000000..ef64e14
--- /dev/null
+++ b/java/util/Observer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+/**
+ * A class can implement the <code>Observer</code> interface when it
+ * wants to be informed of changes in observable objects.
+ *
+ * @author  Chris Warth
+ * @see     java.util.Observable
+ * @since   JDK1.0
+ */
+public interface Observer {
+    /**
+     * This method is called whenever the observed object is changed. An
+     * application calls an <tt>Observable</tt> object's
+     * <code>notifyObservers</code> method to have all the object's
+     * observers notified of the change.
+     *
+     * @param   o     the observable object.
+     * @param   arg   an argument passed to the <code>notifyObservers</code>
+     *                 method.
+     */
+    void update(Observable o, Object arg);
+}
diff --git a/java/util/Optional.java b/java/util/Optional.java
new file mode 100644
index 0000000..bce8ff9
--- /dev/null
+++ b/java/util/Optional.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A container object which may or may not contain a non-null value.
+ * If a value is present, {@code isPresent()} will return {@code true} and
+ * {@code get()} will return the value.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(java.lang.Object) orElse()}
+ * (return a default value if value not present) and
+ * {@link #ifPresent(java.util.function.Consumer) ifPresent()} (execute a block
+ * of code if the value is present).
+ *
+ * @since 1.8
+ */
+public final class Optional<T> {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final Optional<?> EMPTY = new Optional<>();
+
+    /**
+     * If non-null, the value; if null, indicates no value is present
+     */
+    private final T value;
+
+    /**
+     * Constructs an empty instance.
+     *
+     * @implNote Generally only one empty instance, {@link Optional#EMPTY},
+     * should exist per VM.
+     */
+    private Optional() {
+        this.value = null;
+    }
+
+    /**
+     * Returns an empty {@code Optional} instance.  No value is present for this
+     * Optional.
+     *
+     * @apiNote Though it may be tempting to do so, avoid testing if an object
+     * is empty by comparing with {@code ==} against instances returned by
+     * {@code Option.empty()}. There is no guarantee that it is a singleton.
+     * Instead, use {@link #isPresent()}.
+     *
+     * @param <T> Type of the non-existent value
+     * @return an empty {@code Optional}
+     */
+    public static<T> Optional<T> empty() {
+        @SuppressWarnings("unchecked")
+        Optional<T> t = (Optional<T>) EMPTY;
+        return t;
+    }
+
+    /**
+     * Constructs an instance with the value present.
+     *
+     * @param value the non-null value to be present
+     * @throws NullPointerException if value is null
+     */
+    private Optional(T value) {
+        this.value = Objects.requireNonNull(value);
+    }
+
+    /**
+     * Returns an {@code Optional} with the specified present non-null value.
+     *
+     * @param <T> the class of the value
+     * @param value the value to be present, which must be non-null
+     * @return an {@code Optional} with the value present
+     * @throws NullPointerException if value is null
+     */
+    public static <T> Optional<T> of(T value) {
+        return new Optional<>(value);
+    }
+
+    /**
+     * Returns an {@code Optional} describing the specified value, if non-null,
+     * otherwise returns an empty {@code Optional}.
+     *
+     * @param <T> the class of the value
+     * @param value the possibly-null value to describe
+     * @return an {@code Optional} with a present value if the specified value
+     * is non-null, otherwise an empty {@code Optional}
+     */
+    public static <T> Optional<T> ofNullable(T value) {
+        return value == null ? empty() : of(value);
+    }
+
+    /**
+     * If a value is present in this {@code Optional}, returns the value,
+     * otherwise throws {@code NoSuchElementException}.
+     *
+     * @return the non-null value held by this {@code Optional}
+     * @throws NoSuchElementException if there is no value present
+     *
+     * @see Optional#isPresent()
+     */
+    public T get() {
+        if (value == null) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * Return {@code true} if there is a value present, otherwise {@code false}.
+     *
+     * @return {@code true} if there is a value present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return value != null;
+    }
+
+    /**
+     * If a value is present, invoke the specified consumer with the value,
+     * otherwise do nothing.
+     *
+     * @param consumer block to be executed if a value is present
+     * @throws NullPointerException if value is present and {@code consumer} is
+     * null
+     */
+    public void ifPresent(Consumer<? super T> consumer) {
+        if (value != null)
+            consumer.accept(value);
+    }
+
+    /**
+     * If a value is present, and the value matches the given predicate,
+     * return an {@code Optional} describing the value, otherwise return an
+     * empty {@code Optional}.
+     *
+     * @param predicate a predicate to apply to the value, if present
+     * @return an {@code Optional} describing the value of this {@code Optional}
+     * if a value is present and the value matches the given predicate,
+     * otherwise an empty {@code Optional}
+     * @throws NullPointerException if the predicate is null
+     */
+    public Optional<T> filter(Predicate<? super T> predicate) {
+        Objects.requireNonNull(predicate);
+        if (!isPresent())
+            return this;
+        else
+            return predicate.test(value) ? this : empty();
+    }
+
+    /**
+     * If a value is present, apply the provided mapping function to it,
+     * and if the result is non-null, return an {@code Optional} describing the
+     * result.  Otherwise return an empty {@code Optional}.
+     *
+     * @apiNote This method supports post-processing on optional values, without
+     * the need to explicitly check for a return status.  For example, the
+     * following code traverses a stream of file names, selects one that has
+     * not yet been processed, and then opens that file, returning an
+     * {@code Optional<FileInputStream>}:
+     *
+     * <pre>{@code
+     *     Optional<FileInputStream> fis =
+     *         names.stream().filter(name -> !isProcessedYet(name))
+     *                       .findFirst()
+     *                       .map(name -> new FileInputStream(name));
+     * }</pre>
+     *
+     * Here, {@code findFirst} returns an {@code Optional<String>}, and then
+     * {@code map} returns an {@code Optional<FileInputStream>} for the desired
+     * file if one exists.
+     *
+     * @param <U> The type of the result of the mapping function
+     * @param mapper a mapping function to apply to the value, if present
+     * @return an {@code Optional} describing the result of applying a mapping
+     * function to the value of this {@code Optional}, if a value is present,
+     * otherwise an empty {@code Optional}
+     * @throws NullPointerException if the mapping function is null
+     */
+    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        if (!isPresent())
+            return empty();
+        else {
+            return Optional.ofNullable(mapper.apply(value));
+        }
+    }
+
+    /**
+     * If a value is present, apply the provided {@code Optional}-bearing
+     * mapping function to it, return that result, otherwise return an empty
+     * {@code Optional}.  This method is similar to {@link #map(Function)},
+     * but the provided mapper is one whose result is already an {@code Optional},
+     * and if invoked, {@code flatMap} does not wrap it with an additional
+     * {@code Optional}.
+     *
+     * @param <U> The type parameter to the {@code Optional} returned by
+     * @param mapper a mapping function to apply to the value, if present
+     *           the mapping function
+     * @return the result of applying an {@code Optional}-bearing mapping
+     * function to the value of this {@code Optional}, if a value is present,
+     * otherwise an empty {@code Optional}
+     * @throws NullPointerException if the mapping function is null or returns
+     * a null result
+     */
+    public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
+        Objects.requireNonNull(mapper);
+        if (!isPresent())
+            return empty();
+        else {
+            return Objects.requireNonNull(mapper.apply(value));
+        }
+    }
+
+    /**
+     * Return the value if present, otherwise return {@code other}.
+     *
+     * @param other the value to be returned if there is no value present, may
+     * be null
+     * @return the value, if present, otherwise {@code other}
+     */
+    public T orElse(T other) {
+        return value != null ? value : other;
+    }
+
+    /**
+     * Return the value if present, otherwise invoke {@code other} and return
+     * the result of that invocation.
+     *
+     * @param other a {@code Supplier} whose result is returned if no value
+     * is present
+     * @return the value if present otherwise the result of {@code other.get()}
+     * @throws NullPointerException if value is not present and {@code other} is
+     * null
+     */
+    public T orElseGet(Supplier<? extends T> other) {
+        return value != null ? value : other.get();
+    }
+
+    /**
+     * Return the contained value, if present, otherwise throw an exception
+     * to be created by the provided supplier.
+     *
+     * @apiNote A method reference to the exception constructor with an empty
+     * argument list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier The supplier which will return the exception to
+     * be thrown
+     * @return the present value
+     * @throws X if there is no value present
+     * @throws NullPointerException if no value is present and
+     * {@code exceptionSupplier} is null
+     */
+    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
+        if (value != null) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this Optional. The
+     * other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code Optional} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via {@code equals()}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {code true} if the other object is "equal to" this object
+     * otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof Optional)) {
+            return false;
+        }
+
+        Optional<?> other = (Optional<?>) obj;
+        return Objects.equals(value, other.value);
+    }
+
+    /**
+     * Returns the hash code value of the present value, if any, or 0 (zero) if
+     * no value is present.
+     *
+     * @return hash code value of the present value or 0 if no value is present
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(value);
+    }
+
+    /**
+     * Returns a non-empty string representation of this Optional suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     *
+     * @implSpec If a value is present the result must include its string
+     * representation in the result. Empty and present Optionals must be
+     * unambiguously differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return value != null
+            ? String.format("Optional[%s]", value)
+            : "Optional.empty";
+    }
+}
diff --git a/java/util/OptionalDouble.java b/java/util/OptionalDouble.java
new file mode 100644
index 0000000..7112df1
--- /dev/null
+++ b/java/util/OptionalDouble.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleSupplier;
+import java.util.function.Supplier;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A container object which may or may not contain a {@code double} value.
+ * If a value is present, {@code isPresent()} will return {@code true} and
+ * {@code getAsDouble()} will return the value.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(double) orElse()}
+ * (return a default value if value not present) and
+ * {@link #ifPresent(java.util.function.DoubleConsumer) ifPresent()} (execute a block
+ * of code if the value is present).
+ *
+ * @since 1.8
+ */
+public final class OptionalDouble {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final OptionalDouble EMPTY = new OptionalDouble();
+
+    /**
+     * If true then the value is present, otherwise indicates no value is present
+     */
+    private final boolean isPresent;
+    private final double value;
+
+    /**
+     * Construct an empty instance.
+     *
+     * @implNote generally only one empty instance, {@link OptionalDouble#EMPTY},
+     * should exist per VM.
+     */
+    private OptionalDouble() {
+        this.isPresent = false;
+        this.value = Double.NaN;
+    }
+
+    /**
+     * Returns an empty {@code OptionalDouble} instance.  No value is present for this
+     * OptionalDouble.
+     *
+     * @apiNote Though it may be tempting to do so, avoid testing if an object
+     * is empty by comparing with {@code ==} against instances returned by
+     * {@code Option.empty()}. There is no guarantee that it is a singleton.
+     * Instead, use {@link #isPresent()}.
+     *
+     *  @return an empty {@code OptionalDouble}.
+     */
+    public static OptionalDouble empty() {
+        return EMPTY;
+    }
+
+    /**
+     * Construct an instance with the value present.
+     *
+     * @param value the double value to be present.
+     */
+    private OptionalDouble(double value) {
+        this.isPresent = true;
+        this.value = value;
+    }
+
+    /**
+     * Return an {@code OptionalDouble} with the specified value present.
+     *
+     * @param value the value to be present
+     * @return an {@code OptionalDouble} with the value present
+     */
+    public static OptionalDouble of(double value) {
+        return new OptionalDouble(value);
+    }
+
+    /**
+     * If a value is present in this {@code OptionalDouble}, returns the value,
+     * otherwise throws {@code NoSuchElementException}.
+     *
+     * @return the value held by this {@code OptionalDouble}
+     * @throws NoSuchElementException if there is no value present
+     *
+     * @see OptionalDouble#isPresent()
+     */
+    public double getAsDouble() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * Return {@code true} if there is a value present, otherwise {@code false}.
+     *
+     * @return {@code true} if there is a value present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return isPresent;
+    }
+
+    /**
+     * Have the specified consumer accept the value if a value is present,
+     * otherwise do nothing.
+     *
+     * @param consumer block to be executed if a value is present
+     * @throws NullPointerException if value is present and {@code consumer} is
+     * null
+     */
+    public void ifPresent(DoubleConsumer consumer) {
+        if (isPresent)
+            consumer.accept(value);
+    }
+
+    /**
+     * Return the value if present, otherwise return {@code other}.
+     *
+     * @param other the value to be returned if there is no value present
+     * @return the value, if present, otherwise {@code other}
+     */
+    public double orElse(double other) {
+        return isPresent ? value : other;
+    }
+
+    /**
+     * Return the value if present, otherwise invoke {@code other} and return
+     * the result of that invocation.
+     *
+     * @param other a {@code DoubleSupplier} whose result is returned if no value
+     * is present
+     * @return the value if present otherwise the result of {@code other.getAsDouble()}
+     * @throws NullPointerException if value is not present and {@code other} is
+     * null
+     */
+    public double orElseGet(DoubleSupplier other) {
+        return isPresent ? value : other.getAsDouble();
+    }
+
+    /**
+     * Return the contained value, if present, otherwise throw an exception
+     * to be created by the provided supplier.
+     *
+     * @apiNote A method reference to the exception constructor with an empty
+     * argument list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier The supplier which will return the exception to
+     * be thrown
+     * @return the present value
+     * @throws X if there is no value present
+     * @throws NullPointerException if no value is present and
+     * {@code exceptionSupplier} is null
+     */
+    public<X extends Throwable> double orElseThrow(Supplier<X> exceptionSupplier) throws X {
+        if (isPresent) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this OptionalDouble. The
+     * other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code OptionalDouble} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via {@code Double.compare() == 0}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {code true} if the other object is "equal to" this object
+     * otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof OptionalDouble)) {
+            return false;
+        }
+
+        OptionalDouble other = (OptionalDouble) obj;
+        return (isPresent && other.isPresent)
+               ? Double.compare(value, other.value) == 0
+               : isPresent == other.isPresent;
+    }
+
+    /**
+     * Returns the hash code value of the present value, if any, or 0 (zero) if
+     * no value is present.
+     *
+     * @return hash code value of the present value or 0 if no value is present
+     */
+    @Override
+    public int hashCode() {
+        return isPresent ? Double.hashCode(value) : 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     *
+     * @implSpec If a value is present the result must include its string
+     * representation in the result. Empty and present instances must be
+     * unambiguously differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return isPresent
+                ? String.format("OptionalDouble[%s]", value)
+                : "OptionalDouble.empty";
+    }
+}
diff --git a/java/util/OptionalInt.java b/java/util/OptionalInt.java
new file mode 100644
index 0000000..61cac03
--- /dev/null
+++ b/java/util/OptionalInt.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+import java.util.function.Supplier;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A container object which may or may not contain a {@code int} value.
+ * If a value is present, {@code isPresent()} will return {@code true} and
+ * {@code getAsInt()} will return the value.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(int) orElse()}
+ * (return a default value if value not present) and
+ * {@link #ifPresent(java.util.function.IntConsumer) ifPresent()} (execute a block
+ * of code if the value is present).
+ *
+ * @since 1.8
+ */
+public final class OptionalInt {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final OptionalInt EMPTY = new OptionalInt();
+
+    /**
+     * If true then the value is present, otherwise indicates no value is present
+     */
+    private final boolean isPresent;
+    private final int value;
+
+    /**
+     * Construct an empty instance.
+     *
+     * @implNote Generally only one empty instance, {@link OptionalInt#EMPTY},
+     * should exist per VM.
+     */
+    private OptionalInt() {
+        this.isPresent = false;
+        this.value = 0;
+    }
+
+    /**
+     * Returns an empty {@code OptionalInt} instance.  No value is present for this
+     * OptionalInt.
+     *
+     * @apiNote Though it may be tempting to do so, avoid testing if an object
+     * is empty by comparing with {@code ==} against instances returned by
+     * {@code Option.empty()}. There is no guarantee that it is a singleton.
+     * Instead, use {@link #isPresent()}.
+     *
+     *  @return an empty {@code OptionalInt}
+     */
+    public static OptionalInt empty() {
+        return EMPTY;
+    }
+
+    /**
+     * Construct an instance with the value present.
+     *
+     * @param value the int value to be present
+     */
+    private OptionalInt(int value) {
+        this.isPresent = true;
+        this.value = value;
+    }
+
+    /**
+     * Return an {@code OptionalInt} with the specified value present.
+     *
+     * @param value the value to be present
+     * @return an {@code OptionalInt} with the value present
+     */
+    public static OptionalInt of(int value) {
+        return new OptionalInt(value);
+    }
+
+    /**
+     * If a value is present in this {@code OptionalInt}, returns the value,
+     * otherwise throws {@code NoSuchElementException}.
+     *
+     * @return the value held by this {@code OptionalInt}
+     * @throws NoSuchElementException if there is no value present
+     *
+     * @see OptionalInt#isPresent()
+     */
+    public int getAsInt() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * Return {@code true} if there is a value present, otherwise {@code false}.
+     *
+     * @return {@code true} if there is a value present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return isPresent;
+    }
+
+    /**
+     * Have the specified consumer accept the value if a value is present,
+     * otherwise do nothing.
+     *
+     * @param consumer block to be executed if a value is present
+     * @throws NullPointerException if value is present and {@code consumer} is
+     * null
+     */
+    public void ifPresent(IntConsumer consumer) {
+        if (isPresent)
+            consumer.accept(value);
+    }
+
+    /**
+     * Return the value if present, otherwise return {@code other}.
+     *
+     * @param other the value to be returned if there is no value present
+     * @return the value, if present, otherwise {@code other}
+     */
+    public int orElse(int other) {
+        return isPresent ? value : other;
+    }
+
+    /**
+     * Return the value if present, otherwise invoke {@code other} and return
+     * the result of that invocation.
+     *
+     * @param other a {@code IntSupplier} whose result is returned if no value
+     * is present
+     * @return the value if present otherwise the result of {@code other.getAsInt()}
+     * @throws NullPointerException if value is not present and {@code other} is
+     * null
+     */
+    public int orElseGet(IntSupplier other) {
+        return isPresent ? value : other.getAsInt();
+    }
+
+    /**
+     * Return the contained value, if present, otherwise throw an exception
+     * to be created by the provided supplier.
+     *
+     * @apiNote A method reference to the exception constructor with an empty
+     * argument list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier The supplier which will return the exception to
+     * be thrown
+     * @return the present value
+     * @throws X if there is no value present
+     * @throws NullPointerException if no value is present and
+     * {@code exceptionSupplier} is null
+     */
+    public<X extends Throwable> int orElseThrow(Supplier<X> exceptionSupplier) throws X {
+        if (isPresent) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this OptionalInt. The
+     * other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code OptionalInt} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via {@code ==}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {code true} if the other object is "equal to" this object
+     * otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof OptionalInt)) {
+            return false;
+        }
+
+        OptionalInt other = (OptionalInt) obj;
+        return (isPresent && other.isPresent)
+                ? value == other.value
+                : isPresent == other.isPresent;
+    }
+
+    /**
+     * Returns the hash code value of the present value, if any, or 0 (zero) if
+     * no value is present.
+     *
+     * @return hash code value of the present value or 0 if no value is present
+     */
+    @Override
+    public int hashCode() {
+        return isPresent ? Integer.hashCode(value) : 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     *
+     * @implSpec If a value is present the result must include its string
+     * representation in the result. Empty and present instances must be
+     * unambiguously differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return isPresent
+                ? String.format("OptionalInt[%s]", value)
+                : "OptionalInt.empty";
+    }
+}
diff --git a/java/util/OptionalLong.java b/java/util/OptionalLong.java
new file mode 100644
index 0000000..b337d83
--- /dev/null
+++ b/java/util/OptionalLong.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.LongConsumer;
+import java.util.function.LongSupplier;
+import java.util.function.Supplier;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A container object which may or may not contain a {@code long} value.
+ * If a value is present, {@code isPresent()} will return {@code true} and
+ * {@code getAsLong()} will return the value.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(long) orElse()}
+ * (return a default value if value not present) and
+ * {@link #ifPresent(java.util.function.LongConsumer) ifPresent()} (execute a block
+ * of code if the value is present).
+ *
+ * @since 1.8
+ */
+public final class OptionalLong {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final OptionalLong EMPTY = new OptionalLong();
+
+    /**
+     * If true then the value is present, otherwise indicates no value is present
+     */
+    private final boolean isPresent;
+    private final long value;
+
+    /**
+     * Construct an empty instance.
+     *
+     * @implNote generally only one empty instance, {@link OptionalLong#EMPTY},
+     * should exist per VM.
+     */
+    private OptionalLong() {
+        this.isPresent = false;
+        this.value = 0;
+    }
+
+    /**
+     * Returns an empty {@code OptionalLong} instance.  No value is present for this
+     * OptionalLong.
+     *
+     * @apiNote Though it may be tempting to do so, avoid testing if an object
+     * is empty by comparing with {@code ==} against instances returned by
+     * {@code Option.empty()}. There is no guarantee that it is a singleton.
+     * Instead, use {@link #isPresent()}.
+     *
+     *  @return an empty {@code OptionalLong}.
+     */
+    public static OptionalLong empty() {
+        return EMPTY;
+    }
+
+    /**
+     * Construct an instance with the value present.
+     *
+     * @param value the long value to be present
+     */
+    private OptionalLong(long value) {
+        this.isPresent = true;
+        this.value = value;
+    }
+
+    /**
+     * Return an {@code OptionalLong} with the specified value present.
+     *
+     * @param value the value to be present
+     * @return an {@code OptionalLong} with the value present
+     */
+    public static OptionalLong of(long value) {
+        return new OptionalLong(value);
+    }
+
+    /**
+     * If a value is present in this {@code OptionalLong}, returns the value,
+     * otherwise throws {@code NoSuchElementException}.
+     *
+     * @return the value held by this {@code OptionalLong}
+     * @throws NoSuchElementException if there is no value present
+     *
+     * @see OptionalLong#isPresent()
+     */
+    public long getAsLong() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * Return {@code true} if there is a value present, otherwise {@code false}.
+     *
+     * @return {@code true} if there is a value present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return isPresent;
+    }
+
+    /**
+     * Have the specified consumer accept the value if a value is present,
+     * otherwise do nothing.
+     *
+     * @param consumer block to be executed if a value is present
+     * @throws NullPointerException if value is present and {@code consumer} is
+     * null
+     */
+    public void ifPresent(LongConsumer consumer) {
+        if (isPresent)
+            consumer.accept(value);
+    }
+
+    /**
+     * Return the value if present, otherwise return {@code other}.
+     *
+     * @param other the value to be returned if there is no value present
+     * @return the value, if present, otherwise {@code other}
+     */
+    public long orElse(long other) {
+        return isPresent ? value : other;
+    }
+
+    /**
+     * Return the value if present, otherwise invoke {@code other} and return
+     * the result of that invocation.
+     *
+     * @param other a {@code LongSupplier} whose result is returned if no value
+     * is present
+     * @return the value if present otherwise the result of {@code other.getAsLong()}
+     * @throws NullPointerException if value is not present and {@code other} is
+     * null
+     */
+    public long orElseGet(LongSupplier other) {
+        return isPresent ? value : other.getAsLong();
+    }
+
+    /**
+     * Return the contained value, if present, otherwise throw an exception
+     * to be created by the provided supplier.
+     *
+     * @apiNote A method reference to the exception constructor with an empty
+     * argument list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier The supplier which will return the exception to
+     * be thrown
+     * @return the present value
+     * @throws X if there is no value present
+     * @throws NullPointerException if no value is present and
+     * {@code exceptionSupplier} is null
+     */
+    public<X extends Throwable> long orElseThrow(Supplier<X> exceptionSupplier) throws X {
+        if (isPresent) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this OptionalLong. The
+     * other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code OptionalLong} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via {@code ==}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {code true} if the other object is "equal to" this object
+     * otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof OptionalLong)) {
+            return false;
+        }
+
+        OptionalLong other = (OptionalLong) obj;
+        return (isPresent && other.isPresent)
+                ? value == other.value
+                : isPresent == other.isPresent;
+    }
+
+    /**
+     * Returns the hash code value of the present value, if any, or 0 (zero) if
+     * no value is present.
+     *
+     * @return hash code value of the present value or 0 if no value is present
+     */
+    @Override
+    public int hashCode() {
+        return isPresent ? Long.hashCode(value) : 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     *
+     * @implSpec If a value is present the result must include its string
+     * representation in the result. Empty and present instances must be
+     * unambiguously differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return isPresent
+                ? String.format("OptionalLong[%s]", value)
+                : "OptionalLong.empty";
+    }
+}
diff --git a/java/util/PrimitiveIterator.java b/java/util/PrimitiveIterator.java
new file mode 100644
index 0000000..2bc864a
--- /dev/null
+++ b/java/util/PrimitiveIterator.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * A base type for primitive specializations of {@code Iterator}.  Specialized
+ * subtypes are provided for {@link OfInt int}, {@link OfLong long}, and
+ * {@link OfDouble double} values.
+ *
+ * <p>The specialized subtype default implementations of {@link Iterator#next}
+ * and {@link Iterator#forEachRemaining(java.util.function.Consumer)} box
+ * primitive values to instances of their corresponding wrapper class.  Such
+ * boxing may offset any advantages gained when using the primitive
+ * specializations.  To avoid boxing, the corresponding primitive-based methods
+ * should be used.  For example, {@link PrimitiveIterator.OfInt#nextInt()} and
+ * {@link PrimitiveIterator.OfInt#forEachRemaining(java.util.function.IntConsumer)}
+ * should be used in preference to {@link PrimitiveIterator.OfInt#next()} and
+ * {@link PrimitiveIterator.OfInt#forEachRemaining(java.util.function.Consumer)}.
+ *
+ * <p>Iteration of primitive values using boxing-based methods
+ * {@link Iterator#next next()} and
+ * {@link Iterator#forEachRemaining(java.util.function.Consumer) forEachRemaining()},
+ * does not affect the order in which the values, transformed to boxed values,
+ * are encountered.
+ *
+ * @implNote
+ * If the boolean system property {@code org.openjdk.java.util.stream.tripwire}
+ * is set to {@code true} then diagnostic warnings are reported if boxing of
+ * primitive values occur when operating on primitive subtype specializations.
+ *
+ * @param <T> the type of elements returned by this PrimitiveIterator.  The
+ *        type must be a wrapper type for a primitive type, such as
+ *        {@code Integer} for the primitive {@code int} type.
+ * @param <T_CONS> the type of primitive consumer.  The type must be a
+ *        primitive specialization of {@link java.util.function.Consumer} for
+ *        {@code T}, such as {@link java.util.function.IntConsumer} for
+ *        {@code Integer}.
+ *
+ * @since 1.8
+ */
+public interface PrimitiveIterator<T, T_CONS> extends Iterator<T> {
+
+    /**
+     * Performs the given action for each remaining element, in the order
+     * elements occur when iterating, until all elements have been processed
+     * or the action throws an exception.  Errors or runtime exceptions
+     * thrown by the action are relayed to the caller.
+     *
+     * @param action The action to be performed for each element
+     * @throws NullPointerException if the specified action is null
+     */
+    @SuppressWarnings("overloads")
+    void forEachRemaining(T_CONS action);
+
+    /**
+     * An Iterator specialized for {@code int} values.
+     * @since 1.8
+     */
+    public static interface OfInt extends PrimitiveIterator<Integer, IntConsumer> {
+
+        /**
+         * Returns the next {@code int} element in the iteration.
+         *
+         * @return the next {@code int} element in the iteration
+         * @throws NoSuchElementException if the iteration has no more elements
+         */
+        int nextInt();
+
+        /**
+         * Performs the given action for each remaining element until all elements
+         * have been processed or the action throws an exception.  Actions are
+         * performed in the order of iteration, if that order is specified.
+         * Exceptions thrown by the action are relayed to the caller.
+         *
+         * @implSpec
+         * <p>The default implementation behaves as if:
+         * <pre>{@code
+         *     while (hasNext())
+         *         action.accept(nextInt());
+         * }</pre>
+         *
+         * @param action The action to be performed for each element
+         * @throws NullPointerException if the specified action is null
+         */
+        default void forEachRemaining(IntConsumer action) {
+            Objects.requireNonNull(action);
+            while (hasNext())
+                action.accept(nextInt());
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * The default implementation boxes the result of calling
+         * {@link #nextInt()}, and returns that boxed result.
+         */
+        @Override
+        default Integer next() {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.nextInt()");
+            return nextInt();
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code IntConsumer} then it is cast
+         * to {@code IntConsumer} and passed to {@link #forEachRemaining};
+         * otherwise the action is adapted to an instance of
+         * {@code IntConsumer}, by boxing the argument of {@code IntConsumer},
+         * and then passed to {@link #forEachRemaining}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Integer> action) {
+            if (action instanceof IntConsumer) {
+                forEachRemaining((IntConsumer) action);
+            }
+            else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.forEachRemainingInt(action::accept)");
+                forEachRemaining((IntConsumer) action::accept);
+            }
+        }
+
+    }
+
+    /**
+     * An Iterator specialized for {@code long} values.
+     * @since 1.8
+     */
+    public static interface OfLong extends PrimitiveIterator<Long, LongConsumer> {
+
+        /**
+         * Returns the next {@code long} element in the iteration.
+         *
+         * @return the next {@code long} element in the iteration
+         * @throws NoSuchElementException if the iteration has no more elements
+         */
+        long nextLong();
+
+        /**
+         * Performs the given action for each remaining element until all elements
+         * have been processed or the action throws an exception.  Actions are
+         * performed in the order of iteration, if that order is specified.
+         * Exceptions thrown by the action are relayed to the caller.
+         *
+         * @implSpec
+         * <p>The default implementation behaves as if:
+         * <pre>{@code
+         *     while (hasNext())
+         *         action.accept(nextLong());
+         * }</pre>
+         *
+         * @param action The action to be performed for each element
+         * @throws NullPointerException if the specified action is null
+         */
+        default void forEachRemaining(LongConsumer action) {
+            Objects.requireNonNull(action);
+            while (hasNext())
+                action.accept(nextLong());
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * The default implementation boxes the result of calling
+         * {@link #nextLong()}, and returns that boxed result.
+         */
+        @Override
+        default Long next() {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfLong.nextLong()");
+            return nextLong();
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code LongConsumer} then it is cast
+         * to {@code LongConsumer} and passed to {@link #forEachRemaining};
+         * otherwise the action is adapted to an instance of
+         * {@code LongConsumer}, by boxing the argument of {@code LongConsumer},
+         * and then passed to {@link #forEachRemaining}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Long> action) {
+            if (action instanceof LongConsumer) {
+                forEachRemaining((LongConsumer) action);
+            }
+            else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfLong.forEachRemainingLong(action::accept)");
+                forEachRemaining((LongConsumer) action::accept);
+            }
+        }
+    }
+
+    /**
+     * An Iterator specialized for {@code double} values.
+     * @since 1.8
+     */
+    public static interface OfDouble extends PrimitiveIterator<Double, DoubleConsumer> {
+
+        /**
+         * Returns the next {@code double} element in the iteration.
+         *
+         * @return the next {@code double} element in the iteration
+         * @throws NoSuchElementException if the iteration has no more elements
+         */
+        double nextDouble();
+
+        /**
+         * Performs the given action for each remaining element until all elements
+         * have been processed or the action throws an exception.  Actions are
+         * performed in the order of iteration, if that order is specified.
+         * Exceptions thrown by the action are relayed to the caller.
+         *
+         * @implSpec
+         * <p>The default implementation behaves as if:
+         * <pre>{@code
+         *     while (hasNext())
+         *         action.accept(nextDouble());
+         * }</pre>
+         *
+         * @param action The action to be performed for each element
+         * @throws NullPointerException if the specified action is null
+         */
+        default void forEachRemaining(DoubleConsumer action) {
+            Objects.requireNonNull(action);
+            while (hasNext())
+                action.accept(nextDouble());
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * The default implementation boxes the result of calling
+         * {@link #nextDouble()}, and returns that boxed result.
+         */
+        @Override
+        default Double next() {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfDouble.nextLong()");
+            return nextDouble();
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code DoubleConsumer} then it is
+         * cast to {@code DoubleConsumer} and passed to
+         * {@link #forEachRemaining}; otherwise the action is adapted to
+         * an instance of {@code DoubleConsumer}, by boxing the argument of
+         * {@code DoubleConsumer}, and then passed to
+         * {@link #forEachRemaining}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Double> action) {
+            if (action instanceof DoubleConsumer) {
+                forEachRemaining((DoubleConsumer) action);
+            }
+            else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfDouble.forEachRemainingDouble(action::accept)");
+                forEachRemaining((DoubleConsumer) action::accept);
+            }
+        }
+    }
+}
diff --git a/java/util/PriorityQueue.java b/java/util/PriorityQueue.java
new file mode 100644
index 0000000..7c929bd
--- /dev/null
+++ b/java/util/PriorityQueue.java
@@ -0,0 +1,909 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * An unbounded priority {@linkplain Queue queue} based on a priority heap.
+ * The elements of the priority queue are ordered according to their
+ * {@linkplain Comparable natural ordering}, or by a {@link Comparator}
+ * provided at queue construction time, depending on which constructor is
+ * used.  A priority queue does not permit {@code null} elements.
+ * A priority queue relying on natural ordering also does not permit
+ * insertion of non-comparable objects (doing so may result in
+ * {@code ClassCastException}).
+ *
+ * <p>The <em>head</em> of this queue is the <em>least</em> element
+ * with respect to the specified ordering.  If multiple elements are
+ * tied for least value, the head is one of those elements -- ties are
+ * broken arbitrarily.  The queue retrieval operations {@code poll},
+ * {@code remove}, {@code peek}, and {@code element} access the
+ * element at the head of the queue.
+ *
+ * <p>A priority queue is unbounded, but has an internal
+ * <i>capacity</i> governing the size of an array used to store the
+ * elements on the queue.  It is always at least as large as the queue
+ * size.  As elements are added to a priority queue, its capacity
+ * grows automatically.  The details of the growth policy are not
+ * specified.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.  The Iterator provided in method {@link
+ * #iterator()} is <em>not</em> guaranteed to traverse the elements of
+ * the priority queue in any particular order. If you need ordered
+ * traversal, consider using {@code Arrays.sort(pq.toArray())}.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * Multiple threads should not access a {@code PriorityQueue}
+ * instance concurrently if any of the threads modifies the queue.
+ * Instead, use the thread-safe {@link
+ * java.util.concurrent.PriorityBlockingQueue} class.
+ *
+ * <p>Implementation note: this implementation provides
+ * O(log(n)) time for the enqueuing and dequeuing methods
+ * ({@code offer}, {@code poll}, {@code remove()} and {@code add});
+ * linear time for the {@code remove(Object)} and {@code contains(Object)}
+ * methods; and constant time for the retrieval methods
+ * ({@code peek}, {@code element}, and {@code size}).
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Josh Bloch, Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class PriorityQueue<E> extends AbstractQueue<E>
+    implements java.io.Serializable {
+
+    private static final long serialVersionUID = -7720805057305804111L;
+
+    private static final int DEFAULT_INITIAL_CAPACITY = 11;
+
+    /**
+     * Priority queue represented as a balanced binary heap: the two
+     * children of queue[n] are queue[2*n+1] and queue[2*(n+1)].  The
+     * priority queue is ordered by comparator, or by the elements'
+     * natural ordering, if comparator is null: For each node n in the
+     * heap and each descendant d of n, n <= d.  The element with the
+     * lowest value is in queue[0], assuming the queue is nonempty.
+     */
+    transient Object[] queue; // non-private to simplify nested class access
+
+    /**
+     * The number of elements in the priority queue.
+     */
+    int size;
+
+    /**
+     * The comparator, or null if priority queue uses elements'
+     * natural ordering.
+     */
+    private final Comparator<? super E> comparator;
+
+    /**
+     * The number of times this priority queue has been
+     * <i>structurally modified</i>.  See AbstractList for gory details.
+     */
+    transient int modCount;     // non-private to simplify nested class access
+
+    /**
+     * Creates a {@code PriorityQueue} with the default initial
+     * capacity (11) that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     */
+    public PriorityQueue() {
+        this(DEFAULT_INITIAL_CAPACITY, null);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} with the specified initial
+     * capacity that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     *
+     * @param initialCapacity the initial capacity for this priority queue
+     * @throws IllegalArgumentException if {@code initialCapacity} is less
+     *         than 1
+     */
+    public PriorityQueue(int initialCapacity) {
+        this(initialCapacity, null);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} with the default initial capacity and
+     * whose elements are ordered according to the specified comparator.
+     *
+     * @param  comparator the comparator that will be used to order this
+     *         priority queue.  If {@code null}, the {@linkplain Comparable
+     *         natural ordering} of the elements will be used.
+     * @since 1.8
+     */
+    public PriorityQueue(Comparator<? super E> comparator) {
+        this(DEFAULT_INITIAL_CAPACITY, comparator);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} with the specified initial capacity
+     * that orders its elements according to the specified comparator.
+     *
+     * @param  initialCapacity the initial capacity for this priority queue
+     * @param  comparator the comparator that will be used to order this
+     *         priority queue.  If {@code null}, the {@linkplain Comparable
+     *         natural ordering} of the elements will be used.
+     * @throws IllegalArgumentException if {@code initialCapacity} is
+     *         less than 1
+     */
+    public PriorityQueue(int initialCapacity,
+                         Comparator<? super E> comparator) {
+        // Note: This restriction of at least one is not actually needed,
+        // but continues for 1.5 compatibility
+        if (initialCapacity < 1)
+            throw new IllegalArgumentException();
+        this.queue = new Object[initialCapacity];
+        this.comparator = comparator;
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} containing the elements in the
+     * specified collection.  If the specified collection is an instance of
+     * a {@link SortedSet} or is another {@code PriorityQueue}, this
+     * priority queue will be ordered according to the same ordering.
+     * Otherwise, this priority queue will be ordered according to the
+     * {@linkplain Comparable natural ordering} of its elements.
+     *
+     * @param  c the collection whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of the specified collection
+     *         cannot be compared to one another according to the priority
+     *         queue's ordering
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    @SuppressWarnings("unchecked")
+    public PriorityQueue(Collection<? extends E> c) {
+        if (c instanceof SortedSet<?>) {
+            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
+            this.comparator = (Comparator<? super E>) ss.comparator();
+            initElementsFromCollection(ss);
+        }
+        else if (c instanceof PriorityQueue<?>) {
+            PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
+            this.comparator = (Comparator<? super E>) pq.comparator();
+            initFromPriorityQueue(pq);
+        }
+        else {
+            this.comparator = null;
+            initFromCollection(c);
+        }
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} containing the elements in the
+     * specified priority queue.  This priority queue will be
+     * ordered according to the same ordering as the given priority
+     * queue.
+     *
+     * @param  c the priority queue whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of {@code c} cannot be
+     *         compared to one another according to {@code c}'s
+     *         ordering
+     * @throws NullPointerException if the specified priority queue or any
+     *         of its elements are null
+     */
+    @SuppressWarnings("unchecked")
+    public PriorityQueue(PriorityQueue<? extends E> c) {
+        this.comparator = (Comparator<? super E>) c.comparator();
+        initFromPriorityQueue(c);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} containing the elements in the
+     * specified sorted set.   This priority queue will be ordered
+     * according to the same ordering as the given sorted set.
+     *
+     * @param  c the sorted set whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of the specified sorted
+     *         set cannot be compared to one another according to the
+     *         sorted set's ordering
+     * @throws NullPointerException if the specified sorted set or any
+     *         of its elements are null
+     */
+    @SuppressWarnings("unchecked")
+    public PriorityQueue(SortedSet<? extends E> c) {
+        this.comparator = (Comparator<? super E>) c.comparator();
+        initElementsFromCollection(c);
+    }
+
+    private void initFromPriorityQueue(PriorityQueue<? extends E> c) {
+        if (c.getClass() == PriorityQueue.class) {
+            this.queue = c.toArray();
+            this.size = c.size();
+        } else {
+            initFromCollection(c);
+        }
+    }
+
+    private void initElementsFromCollection(Collection<? extends E> c) {
+        Object[] a = c.toArray();
+        // If c.toArray incorrectly doesn't return Object[], copy it.
+        if (a.getClass() != Object[].class)
+            a = Arrays.copyOf(a, a.length, Object[].class);
+        int len = a.length;
+        if (len == 1 || this.comparator != null)
+            for (Object e : a)
+                if (e == null)
+                    throw new NullPointerException();
+        this.queue = a;
+        this.size = a.length;
+    }
+
+    /**
+     * Initializes queue array with elements from the given Collection.
+     *
+     * @param c the collection
+     */
+    private void initFromCollection(Collection<? extends E> c) {
+        initElementsFromCollection(c);
+        heapify();
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Increases the capacity of the array.
+     *
+     * @param minCapacity the desired minimum capacity
+     */
+    private void grow(int minCapacity) {
+        int oldCapacity = queue.length;
+        // Double size if small; else grow by 50%
+        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
+                                         (oldCapacity + 2) :
+                                         (oldCapacity >> 1));
+        // overflow-conscious code
+        if (newCapacity - MAX_ARRAY_SIZE > 0)
+            newCapacity = hugeCapacity(minCapacity);
+        queue = Arrays.copyOf(queue, newCapacity);
+    }
+
+    private static int hugeCapacity(int minCapacity) {
+        if (minCapacity < 0) // overflow
+            throw new OutOfMemoryError();
+        return (minCapacity > MAX_ARRAY_SIZE) ?
+            Integer.MAX_VALUE :
+            MAX_ARRAY_SIZE;
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     *
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with elements currently in this priority queue
+     *         according to the priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     *
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with elements currently in this priority queue
+     *         according to the priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        modCount++;
+        int i = size;
+        if (i >= queue.length)
+            grow(i + 1);
+        size = i + 1;
+        if (i == 0)
+            queue[0] = e;
+        else
+            siftUp(i, e);
+        return true;
+    }
+
+    @SuppressWarnings("unchecked")
+    public E peek() {
+        return (size == 0) ? null : (E) queue[0];
+    }
+
+    private int indexOf(Object o) {
+        if (o != null) {
+            for (int i = 0; i < size; i++)
+                if (o.equals(queue[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.  Returns {@code true} if and only if this queue contained
+     * the specified element (or equivalently, if this queue changed as a
+     * result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        int i = indexOf(o);
+        if (i == -1)
+            return false;
+        else {
+            removeAt(i);
+            return true;
+        }
+    }
+
+    /**
+     * Version of remove using reference equality, not equals.
+     * Needed by iterator.remove.
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if removed
+     */
+    boolean removeEq(Object o) {
+        for (int i = 0; i < size; i++) {
+            if (o == queue[i]) {
+                removeAt(i);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        return indexOf(o) >= 0;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue.
+     * The elements are in no particular order.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        return Arrays.copyOf(queue, size);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue; the
+     * runtime type of the returned array is that of the specified array.
+     * The returned array elements are in no particular order.
+     * If the queue fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this queue.
+     *
+     * <p>If the queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than the queue), the element in
+     * the array immediately following the end of the collection is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        final int size = this.size;
+        if (a.length < size)
+            // Make a new array of a's runtime type, but my contents:
+            return (T[]) Arrays.copyOf(queue, size, a.getClass());
+        System.arraycopy(queue, 0, a, 0, size);
+        if (a.length > size)
+            a[size] = null;
+        return a;
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue. The iterator
+     * does not return the elements in any particular order.
+     *
+     * @return an iterator over the elements in this queue
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    private final class Itr implements Iterator<E> {
+        /**
+         * Index (into queue array) of element to be returned by
+         * subsequent call to next.
+         */
+        private int cursor;
+
+        /**
+         * Index of element returned by most recent call to next,
+         * unless that element came from the forgetMeNot list.
+         * Set to -1 if element is deleted by a call to remove.
+         */
+        private int lastRet = -1;
+
+        /**
+         * A queue of elements that were moved from the unvisited portion of
+         * the heap into the visited portion as a result of "unlucky" element
+         * removals during the iteration.  (Unlucky element removals are those
+         * that require a siftup instead of a siftdown.)  We must visit all of
+         * the elements in this list to complete the iteration.  We do this
+         * after we've completed the "normal" iteration.
+         *
+         * We expect that most iterations, even those involving removals,
+         * will not need to store elements in this field.
+         */
+        private ArrayDeque<E> forgetMeNot;
+
+        /**
+         * Element returned by the most recent call to next iff that
+         * element was drawn from the forgetMeNot list.
+         */
+        private E lastRetElt;
+
+        /**
+         * The modCount value that the iterator believes that the backing
+         * Queue should have.  If this expectation is violated, the iterator
+         * has detected concurrent modification.
+         */
+        private int expectedModCount = modCount;
+
+        public boolean hasNext() {
+            return cursor < size ||
+                (forgetMeNot != null && !forgetMeNot.isEmpty());
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (expectedModCount != modCount)
+                throw new ConcurrentModificationException();
+            if (cursor < size)
+                return (E) queue[lastRet = cursor++];
+            if (forgetMeNot != null) {
+                lastRet = -1;
+                lastRetElt = forgetMeNot.poll();
+                if (lastRetElt != null)
+                    return lastRetElt;
+            }
+            throw new NoSuchElementException();
+        }
+
+        public void remove() {
+            if (expectedModCount != modCount)
+                throw new ConcurrentModificationException();
+            if (lastRet != -1) {
+                E moved = PriorityQueue.this.removeAt(lastRet);
+                lastRet = -1;
+                if (moved == null)
+                    cursor--;
+                else {
+                    if (forgetMeNot == null)
+                        forgetMeNot = new ArrayDeque<>();
+                    forgetMeNot.add(moved);
+                }
+            } else if (lastRetElt != null) {
+                PriorityQueue.this.removeEq(lastRetElt);
+                lastRetElt = null;
+            } else {
+                throw new IllegalStateException();
+            }
+            expectedModCount = modCount;
+        }
+    }
+
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Removes all of the elements from this priority queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+        for (int i = 0; i < size; i++)
+            queue[i] = null;
+        size = 0;
+    }
+
+    @SuppressWarnings("unchecked")
+    public E poll() {
+        if (size == 0)
+            return null;
+        int s = --size;
+        modCount++;
+        E result = (E) queue[0];
+        E x = (E) queue[s];
+        queue[s] = null;
+        if (s != 0)
+            siftDown(0, x);
+        return result;
+    }
+
+    /**
+     * Removes the ith element from queue.
+     *
+     * Normally this method leaves the elements at up to i-1,
+     * inclusive, untouched.  Under these circumstances, it returns
+     * null.  Occasionally, in order to maintain the heap invariant,
+     * it must swap a later element of the list with one earlier than
+     * i.  Under these circumstances, this method returns the element
+     * that was previously at the end of the list and is now at some
+     * position before i. This fact is used by iterator.remove so as to
+     * avoid missing traversing elements.
+     */
+    @SuppressWarnings("unchecked")
+    E removeAt(int i) {
+        // assert i >= 0 && i < size;
+        modCount++;
+        int s = --size;
+        if (s == i) // removed last element
+            queue[i] = null;
+        else {
+            E moved = (E) queue[s];
+            queue[s] = null;
+            siftDown(i, moved);
+            if (queue[i] == moved) {
+                siftUp(i, moved);
+                if (queue[i] != moved)
+                    return moved;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * promoting x up the tree until it is greater than or equal to
+     * its parent, or is the root.
+     *
+     * To simplify and speed up coercions and comparisons. the
+     * Comparable and Comparator versions are separated into different
+     * methods that are otherwise identical. (Similarly for siftDown.)
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     */
+    private void siftUp(int k, E x) {
+        if (comparator != null)
+            siftUpUsingComparator(k, x);
+        else
+            siftUpComparable(k, x);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void siftUpComparable(int k, E x) {
+        Comparable<? super E> key = (Comparable<? super E>) x;
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = queue[parent];
+            if (key.compareTo((E) e) >= 0)
+                break;
+            queue[k] = e;
+            k = parent;
+        }
+        queue[k] = key;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void siftUpUsingComparator(int k, E x) {
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = queue[parent];
+            if (comparator.compare(x, (E) e) >= 0)
+                break;
+            queue[k] = e;
+            k = parent;
+        }
+        queue[k] = x;
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * demoting x down the tree repeatedly until it is less than or
+     * equal to its children or is a leaf.
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     */
+    private void siftDown(int k, E x) {
+        if (comparator != null)
+            siftDownUsingComparator(k, x);
+        else
+            siftDownComparable(k, x);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void siftDownComparable(int k, E x) {
+        Comparable<? super E> key = (Comparable<? super E>)x;
+        int half = size >>> 1;        // loop while a non-leaf
+        while (k < half) {
+            int child = (k << 1) + 1; // assume left child is least
+            Object c = queue[child];
+            int right = child + 1;
+            if (right < size &&
+                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
+                c = queue[child = right];
+            if (key.compareTo((E) c) <= 0)
+                break;
+            queue[k] = c;
+            k = child;
+        }
+        queue[k] = key;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void siftDownUsingComparator(int k, E x) {
+        int half = size >>> 1;
+        while (k < half) {
+            int child = (k << 1) + 1;
+            Object c = queue[child];
+            int right = child + 1;
+            if (right < size &&
+                comparator.compare((E) c, (E) queue[right]) > 0)
+                c = queue[child = right];
+            if (comparator.compare(x, (E) c) <= 0)
+                break;
+            queue[k] = c;
+            k = child;
+        }
+        queue[k] = x;
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the entire tree,
+     * assuming nothing about the order of the elements prior to the call.
+     */
+    @SuppressWarnings("unchecked")
+    private void heapify() {
+        for (int i = (size >>> 1) - 1; i >= 0; i--)
+            siftDown(i, (E) queue[i]);
+    }
+
+    /**
+     * Returns the comparator used to order the elements in this
+     * queue, or {@code null} if this queue is sorted according to
+     * the {@linkplain Comparable natural ordering} of its elements.
+     *
+     * @return the comparator used to order this queue, or
+     *         {@code null} if this queue is sorted according to the
+     *         natural ordering of its elements
+     */
+    public Comparator<? super E> comparator() {
+        return comparator;
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @serialData The length of the array backing the instance is
+     *             emitted (int), followed by all of its elements
+     *             (each an {@code Object}) in the proper order.
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out element count, and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out array length, for compatibility with 1.5 version
+        s.writeInt(Math.max(2, size + 1));
+
+        // Write out all elements in the "proper order".
+        for (int i = 0; i < size; i++)
+            s.writeObject(queue[i]);
+    }
+
+    /**
+     * Reconstitutes the {@code PriorityQueue} instance from a stream
+     * (that is, deserializes it).
+     *
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in size, and any hidden stuff
+        s.defaultReadObject();
+
+        // Read in (and discard) array length
+        s.readInt();
+
+        queue = new Object[size];
+
+        // Read in all elements.
+        for (int i = 0; i < size; i++)
+            queue[i] = s.readObject();
+
+        // Elements are guaranteed to be in "proper order", but the
+        // spec has never explained what that might be.
+        heapify();
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * queue.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#NONNULL}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public final Spliterator<E> spliterator() {
+        return new PriorityQueueSpliterator<>(this, 0, -1, 0);
+    }
+
+    static final class PriorityQueueSpliterator<E> implements Spliterator<E> {
+        /*
+         * This is very similar to ArrayList Spliterator, except for
+         * extra null checks.
+         */
+        private final PriorityQueue<E> pq;
+        private int index;            // current index, modified on advance/split
+        private int fence;            // -1 until first use
+        private int expectedModCount; // initialized when fence set
+
+        /** Creates new spliterator covering the given range. */
+        PriorityQueueSpliterator(PriorityQueue<E> pq, int origin, int fence,
+                                 int expectedModCount) {
+            this.pq = pq;
+            this.index = origin;
+            this.fence = fence;
+            this.expectedModCount = expectedModCount;
+        }
+
+        private int getFence() { // initialize fence to size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                expectedModCount = pq.modCount;
+                hi = fence = pq.size;
+            }
+            return hi;
+        }
+
+        public PriorityQueueSpliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new PriorityQueueSpliterator<>(pq, lo, index = mid,
+                                               expectedModCount);
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            int i, hi, mc; // hoist accesses and checks from loop
+            PriorityQueue<E> q; Object[] a;
+            if (action == null)
+                throw new NullPointerException();
+            if ((q = pq) != null && (a = q.queue) != null) {
+                if ((hi = fence) < 0) {
+                    mc = q.modCount;
+                    hi = q.size;
+                }
+                else
+                    mc = expectedModCount;
+                if ((i = index) >= 0 && (index = hi) <= a.length) {
+                    for (E e;; ++i) {
+                        if (i < hi) {
+                            if ((e = (E) a[i]) == null) // must be CME
+                                break;
+                            action.accept(e);
+                        }
+                        else if (q.modCount != mc)
+                            break;
+                        else
+                            return;
+                    }
+                }
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int hi = getFence(), lo = index;
+            if (lo >= 0 && lo < hi) {
+                index = lo + 1;
+                @SuppressWarnings("unchecked") E e = (E)pq.queue[lo];
+                if (e == null)
+                    throw new ConcurrentModificationException();
+                action.accept(e);
+                if (pq.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                return true;
+            }
+            return false;
+        }
+
+        public long estimateSize() {
+            return (long) (getFence() - index);
+        }
+
+        public int characteristics() {
+            return Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL;
+        }
+    }
+}
diff --git a/java/util/Properties.java b/java/util/Properties.java
new file mode 100644
index 0000000..b413abb
--- /dev/null
+++ b/java/util/Properties.java
@@ -0,0 +1,1232 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.io.OutputStreamWriter;
+import java.io.BufferedWriter;
+
+// Android-removed: Dead native2ascii links.
+// These links are also gone in OpenJDK 9.
+/**
+ * The {@code Properties} class represents a persistent set of
+ * properties. The {@code Properties} can be saved to a stream
+ * or loaded from a stream. Each key and its corresponding value in
+ * the property list is a string.
+ * <p>
+ * A property list can contain another property list as its
+ * "defaults"; this second property list is searched if
+ * the property key is not found in the original property list.
+ * <p>
+ * Because {@code Properties} inherits from {@code Hashtable}, the
+ * {@code put} and {@code putAll} methods can be applied to a
+ * {@code Properties} object.  Their use is strongly discouraged as they
+ * allow the caller to insert entries whose keys or values are not
+ * {@code Strings}.  The {@code setProperty} method should be used
+ * instead.  If the {@code store} or {@code save} method is called
+ * on a "compromised" {@code Properties} object that contains a
+ * non-{@code String} key or value, the call will fail. Similarly,
+ * the call to the {@code propertyNames} or {@code list} method
+ * will fail if it is called on a "compromised" {@code Properties}
+ * object that contains a non-{@code String} key.
+ *
+ * <p>
+ * The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt>
+ * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)}
+ * methods load and store properties from and to a character based stream
+ * in a simple line-oriented format specified below.
+ *
+ * The {@link #load(java.io.InputStream) load(InputStream)} <tt>/</tt>
+ * {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)}
+ * methods work the same way as the load(Reader)/store(Writer, String) pair, except
+ * the input/output stream is encoded in ISO 8859-1 character encoding.
+ * Characters that cannot be directly represented in this encoding can be written using
+ * Unicode escapes as defined in section 3.3 of
+ * <cite>The Java&trade; Language Specification</cite>;
+ * only a single 'u' character is allowed in an escape
+ * sequence. The native2ascii tool can be used to convert property files to and
+ * from other character encodings.
+ *
+ * <p> The {@link #loadFromXML(InputStream)} and {@link
+ * #storeToXML(OutputStream, String, String)} methods load and store properties
+ * in a simple XML format.  By default the UTF-8 character encoding is used,
+ * however a specific encoding may be specified if required. Implementations
+ * are required to support UTF-8 and UTF-16 and may support other encodings.
+ * An XML properties document has the following DOCTYPE declaration:
+ *
+ * <pre>
+ * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
+ * </pre>
+ * Note that the system URI (http://java.sun.com/dtd/properties.dtd) is
+ * <i>not</i> accessed when exporting or importing properties; it merely
+ * serves as a string to uniquely identify the DTD, which is:
+ * <pre>
+ *    &lt;?xml version="1.0" encoding="UTF-8"?&gt;
+ *
+ *    &lt;!-- DTD for properties --&gt;
+ *
+ *    &lt;!ELEMENT properties ( comment?, entry* ) &gt;
+ *
+ *    &lt;!ATTLIST properties version CDATA #FIXED "1.0"&gt;
+ *
+ *    &lt;!ELEMENT comment (#PCDATA) &gt;
+ *
+ *    &lt;!ELEMENT entry (#PCDATA) &gt;
+ *
+ *    &lt;!ATTLIST entry key CDATA #REQUIRED&gt;
+ * </pre>
+ *
+ * <p>This class is thread-safe: multiple threads can share a single
+ * <tt>Properties</tt> object without the need for external synchronization.
+ *
+ * @author  Arthur van Hoff
+ * @author  Michael McCloskey
+ * @author  Xueming Shen
+ * @since   JDK1.0
+ */
+public
+class Properties extends Hashtable<Object,Object> {
+    /**
+     * use serialVersionUID from JDK 1.1.X for interoperability
+     */
+     private static final long serialVersionUID = 4112578634029874840L;
+
+    /**
+     * A property list that contains default values for any keys not
+     * found in this property list.
+     *
+     * @serial
+     */
+    protected Properties defaults;
+
+    /**
+     * Creates an empty property list with no default values.
+     */
+    public Properties() {
+        this(null);
+    }
+
+    /**
+     * Creates an empty property list with the specified defaults.
+     *
+     * @param   defaults   the defaults.
+     */
+    public Properties(Properties defaults) {
+        this.defaults = defaults;
+    }
+
+    /**
+     * Calls the <tt>Hashtable</tt> method {@code put}. Provided for
+     * parallelism with the <tt>getProperty</tt> method. Enforces use of
+     * strings for property keys and values. The value returned is the
+     * result of the <tt>Hashtable</tt> call to {@code put}.
+     *
+     * @param key the key to be placed into this property list.
+     * @param value the value corresponding to <tt>key</tt>.
+     * @return     the previous value of the specified key in this property
+     *             list, or {@code null} if it did not have one.
+     * @see #getProperty
+     * @since    1.2
+     */
+    public synchronized Object setProperty(String key, String value) {
+        return put(key, value);
+    }
+
+
+    /**
+     * Reads a property list (key and element pairs) from the input
+     * character stream in a simple line-oriented format.
+     * <p>
+     * Properties are processed in terms of lines. There are two
+     * kinds of line, <i>natural lines</i> and <i>logical lines</i>.
+     * A natural line is defined as a line of
+     * characters that is terminated either by a set of line terminator
+     * characters ({@code \n} or {@code \r} or {@code \r\n})
+     * or by the end of the stream. A natural line may be either a blank line,
+     * a comment line, or hold all or some of a key-element pair. A logical
+     * line holds all the data of a key-element pair, which may be spread
+     * out across several adjacent natural lines by escaping
+     * the line terminator sequence with a backslash character
+     * {@code \}.  Note that a comment line cannot be extended
+     * in this manner; every natural line that is a comment must have
+     * its own comment indicator, as described below. Lines are read from
+     * input until the end of the stream is reached.
+     *
+     * <p>
+     * A natural line that contains only white space characters is
+     * considered blank and is ignored.  A comment line has an ASCII
+     * {@code '#'} or {@code '!'} as its first non-white
+     * space character; comment lines are also ignored and do not
+     * encode key-element information.  In addition to line
+     * terminators, this format considers the characters space
+     * ({@code ' '}, {@code '\u005Cu0020'}), tab
+     * ({@code '\t'}, {@code '\u005Cu0009'}), and form feed
+     * ({@code '\f'}, {@code '\u005Cu000C'}) to be white
+     * space.
+     *
+     * <p>
+     * If a logical line is spread across several natural lines, the
+     * backslash escaping the line terminator sequence, the line
+     * terminator sequence, and any white space at the start of the
+     * following line have no affect on the key or element values.
+     * The remainder of the discussion of key and element parsing
+     * (when loading) will assume all the characters constituting
+     * the key and element appear on a single natural line after
+     * line continuation characters have been removed.  Note that
+     * it is <i>not</i> sufficient to only examine the character
+     * preceding a line terminator sequence to decide if the line
+     * terminator is escaped; there must be an odd number of
+     * contiguous backslashes for the line terminator to be escaped.
+     * Since the input is processed from left to right, a
+     * non-zero even number of 2<i>n</i> contiguous backslashes
+     * before a line terminator (or elsewhere) encodes <i>n</i>
+     * backslashes after escape processing.
+     *
+     * <p>
+     * The key contains all of the characters in the line starting
+     * with the first non-white space character and up to, but not
+     * including, the first unescaped {@code '='},
+     * {@code ':'}, or white space character other than a line
+     * terminator. All of these key termination characters may be
+     * included in the key by escaping them with a preceding backslash
+     * character; for example,<p>
+     *
+     * {@code \:\=}<p>
+     *
+     * would be the two-character key {@code ":="}.  Line
+     * terminator characters can be included using {@code \r} and
+     * {@code \n} escape sequences.  Any white space after the
+     * key is skipped; if the first non-white space character after
+     * the key is {@code '='} or {@code ':'}, then it is
+     * ignored and any white space characters after it are also
+     * skipped.  All remaining characters on the line become part of
+     * the associated element string; if there are no remaining
+     * characters, the element is the empty string
+     * {@code ""}.  Once the raw character sequences
+     * constituting the key and element are identified, escape
+     * processing is performed as described above.
+     *
+     * <p>
+     * As an example, each of the following three lines specifies the key
+     * {@code "Truth"} and the associated element value
+     * {@code "Beauty"}:
+     * <pre>
+     * Truth = Beauty
+     *  Truth:Beauty
+     * Truth                    :Beauty
+     * </pre>
+     * As another example, the following three lines specify a single
+     * property:
+     * <pre>
+     * fruits                           apple, banana, pear, \
+     *                                  cantaloupe, watermelon, \
+     *                                  kiwi, mango
+     * </pre>
+     * The key is {@code "fruits"} and the associated element is:
+     * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre>
+     * Note that a space appears before each {@code \} so that a space
+     * will appear after each comma in the final result; the {@code \},
+     * line terminator, and leading white space on the continuation line are
+     * merely discarded and are <i>not</i> replaced by one or more other
+     * characters.
+     * <p>
+     * As a third example, the line:
+     * <pre>cheeses
+     * </pre>
+     * specifies that the key is {@code "cheeses"} and the associated
+     * element is the empty string {@code ""}.
+     * <p>
+     * <a name="unicodeescapes"></a>
+     * Characters in keys and elements can be represented in escape
+     * sequences similar to those used for character and string literals
+     * (see sections 3.3 and 3.10.6 of
+     * <cite>The Java&trade; Language Specification</cite>).
+     *
+     * The differences from the character escape sequences and Unicode
+     * escapes used for characters and strings are:
+     *
+     * <ul>
+     * <li> Octal escapes are not recognized.
+     *
+     * <li> The character sequence {@code \b} does <i>not</i>
+     * represent a backspace character.
+     *
+     * <li> The method does not treat a backslash character,
+     * {@code \}, before a non-valid escape character as an
+     * error; the backslash is silently dropped.  For example, in a
+     * Java string the sequence {@code "\z"} would cause a
+     * compile time error.  In contrast, this method silently drops
+     * the backslash.  Therefore, this method treats the two character
+     * sequence {@code "\b"} as equivalent to the single
+     * character {@code 'b'}.
+     *
+     * <li> Escapes are not necessary for single and double quotes;
+     * however, by the rule above, single and double quote characters
+     * preceded by a backslash still yield single and double quote
+     * characters, respectively.
+     *
+     * <li> Only a single 'u' character is allowed in a Unicode escape
+     * sequence.
+     *
+     * </ul>
+     * <p>
+     * The specified stream remains open after this method returns.
+     *
+     * @param   reader   the input character stream.
+     * @throws  IOException  if an error occurred when reading from the
+     *          input stream.
+     * @throws  IllegalArgumentException if a malformed Unicode escape
+     *          appears in the input.
+     * @since   1.6
+     */
+    public synchronized void load(Reader reader) throws IOException {
+        load0(new LineReader(reader));
+    }
+
+    /**
+     * Reads a property list (key and element pairs) from the input
+     * byte stream. The input stream is in a simple line-oriented
+     * format as specified in
+     * {@link #load(java.io.Reader) load(Reader)} and is assumed to use
+     * the ISO 8859-1 character encoding; that is each byte is one Latin1
+     * character. Characters not in Latin1, and certain special characters,
+     * are represented in keys and elements using Unicode escapes as defined in
+     * section 3.3 of
+     * <cite>The Java&trade; Language Specification</cite>.
+     * <p>
+     * The specified stream remains open after this method returns.
+     *
+     * @param      inStream   the input stream.
+     * @exception  IOException  if an error occurred when reading from the
+     *             input stream.
+     * @throws     IllegalArgumentException if the input stream contains a
+     *             malformed Unicode escape sequence.
+     * @since 1.2
+     */
+    public synchronized void load(InputStream inStream) throws IOException {
+        load0(new LineReader(inStream));
+    }
+
+    private void load0 (LineReader lr) throws IOException {
+        char[] convtBuf = new char[1024];
+        int limit;
+        int keyLen;
+        int valueStart;
+        char c;
+        boolean hasSep;
+        boolean precedingBackslash;
+
+        while ((limit = lr.readLine()) >= 0) {
+            c = 0;
+            keyLen = 0;
+            valueStart = limit;
+            hasSep = false;
+
+            //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
+            precedingBackslash = false;
+            while (keyLen < limit) {
+                c = lr.lineBuf[keyLen];
+                //need check if escaped.
+                if ((c == '=' ||  c == ':') && !precedingBackslash) {
+                    valueStart = keyLen + 1;
+                    hasSep = true;
+                    break;
+                // Android-changed: Treat all whitespace the same. http://b/25998006
+                // } else if ((c == ' ' || c == '\t' ||  c == '\f') && !precedingBackslash) {
+                } else if (Character.isWhitespace(c) && !precedingBackslash) {
+                    valueStart = keyLen + 1;
+                    break;
+                }
+                if (c == '\\') {
+                    precedingBackslash = !precedingBackslash;
+                } else {
+                    precedingBackslash = false;
+                }
+                keyLen++;
+            }
+            while (valueStart < limit) {
+                c = lr.lineBuf[valueStart];
+                // Android-changed: Treat all whitespace the same. http://b/25998006
+                // if (c != ' ' && c != '\t' &&  c != '\f') {
+                if (!Character.isWhitespace(c)) {
+                    if (!hasSep && (c == '=' ||  c == ':')) {
+                        hasSep = true;
+                    } else {
+                        break;
+                    }
+                }
+                valueStart++;
+            }
+            String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
+            String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
+            put(key, value);
+        }
+    }
+
+    /* Read in a "logical line" from an InputStream/Reader, skip all comment
+     * and blank lines and filter out those leading whitespace characters
+     * (\u0020, \u0009 and \u000c) from the beginning of a "natural line".
+     * Method returns the char length of the "logical line" and stores
+     * the line in "lineBuf".
+     */
+    class LineReader {
+        public LineReader(InputStream inStream) {
+            this.inStream = inStream;
+            inByteBuf = new byte[8192];
+        }
+
+        public LineReader(Reader reader) {
+            this.reader = reader;
+            inCharBuf = new char[8192];
+        }
+
+        byte[] inByteBuf;
+        char[] inCharBuf;
+        char[] lineBuf = new char[1024];
+        int inLimit = 0;
+        int inOff = 0;
+        InputStream inStream;
+        Reader reader;
+
+        int readLine() throws IOException {
+            int len = 0;
+            char c = 0;
+
+            boolean skipWhiteSpace = true;
+            boolean isCommentLine = false;
+            boolean isNewLine = true;
+            boolean appendedLineBegin = false;
+            boolean precedingBackslash = false;
+            boolean skipLF = false;
+
+            while (true) {
+                if (inOff >= inLimit) {
+                    inLimit = (inStream==null)?reader.read(inCharBuf)
+                                              :inStream.read(inByteBuf);
+                    inOff = 0;
+                    if (inLimit <= 0) {
+                        if (len == 0 || isCommentLine) {
+                            return -1;
+                        }
+                        if (precedingBackslash) {
+                            len--;
+                        }
+                        return len;
+                    }
+                }
+                if (inStream != null) {
+                    //The line below is equivalent to calling a
+                    //ISO8859-1 decoder.
+                    c = (char) (0xff & inByteBuf[inOff++]);
+                } else {
+                    c = inCharBuf[inOff++];
+                }
+                if (skipLF) {
+                    skipLF = false;
+                    if (c == '\n') {
+                        continue;
+                    }
+                }
+                if (skipWhiteSpace) {
+                    // Android-changed: Treat all whitespace the same. http://b/25998006
+                    // if (c == ' ' || c == '\t' || c == '\f') {
+                    if (Character.isWhitespace(c)) {
+                        continue;
+                    }
+                    if (!appendedLineBegin && (c == '\r' || c == '\n')) {
+                        continue;
+                    }
+                    skipWhiteSpace = false;
+                    appendedLineBegin = false;
+                }
+                if (isNewLine) {
+                    isNewLine = false;
+                    if (c == '#' || c == '!') {
+                        isCommentLine = true;
+                        continue;
+                    }
+                }
+
+                if (c != '\n' && c != '\r') {
+                    lineBuf[len++] = c;
+                    if (len == lineBuf.length) {
+                        int newLength = lineBuf.length * 2;
+                        if (newLength < 0) {
+                            newLength = Integer.MAX_VALUE;
+                        }
+                        char[] buf = new char[newLength];
+                        System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length);
+                        lineBuf = buf;
+                    }
+                    //flip the preceding backslash flag
+                    if (c == '\\') {
+                        precedingBackslash = !precedingBackslash;
+                    } else {
+                        precedingBackslash = false;
+                    }
+                }
+                else {
+                    // reached EOL
+                    if (isCommentLine || len == 0) {
+                        isCommentLine = false;
+                        isNewLine = true;
+                        skipWhiteSpace = true;
+                        len = 0;
+                        continue;
+                    }
+                    if (inOff >= inLimit) {
+                        inLimit = (inStream==null)
+                                  ?reader.read(inCharBuf)
+                                  :inStream.read(inByteBuf);
+                        inOff = 0;
+                        if (inLimit <= 0) {
+                            if (precedingBackslash) {
+                                len--;
+                            }
+                            return len;
+                        }
+                    }
+                    if (precedingBackslash) {
+                        len -= 1;
+                        //skip the leading whitespace characters in following line
+                        skipWhiteSpace = true;
+                        appendedLineBegin = true;
+                        precedingBackslash = false;
+                        if (c == '\r') {
+                            skipLF = true;
+                        }
+                    } else {
+                        return len;
+                    }
+                }
+            }
+        }
+    }
+
+    /*
+     * Converts encoded &#92;uxxxx to unicode chars
+     * and changes special saved chars to their original forms
+     */
+    private String loadConvert (char[] in, int off, int len, char[] convtBuf) {
+        if (convtBuf.length < len) {
+            int newLen = len * 2;
+            if (newLen < 0) {
+                newLen = Integer.MAX_VALUE;
+            }
+            convtBuf = new char[newLen];
+        }
+        char aChar;
+        char[] out = convtBuf;
+        int outLen = 0;
+        int end = off + len;
+
+        while (off < end) {
+            aChar = in[off++];
+            if (aChar == '\\') {
+                aChar = in[off++];
+                if(aChar == 'u') {
+                    // Read the xxxx
+                    int value=0;
+                    for (int i=0; i<4; i++) {
+                        aChar = in[off++];
+                        switch (aChar) {
+                          case '0': case '1': case '2': case '3': case '4':
+                          case '5': case '6': case '7': case '8': case '9':
+                             value = (value << 4) + aChar - '0';
+                             break;
+                          case 'a': case 'b': case 'c':
+                          case 'd': case 'e': case 'f':
+                             value = (value << 4) + 10 + aChar - 'a';
+                             break;
+                          case 'A': case 'B': case 'C':
+                          case 'D': case 'E': case 'F':
+                             value = (value << 4) + 10 + aChar - 'A';
+                             break;
+                          default:
+                              throw new IllegalArgumentException(
+                                           "Malformed \\uxxxx encoding.");
+                        }
+                     }
+                    out[outLen++] = (char)value;
+                } else {
+                    if (aChar == 't') aChar = '\t';
+                    else if (aChar == 'r') aChar = '\r';
+                    else if (aChar == 'n') aChar = '\n';
+                    else if (aChar == 'f') aChar = '\f';
+                    out[outLen++] = aChar;
+                }
+            } else {
+                out[outLen++] = aChar;
+            }
+        }
+        return new String (out, 0, outLen);
+    }
+
+    /*
+     * Converts unicodes to encoded &#92;uxxxx and escapes
+     * special characters with a preceding slash
+     */
+    private String saveConvert(String theString,
+                               boolean escapeSpace,
+                               boolean escapeUnicode) {
+        int len = theString.length();
+        int bufLen = len * 2;
+        if (bufLen < 0) {
+            bufLen = Integer.MAX_VALUE;
+        }
+        StringBuffer outBuffer = new StringBuffer(bufLen);
+
+        for(int x=0; x<len; x++) {
+            char aChar = theString.charAt(x);
+            // Handle common case first, selecting largest block that
+            // avoids the specials below
+            if ((aChar > 61) && (aChar < 127)) {
+                if (aChar == '\\') {
+                    outBuffer.append('\\'); outBuffer.append('\\');
+                    continue;
+                }
+                outBuffer.append(aChar);
+                continue;
+            }
+            switch(aChar) {
+                case ' ':
+                    if (x == 0 || escapeSpace)
+                        outBuffer.append('\\');
+                    outBuffer.append(' ');
+                    break;
+                case '\t':outBuffer.append('\\'); outBuffer.append('t');
+                          break;
+                case '\n':outBuffer.append('\\'); outBuffer.append('n');
+                          break;
+                case '\r':outBuffer.append('\\'); outBuffer.append('r');
+                          break;
+                case '\f':outBuffer.append('\\'); outBuffer.append('f');
+                          break;
+                case '=': // Fall through
+                case ':': // Fall through
+                case '#': // Fall through
+                case '!':
+                    outBuffer.append('\\'); outBuffer.append(aChar);
+                    break;
+                default:
+                    if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) {
+                        outBuffer.append('\\');
+                        outBuffer.append('u');
+                        outBuffer.append(toHex((aChar >> 12) & 0xF));
+                        outBuffer.append(toHex((aChar >>  8) & 0xF));
+                        outBuffer.append(toHex((aChar >>  4) & 0xF));
+                        outBuffer.append(toHex( aChar        & 0xF));
+                    } else {
+                        outBuffer.append(aChar);
+                    }
+            }
+        }
+        return outBuffer.toString();
+    }
+
+    private static void writeComments(BufferedWriter bw, String comments)
+        throws IOException {
+        bw.write("#");
+        int len = comments.length();
+        int current = 0;
+        int last = 0;
+        char[] uu = new char[6];
+        uu[0] = '\\';
+        uu[1] = 'u';
+        while (current < len) {
+            char c = comments.charAt(current);
+            if (c > '\u00ff' || c == '\n' || c == '\r') {
+                if (last != current)
+                    bw.write(comments.substring(last, current));
+                if (c > '\u00ff') {
+                    uu[2] = toHex((c >> 12) & 0xf);
+                    uu[3] = toHex((c >>  8) & 0xf);
+                    uu[4] = toHex((c >>  4) & 0xf);
+                    uu[5] = toHex( c        & 0xf);
+                    bw.write(new String(uu));
+                } else {
+                    bw.newLine();
+                    if (c == '\r' &&
+                        current != len - 1 &&
+                        comments.charAt(current + 1) == '\n') {
+                        current++;
+                    }
+                    if (current == len - 1 ||
+                        (comments.charAt(current + 1) != '#' &&
+                        comments.charAt(current + 1) != '!'))
+                        bw.write("#");
+                }
+                last = current + 1;
+            }
+            current++;
+        }
+        if (last != current)
+            bw.write(comments.substring(last, current));
+        bw.newLine();
+    }
+
+    /**
+     * Calls the {@code store(OutputStream out, String comments)} method
+     * and suppresses IOExceptions that were thrown.
+     *
+     * @deprecated This method does not throw an IOException if an I/O error
+     * occurs while saving the property list.  The preferred way to save a
+     * properties list is via the {@code store(OutputStream out,
+     * String comments)} method or the
+     * {@code storeToXML(OutputStream os, String comment)} method.
+     *
+     * @param   out      an output stream.
+     * @param   comments   a description of the property list.
+     * @exception  ClassCastException  if this {@code Properties} object
+     *             contains any keys or values that are not
+     *             {@code Strings}.
+     */
+    @Deprecated
+    public void save(OutputStream out, String comments)  {
+        try {
+            store(out, comments);
+        } catch (IOException e) {
+        }
+    }
+
+    /**
+     * Writes this property list (key and element pairs) in this
+     * {@code Properties} table to the output character stream in a
+     * format suitable for using the {@link #load(java.io.Reader) load(Reader)}
+     * method.
+     * <p>
+     * Properties from the defaults table of this {@code Properties}
+     * table (if any) are <i>not</i> written out by this method.
+     * <p>
+     * If the comments argument is not null, then an ASCII {@code #}
+     * character, the comments string, and a line separator are first written
+     * to the output stream. Thus, the {@code comments} can serve as an
+     * identifying comment. Any one of a line feed ('\n'), a carriage
+     * return ('\r'), or a carriage return followed immediately by a line feed
+     * in comments is replaced by a line separator generated by the {@code Writer}
+     * and if the next character in comments is not character {@code #} or
+     * character {@code !} then an ASCII {@code #} is written out
+     * after that line separator.
+     * <p>
+     * Next, a comment line is always written, consisting of an ASCII
+     * {@code #} character, the current date and time (as if produced
+     * by the {@code toString} method of {@code Date} for the
+     * current time), and a line separator as generated by the {@code Writer}.
+     * <p>
+     * Then every entry in this {@code Properties} table is
+     * written out, one per line. For each entry the key string is
+     * written, then an ASCII {@code =}, then the associated
+     * element string. For the key, all space characters are
+     * written with a preceding {@code \} character.  For the
+     * element, leading space characters, but not embedded or trailing
+     * space characters, are written with a preceding {@code \}
+     * character. The key and element characters {@code #},
+     * {@code !}, {@code =}, and {@code :} are written
+     * with a preceding backslash to ensure that they are properly loaded.
+     * <p>
+     * After the entries have been written, the output stream is flushed.
+     * The output stream remains open after this method returns.
+     * <p>
+     *
+     * @param   writer      an output character stream writer.
+     * @param   comments   a description of the property list.
+     * @exception  IOException if writing this property list to the specified
+     *             output stream throws an <tt>IOException</tt>.
+     * @exception  ClassCastException  if this {@code Properties} object
+     *             contains any keys or values that are not {@code Strings}.
+     * @exception  NullPointerException  if {@code writer} is null.
+     * @since 1.6
+     */
+    public void store(Writer writer, String comments)
+        throws IOException
+    {
+        store0((writer instanceof BufferedWriter)?(BufferedWriter)writer
+                                                 : new BufferedWriter(writer),
+               comments,
+               false);
+    }
+
+    /**
+     * Writes this property list (key and element pairs) in this
+     * {@code Properties} table to the output stream in a format suitable
+     * for loading into a {@code Properties} table using the
+     * {@link #load(InputStream) load(InputStream)} method.
+     * <p>
+     * Properties from the defaults table of this {@code Properties}
+     * table (if any) are <i>not</i> written out by this method.
+     * <p>
+     * This method outputs the comments, properties keys and values in
+     * the same format as specified in
+     * {@link #store(java.io.Writer, java.lang.String) store(Writer)},
+     * with the following differences:
+     * <ul>
+     * <li>The stream is written using the ISO 8859-1 character encoding.
+     *
+     * <li>Characters not in Latin-1 in the comments are written as
+     * {@code \u005Cu}<i>xxxx</i> for their appropriate unicode
+     * hexadecimal value <i>xxxx</i>.
+     *
+     * <li>Characters less than {@code \u005Cu0020} and characters greater
+     * than {@code \u005Cu007E} in property keys or values are written
+     * as {@code \u005Cu}<i>xxxx</i> for the appropriate hexadecimal
+     * value <i>xxxx</i>.
+     * </ul>
+     * <p>
+     * After the entries have been written, the output stream is flushed.
+     * The output stream remains open after this method returns.
+     * <p>
+     * @param   out      an output stream.
+     * @param   comments   a description of the property list.
+     * @exception  IOException if writing this property list to the specified
+     *             output stream throws an <tt>IOException</tt>.
+     * @exception  ClassCastException  if this {@code Properties} object
+     *             contains any keys or values that are not {@code Strings}.
+     * @exception  NullPointerException  if {@code out} is null.
+     * @since 1.2
+     */
+    public void store(OutputStream out, String comments)
+        throws IOException
+    {
+        store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
+               comments,
+               true);
+    }
+
+    private void store0(BufferedWriter bw, String comments, boolean escUnicode)
+        throws IOException
+    {
+        if (comments != null) {
+            writeComments(bw, comments);
+        }
+        bw.write("#" + new Date().toString());
+        bw.newLine();
+        synchronized (this) {
+            for (Enumeration<?> e = keys(); e.hasMoreElements();) {
+                String key = (String)e.nextElement();
+                String val = (String)get(key);
+                key = saveConvert(key, true, escUnicode);
+                /* No need to escape embedded and trailing spaces for value, hence
+                 * pass false to flag.
+                 */
+                val = saveConvert(val, false, escUnicode);
+                bw.write(key + "=" + val);
+                bw.newLine();
+            }
+        }
+        bw.flush();
+    }
+
+    /**
+     * Loads all of the properties represented by the XML document on the
+     * specified input stream into this properties table.
+     *
+     * <p>The XML document must have the following DOCTYPE declaration:
+     * <pre>
+     * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
+     * </pre>
+     * Furthermore, the document must satisfy the properties DTD described
+     * above.
+     *
+     * <p> An implementation is required to read XML documents that use the
+     * "{@code UTF-8}" or "{@code UTF-16}" encoding. An implementation may
+     * support additional encodings.
+     *
+     * <p>The specified stream is closed after this method returns.
+     *
+     * @param in the input stream from which to read the XML document.
+     * @throws IOException if reading from the specified input stream
+     *         results in an <tt>IOException</tt>.
+     * @throws java.io.UnsupportedEncodingException if the document's encoding
+     *         declaration can be read and it specifies an encoding that is not
+     *         supported
+     * @throws InvalidPropertiesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     * @throws NullPointerException if {@code in} is null.
+     * @see    #storeToXML(OutputStream, String, String)
+     * @see    <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
+     *         Encoding in Entities</a>
+     * @since 1.5
+     */
+    public synchronized void loadFromXML(InputStream in)
+        throws IOException, InvalidPropertiesFormatException
+    {
+        // Android-changed: Keep OpenJDK7u40's XmlUtils.
+        // XmlSupport's system property based XmlPropertiesProvider
+        // selection does not make sense on Android and has too many
+        // dependencies on classes that are not available on Android.
+        //
+        // XmlSupport.load(this, Objects.requireNonNull(in));
+        XMLUtils.load(this, Objects.requireNonNull(in));
+        in.close();
+    }
+
+    /**
+     * Emits an XML document representing all of the properties contained
+     * in this table.
+     *
+     * <p> An invocation of this method of the form <tt>props.storeToXML(os,
+     * comment)</tt> behaves in exactly the same way as the invocation
+     * <tt>props.storeToXML(os, comment, "UTF-8");</tt>.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @param comment a description of the property list, or {@code null}
+     *        if no comment is desired.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws NullPointerException if {@code os} is null.
+     * @throws ClassCastException  if this {@code Properties} object
+     *         contains any keys or values that are not
+     *         {@code Strings}.
+     * @see    #loadFromXML(InputStream)
+     * @since 1.5
+     */
+    public void storeToXML(OutputStream os, String comment)
+        throws IOException
+    {
+        storeToXML(os, comment, "UTF-8");
+    }
+
+    /**
+     * Emits an XML document representing all of the properties contained
+     * in this table, using the specified encoding.
+     *
+     * <p>The XML document will have the following DOCTYPE declaration:
+     * <pre>
+     * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
+     * </pre>
+     *
+     * <p>If the specified comment is {@code null} then no comment
+     * will be stored in the document.
+     *
+     * <p> An implementation is required to support writing of XML documents
+     * that use the "{@code UTF-8}" or "{@code UTF-16}" encoding. An
+     * implementation may support additional encodings.
+     *
+     * <p>The specified stream remains open after this method returns.
+     *
+     * @param os        the output stream on which to emit the XML document.
+     * @param comment   a description of the property list, or {@code null}
+     *                  if no comment is desired.
+     * @param  encoding the name of a supported
+     *                  <a href="../lang/package-summary.html#charenc">
+     *                  character encoding</a>
+     *
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws java.io.UnsupportedEncodingException if the encoding is not
+     *         supported by the implementation.
+     * @throws NullPointerException if {@code os} is {@code null},
+     *         or if {@code encoding} is {@code null}.
+     * @throws ClassCastException  if this {@code Properties} object
+     *         contains any keys or values that are not
+     *         {@code Strings}.
+     * @see    #loadFromXML(InputStream)
+     * @see    <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
+     *         Encoding in Entities</a>
+     * @since 1.5
+     */
+    public void storeToXML(OutputStream os, String comment, String encoding)
+        throws IOException
+    {
+        // Android-changed: Keep OpenJDK7u40's XmlUtils.
+        // XmlSupport's system property based XmlPropertiesProvider
+        // selection does not make sense on Android and has too many
+        // dependencies on classes that are not available on Android.
+        //
+        // XmlSupport.save(this, Objects.requireNonNull(os), comment,
+        //                Objects.requireNonNull(encoding));
+        XMLUtils.save(this, Objects.requireNonNull(os), comment,
+                       Objects.requireNonNull(encoding));
+    }
+
+    /**
+     * Searches for the property with the specified key in this property list.
+     * If the key is not found in this property list, the default property list,
+     * and its defaults, recursively, are then checked. The method returns
+     * {@code null} if the property is not found.
+     *
+     * @param   key   the property key.
+     * @return  the value in this property list with the specified key value.
+     * @see     #setProperty
+     * @see     #defaults
+     */
+    public String getProperty(String key) {
+        Object oval = super.get(key);
+        String sval = (oval instanceof String) ? (String)oval : null;
+        return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
+    }
+
+    /**
+     * Searches for the property with the specified key in this property list.
+     * If the key is not found in this property list, the default property list,
+     * and its defaults, recursively, are then checked. The method returns the
+     * default value argument if the property is not found.
+     *
+     * @param   key            the hashtable key.
+     * @param   defaultValue   a default value.
+     *
+     * @return  the value in this property list with the specified key value.
+     * @see     #setProperty
+     * @see     #defaults
+     */
+    public String getProperty(String key, String defaultValue) {
+        String val = getProperty(key);
+        return (val == null) ? defaultValue : val;
+    }
+
+    /**
+     * Returns an enumeration of all the keys in this property list,
+     * including distinct keys in the default property list if a key
+     * of the same name has not already been found from the main
+     * properties list.
+     *
+     * @return  an enumeration of all the keys in this property list, including
+     *          the keys in the default property list.
+     * @throws  ClassCastException if any key in this property list
+     *          is not a string.
+     * @see     java.util.Enumeration
+     * @see     java.util.Properties#defaults
+     * @see     #stringPropertyNames
+     */
+    public Enumeration<?> propertyNames() {
+        Hashtable<String,Object> h = new Hashtable<>();
+        enumerate(h);
+        return h.keys();
+    }
+
+    /**
+     * Returns a set of keys in this property list where
+     * the key and its corresponding value are strings,
+     * including distinct keys in the default property list if a key
+     * of the same name has not already been found from the main
+     * properties list.  Properties whose key or value is not
+     * of type <tt>String</tt> are omitted.
+     * <p>
+     * The returned set is not backed by the <tt>Properties</tt> object.
+     * Changes to this <tt>Properties</tt> are not reflected in the set,
+     * or vice versa.
+     *
+     * @return  a set of keys in this property list where
+     *          the key and its corresponding value are strings,
+     *          including the keys in the default property list.
+     * @see     java.util.Properties#defaults
+     * @since   1.6
+     */
+    public Set<String> stringPropertyNames() {
+        Hashtable<String, String> h = new Hashtable<>();
+        enumerateStringProperties(h);
+        return h.keySet();
+    }
+
+    /**
+     * Prints this property list out to the specified output stream.
+     * This method is useful for debugging.
+     *
+     * @param   out   an output stream.
+     * @throws  ClassCastException if any key in this property list
+     *          is not a string.
+     */
+    public void list(PrintStream out) {
+        out.println("-- listing properties --");
+        Hashtable<String,Object> h = new Hashtable<>();
+        enumerate(h);
+        for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) {
+            String key = e.nextElement();
+            String val = (String)h.get(key);
+            if (val.length() > 40) {
+                val = val.substring(0, 37) + "...";
+            }
+            out.println(key + "=" + val);
+        }
+    }
+
+    /**
+     * Prints this property list out to the specified output stream.
+     * This method is useful for debugging.
+     *
+     * @param   out   an output stream.
+     * @throws  ClassCastException if any key in this property list
+     *          is not a string.
+     * @since   JDK1.1
+     */
+    /*
+     * Rather than use an anonymous inner class to share common code, this
+     * method is duplicated in order to ensure that a non-1.1 compiler can
+     * compile this file.
+     */
+    public void list(PrintWriter out) {
+        out.println("-- listing properties --");
+        Hashtable<String,Object> h = new Hashtable<>();
+        enumerate(h);
+        for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) {
+            String key = e.nextElement();
+            String val = (String)h.get(key);
+            if (val.length() > 40) {
+                val = val.substring(0, 37) + "...";
+            }
+            out.println(key + "=" + val);
+        }
+    }
+
+    /**
+     * Enumerates all key/value pairs in the specified hashtable.
+     * @param h the hashtable
+     * @throws ClassCastException if any of the property keys
+     *         is not of String type.
+     */
+    private synchronized void enumerate(Hashtable<String,Object> h) {
+        if (defaults != null) {
+            defaults.enumerate(h);
+        }
+        for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
+            String key = (String)e.nextElement();
+            h.put(key, get(key));
+        }
+    }
+
+    /**
+     * Enumerates all key/value pairs in the specified hashtable
+     * and omits the property if the key or value is not a string.
+     * @param h the hashtable
+     */
+    private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
+        if (defaults != null) {
+            defaults.enumerateStringProperties(h);
+        }
+        for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
+            Object k = e.nextElement();
+            Object v = get(k);
+            if (k instanceof String && v instanceof String) {
+                h.put((String) k, (String) v);
+            }
+        }
+    }
+
+    /**
+     * Convert a nibble to a hex character
+     * @param   nibble  the nibble to convert.
+     */
+    private static char toHex(int nibble) {
+        return hexDigit[(nibble & 0xF)];
+    }
+
+    /** A table of hex digits */
+    private static final char[] hexDigit = {
+        '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
+    };
+
+    // Android-removed: Keep OpenJDK7u40's XmlUtils.
+    // XmlSupport's system property based XmlPropertiesProvider
+    // selection does not make sense on Android and has too many
+    // dependencies on classes that are not available on Android.
+    /*
+    /**
+     * Supporting class for loading/storing properties in XML format.
+     *
+     * <p> The {@code load} and {@code store} methods defined here delegate to a
+     * system-wide {@code XmlPropertiesProvider}. On first invocation of either
+     * method then the system-wide provider is located as follows: </p>
+     *
+     * <ol>
+     *   <li> If the system property {@code sun.util.spi.XmlPropertiesProvider}
+     *   is defined then it is taken to be the full-qualified name of a concrete
+     *   provider class. The class is loaded with the system class loader as the
+     *   initiating loader. If it cannot be loaded or instantiated using a zero
+     *   argument constructor then an unspecified error is thrown. </li>
+     *
+     *   <li> If the system property is not defined then the service-provider
+     *   loading facility defined by the {@link ServiceLoader} class is used to
+     *   locate a provider with the system class loader as the initiating
+     *   loader and {@code sun.util.spi.XmlPropertiesProvider} as the service
+     *   type. If this process fails then an unspecified error is thrown. If
+     *   there is more than one service provider installed then it is
+     *   not specified as to which provider will be used. </li>
+     *
+     *   <li> If the provider is not found by the above means then a system
+     *   default provider will be instantiated and used. </li>
+     * </ol>
+     *
+    private static class XmlSupport {
+
+        private static XmlPropertiesProvider loadProviderFromProperty(ClassLoader cl) {
+            String cn = System.getProperty("sun.util.spi.XmlPropertiesProvider");
+            if (cn == null)
+                return null;
+            try {
+                Class<?> c = Class.forName(cn, true, cl);
+                return (XmlPropertiesProvider)c.newInstance();
+            } catch (ClassNotFoundException |
+                     IllegalAccessException |
+                     InstantiationException x) {
+                throw new ServiceConfigurationError(null, x);
+            }
+        }
+
+        private static XmlPropertiesProvider loadProviderAsService(ClassLoader cl) {
+            Iterator<XmlPropertiesProvider> iterator =
+                 ServiceLoader.load(XmlPropertiesProvider.class, cl).iterator();
+            return iterator.hasNext() ? iterator.next() : null;
+        }
+
+        private static XmlPropertiesProvider loadProvider() {
+            return AccessController.doPrivileged(
+                new PrivilegedAction<XmlPropertiesProvider>() {
+                    public XmlPropertiesProvider run() {
+                        ClassLoader cl = ClassLoader.getSystemClassLoader();
+                        XmlPropertiesProvider provider = loadProviderFromProperty(cl);
+                        if (provider != null)
+                            return provider;
+                        provider = loadProviderAsService(cl);
+                        if (provider != null)
+                            return provider;
+                        return new jdk.internal.util.xml.BasicXmlPropertiesProvider();
+                }});
+        }
+
+        private static final XmlPropertiesProvider PROVIDER = loadProvider();
+
+        static void load(Properties props, InputStream in)
+            throws IOException, InvalidPropertiesFormatException
+        {
+            PROVIDER.load(props, in);
+        }
+
+        static void save(Properties props, OutputStream os, String comment,
+                         String encoding)
+            throws IOException
+        {
+            PROVIDER.store(props, os, comment, encoding);
+        }
+    }
+    */
+}
diff --git a/java/util/PropertyPermission.java b/java/util/PropertyPermission.java
new file mode 100644
index 0000000..ac7b521
--- /dev/null
+++ b/java/util/PropertyPermission.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.security.*;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+public final class PropertyPermission extends BasicPermission {
+
+    public PropertyPermission(String name, String actions) { super("", ""); }
+}
diff --git a/java/util/PropertyResourceBundle.java b/java/util/PropertyResourceBundle.java
new file mode 100644
index 0000000..23c3ffe
--- /dev/null
+++ b/java/util/PropertyResourceBundle.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ */
+
+package java.util;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.IOException;
+import sun.util.ResourceBundleEnumeration;
+
+/**
+ * <code>PropertyResourceBundle</code> is a concrete subclass of
+ * <code>ResourceBundle</code> that manages resources for a locale
+ * using a set of static strings from a property file. See
+ * {@link ResourceBundle ResourceBundle} for more information about resource
+ * bundles.
+ *
+ * <p>
+ * Unlike other types of resource bundle, you don't subclass
+ * <code>PropertyResourceBundle</code>.  Instead, you supply properties
+ * files containing the resource data.  <code>ResourceBundle.getBundle</code>
+ * will automatically look for the appropriate properties file and create a
+ * <code>PropertyResourceBundle</code> that refers to it. See
+ * {@link ResourceBundle#getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader) ResourceBundle.getBundle}
+ * for a complete description of the search and instantiation strategy.
+ *
+ * <p>
+ * The following <a name="sample">example</a> shows a member of a resource
+ * bundle family with the base name "MyResources".
+ * The text defines the bundle "MyResources_de",
+ * the German member of the bundle family.
+ * This member is based on <code>PropertyResourceBundle</code>, and the text
+ * therefore is the content of the file "MyResources_de.properties"
+ * (a related <a href="ListResourceBundle.html#sample">example</a> shows
+ * how you can add bundles to this family that are implemented as subclasses
+ * of <code>ListResourceBundle</code>).
+ * The keys in this example are of the form "s1" etc. The actual
+ * keys are entirely up to your choice, so long as they are the same as
+ * the keys you use in your program to retrieve the objects from the bundle.
+ * Keys are case-sensitive.
+ * <blockquote>
+ * <pre>
+ * # MessageFormat pattern
+ * s1=Die Platte \"{1}\" enth&auml;lt {0}.
+ *
+ * # location of {0} in pattern
+ * s2=1
+ *
+ * # sample disk name
+ * s3=Meine Platte
+ *
+ * # first ChoiceFormat choice
+ * s4=keine Dateien
+ *
+ * # second ChoiceFormat choice
+ * s5=eine Datei
+ *
+ * # third ChoiceFormat choice
+ * s6={0,number} Dateien
+ *
+ * # sample date
+ * s7=3. M&auml;rz 1996
+ * </pre>
+ * </blockquote>
+ *
+ * <p>
+ * The implementation of a {@code PropertyResourceBundle} subclass must be
+ * thread-safe if it's simultaneously used by multiple threads. The default
+ * implementations of the non-abstract methods in this class are thread-safe.
+ *
+ * <p>
+ * <strong>Note:</strong> PropertyResourceBundle can be constructed either
+ * from an InputStream or a Reader, which represents a property file.
+ * Constructing a PropertyResourceBundle instance from an InputStream requires
+ * that the input stream be encoded in ISO-8859-1.  In that case, characters
+ * that cannot be represented in ISO-8859-1 encoding must be represented by Unicode Escapes
+ * as defined in section 3.3 of
+ * <cite>The Java&trade; Language Specification</cite>
+ * whereas the other constructor which takes a Reader does not have that limitation.
+ *
+ * @see ResourceBundle
+ * @see ListResourceBundle
+ * @see Properties
+ * @since JDK1.1
+ */
+public class PropertyResourceBundle extends ResourceBundle {
+    /**
+     * Creates a property resource bundle from an {@link java.io.InputStream
+     * InputStream}.  The property file read with this constructor
+     * must be encoded in ISO-8859-1.
+     *
+     * @param stream an InputStream that represents a property file
+     *        to read from.
+     * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if <code>stream</code> is null
+     * @throws IllegalArgumentException if {@code stream} contains a
+     *     malformed Unicode escape sequence.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public PropertyResourceBundle (InputStream stream) throws IOException {
+        Properties properties = new Properties();
+        properties.load(stream);
+        lookup = new HashMap(properties);
+    }
+
+    /**
+     * Creates a property resource bundle from a {@link java.io.Reader
+     * Reader}.  Unlike the constructor
+     * {@link #PropertyResourceBundle(java.io.InputStream) PropertyResourceBundle(InputStream)},
+     * there is no limitation as to the encoding of the input property file.
+     *
+     * @param reader a Reader that represents a property file to
+     *        read from.
+     * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if <code>reader</code> is null
+     * @throws IllegalArgumentException if a malformed Unicode escape sequence appears
+     *     from {@code reader}.
+     * @since 1.6
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public PropertyResourceBundle (Reader reader) throws IOException {
+        Properties properties = new Properties();
+        properties.load(reader);
+        lookup = new HashMap(properties);
+    }
+
+    // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
+    public Object handleGetObject(String key) {
+        if (key == null) {
+            throw new NullPointerException();
+        }
+        return lookup.get(key);
+    }
+
+    /**
+     * Returns an <code>Enumeration</code> of the keys contained in
+     * this <code>ResourceBundle</code> and its parent bundles.
+     *
+     * @return an <code>Enumeration</code> of the keys contained in
+     *         this <code>ResourceBundle</code> and its parent bundles.
+     * @see #keySet()
+     */
+    public Enumeration<String> getKeys() {
+        ResourceBundle parent = this.parent;
+        return new ResourceBundleEnumeration(lookup.keySet(),
+                (parent != null) ? parent.getKeys() : null);
+    }
+
+    /**
+     * Returns a <code>Set</code> of the keys contained
+     * <em>only</em> in this <code>ResourceBundle</code>.
+     *
+     * @return a <code>Set</code> of the keys contained only in this
+     *         <code>ResourceBundle</code>
+     * @since 1.6
+     * @see #keySet()
+     */
+    protected Set<String> handleKeySet() {
+        return lookup.keySet();
+    }
+
+    // ==================privates====================
+
+    // Android-changed: Fix unsafe publication http://b/31467561
+    // Fixed in OpenJDK 9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/29ecac30ecae
+    // was: private Map<String,Object> lookup;
+    private final Map<String,Object> lookup;
+}
diff --git a/java/util/Queue.annotated.java b/java/util/Queue.annotated.java
new file mode 100644
index 0000000..33c666a
--- /dev/null
+++ b/java/util/Queue.annotated.java
@@ -0,0 +1,54 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Queue<E> extends java.util.Collection<E> {
+
+public boolean add(@libcore.util.NullFromTypeParam E e);
+
+public boolean offer(@libcore.util.NullFromTypeParam E e);
+
[email protected] public E remove();
+
[email protected] public E poll();
+
[email protected] public E element();
+
[email protected] public E peek();
+}
diff --git a/java/util/Queue.java b/java/util/Queue.java
new file mode 100644
index 0000000..cbdc205
--- /dev/null
+++ b/java/util/Queue.java
@@ -0,0 +1,209 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A collection designed for holding elements prior to processing.
+ * Besides basic {@link java.util.Collection Collection} operations,
+ * queues provide additional insertion, extraction, and inspection
+ * operations.  Each of these methods exists in two forms: one throws
+ * an exception if the operation fails, the other returns a special
+ * value (either {@code null} or {@code false}, depending on the
+ * operation).  The latter form of the insert operation is designed
+ * specifically for use with capacity-restricted {@code Queue}
+ * implementations; in most implementations, insert operations cannot
+ * fail.
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of Queue methods</caption>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Returns special value</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link Queue#add add(e)}</td>
+ *    <td>{@link Queue#offer offer(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link Queue#remove remove()}</td>
+ *    <td>{@link Queue#poll poll()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link Queue#element element()}</td>
+ *    <td>{@link Queue#peek peek()}</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Queues typically, but do not necessarily, order elements in a
+ * FIFO (first-in-first-out) manner.  Among the exceptions are
+ * priority queues, which order elements according to a supplied
+ * comparator, or the elements' natural ordering, and LIFO queues (or
+ * stacks) which order the elements LIFO (last-in-first-out).
+ * Whatever the ordering used, the <em>head</em> of the queue is that
+ * element which would be removed by a call to {@link #remove() } or
+ * {@link #poll()}.  In a FIFO queue, all new elements are inserted at
+ * the <em>tail</em> of the queue. Other kinds of queues may use
+ * different placement rules.  Every {@code Queue} implementation
+ * must specify its ordering properties.
+ *
+ * <p>The {@link #offer offer} method inserts an element if possible,
+ * otherwise returning {@code false}.  This differs from the {@link
+ * java.util.Collection#add Collection.add} method, which can fail to
+ * add an element only by throwing an unchecked exception.  The
+ * {@code offer} method is designed for use when failure is a normal,
+ * rather than exceptional occurrence, for example, in fixed-capacity
+ * (or &quot;bounded&quot;) queues.
+ *
+ * <p>The {@link #remove()} and {@link #poll()} methods remove and
+ * return the head of the queue.
+ * Exactly which element is removed from the queue is a
+ * function of the queue's ordering policy, which differs from
+ * implementation to implementation. The {@code remove()} and
+ * {@code poll()} methods differ only in their behavior when the
+ * queue is empty: the {@code remove()} method throws an exception,
+ * while the {@code poll()} method returns {@code null}.
+ *
+ * <p>The {@link #element()} and {@link #peek()} methods return, but do
+ * not remove, the head of the queue.
+ *
+ * <p>The {@code Queue} interface does not define the <i>blocking queue
+ * methods</i>, which are common in concurrent programming.  These methods,
+ * which wait for elements to appear or for space to become available, are
+ * defined in the {@link java.util.concurrent.BlockingQueue} interface, which
+ * extends this interface.
+ *
+ * <p>{@code Queue} implementations generally do not allow insertion
+ * of {@code null} elements, although some implementations, such as
+ * {@link LinkedList}, do not prohibit insertion of {@code null}.
+ * Even in the implementations that permit it, {@code null} should
+ * not be inserted into a {@code Queue}, as {@code null} is also
+ * used as a special return value by the {@code poll} method to
+ * indicate that the queue contains no elements.
+ *
+ * <p>{@code Queue} implementations generally do not define
+ * element-based versions of methods {@code equals} and
+ * {@code hashCode} but instead inherit the identity based versions
+ * from class {@code Object}, because element-based equality is not
+ * always well-defined for queues with the same elements but different
+ * ordering properties.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public interface Queue<E> extends Collection<E> {
+    /**
+     * Inserts the specified element into this queue if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an {@code IllegalStateException}
+     * if no space is currently available.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null and
+     *         this queue does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this queue
+     */
+    boolean add(E e);
+
+    /**
+     * Inserts the specified element into this queue if it is possible to do
+     * so immediately without violating capacity restrictions.
+     * When using a capacity-restricted queue, this method is generally
+     * preferable to {@link #add}, which can fail to insert an element only
+     * by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this queue, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null and
+     *         this queue does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this queue
+     */
+    boolean offer(E e);
+
+    /**
+     * Retrieves and removes the head of this queue.  This method differs
+     * from {@link #poll poll} only in that it throws an exception if this
+     * queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    E remove();
+
+    /**
+     * Retrieves and removes the head of this queue,
+     * or returns {@code null} if this queue is empty.
+     *
+     * @return the head of this queue, or {@code null} if this queue is empty
+     */
+    E poll();
+
+    /**
+     * Retrieves, but does not remove, the head of this queue.  This method
+     * differs from {@link #peek peek} only in that it throws an exception
+     * if this queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    E element();
+
+    /**
+     * Retrieves, but does not remove, the head of this queue,
+     * or returns {@code null} if this queue is empty.
+     *
+     * @return the head of this queue, or {@code null} if this queue is empty
+     */
+    E peek();
+}
diff --git a/java/util/Random.java b/java/util/Random.java
new file mode 100644
index 0000000..1061b59
--- /dev/null
+++ b/java/util/Random.java
@@ -0,0 +1,1227 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+import java.io.*;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.StreamSupport;
+
+import sun.misc.Unsafe;
+
+/**
+ * An instance of this class is used to generate a stream of
+ * pseudorandom numbers. The class uses a 48-bit seed, which is
+ * modified using a linear congruential formula. (See Donald Knuth,
+ * <i>The Art of Computer Programming, Volume 2</i>, Section 3.2.1.)
+ * <p>
+ * If two instances of {@code Random} are created with the same
+ * seed, and the same sequence of method calls is made for each, they
+ * will generate and return identical sequences of numbers. In order to
+ * guarantee this property, particular algorithms are specified for the
+ * class {@code Random}. Java implementations must use all the algorithms
+ * shown here for the class {@code Random}, for the sake of absolute
+ * portability of Java code. However, subclasses of class {@code Random}
+ * are permitted to use other algorithms, so long as they adhere to the
+ * general contracts for all the methods.
+ * <p>
+ * The algorithms implemented by class {@code Random} use a
+ * {@code protected} utility method that on each invocation can supply
+ * up to 32 pseudorandomly generated bits.
+ * <p>
+ * Many applications will find the method {@link Math#random} simpler to use.
+ *
+ * <p>Instances of {@code java.util.Random} are threadsafe.
+ * However, the concurrent use of the same {@code java.util.Random}
+ * instance across threads may encounter contention and consequent
+ * poor performance. Consider instead using
+ * {@link java.util.concurrent.ThreadLocalRandom} in multithreaded
+ * designs.
+ *
+ * <p>Instances of {@code java.util.Random} are not cryptographically
+ * secure.  Consider instead using {@link java.security.SecureRandom} to
+ * get a cryptographically secure pseudo-random number generator for use
+ * by security-sensitive applications.
+ *
+ * @author  Frank Yellin
+ * @since   1.0
+ */
+public
+class Random implements java.io.Serializable {
+    /** use serialVersionUID from JDK 1.1 for interoperability */
+    static final long serialVersionUID = 3905348978240129619L;
+
+    /**
+     * The internal state associated with this pseudorandom number generator.
+     * (The specs for the methods in this class describe the ongoing
+     * computation of this value.)
+     */
+    private final AtomicLong seed;
+
+    private static final long multiplier = 0x5DEECE66DL;
+    private static final long addend = 0xBL;
+    private static final long mask = (1L << 48) - 1;
+
+    private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
+
+    // IllegalArgumentException messages
+    static final String BadBound = "bound must be positive";
+    static final String BadRange = "bound must be greater than origin";
+    static final String BadSize  = "size must be non-negative";
+
+    /**
+     * Creates a new random number generator. This constructor sets
+     * the seed of the random number generator to a value very likely
+     * to be distinct from any other invocation of this constructor.
+     */
+    public Random() {
+        this(seedUniquifier() ^ System.nanoTime());
+    }
+
+    private static long seedUniquifier() {
+        // L'Ecuyer, "Tables of Linear Congruential Generators of
+        // Different Sizes and Good Lattice Structure", 1999
+        for (;;) {
+            long current = seedUniquifier.get();
+            long next = current * 181783497276652981L;
+            if (seedUniquifier.compareAndSet(current, next))
+                return next;
+        }
+    }
+
+    private static final AtomicLong seedUniquifier
+        = new AtomicLong(8682522807148012L);
+
+    /**
+     * Creates a new random number generator using a single {@code long} seed.
+     * The seed is the initial value of the internal state of the pseudorandom
+     * number generator which is maintained by method {@link #next}.
+     *
+     * <p>The invocation {@code new Random(seed)} is equivalent to:
+     *  <pre> {@code
+     * Random rnd = new Random();
+     * rnd.setSeed(seed);}</pre>
+     *
+     * @param seed the initial seed
+     * @see   #setSeed(long)
+     */
+    public Random(long seed) {
+        if (getClass() == Random.class)
+            this.seed = new AtomicLong(initialScramble(seed));
+        else {
+            // subclass might have overriden setSeed
+            this.seed = new AtomicLong();
+            setSeed(seed);
+        }
+    }
+
+    private static long initialScramble(long seed) {
+        return (seed ^ multiplier) & mask;
+    }
+
+    /**
+     * Sets the seed of this random number generator using a single
+     * {@code long} seed. The general contract of {@code setSeed} is
+     * that it alters the state of this random number generator object
+     * so as to be in exactly the same state as if it had just been
+     * created with the argument {@code seed} as a seed. The method
+     * {@code setSeed} is implemented by class {@code Random} by
+     * atomically updating the seed to
+     *  <pre>{@code (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1)}</pre>
+     * and clearing the {@code haveNextNextGaussian} flag used by {@link
+     * #nextGaussian}.
+     *
+     * <p>The implementation of {@code setSeed} by class {@code Random}
+     * happens to use only 48 bits of the given seed. In general, however,
+     * an overriding method may use all 64 bits of the {@code long}
+     * argument as a seed value.
+     *
+     * @param seed the initial seed
+     */
+    synchronized public void setSeed(long seed) {
+        this.seed.set(initialScramble(seed));
+        haveNextNextGaussian = false;
+    }
+
+    /**
+     * Generates the next pseudorandom number. Subclasses should
+     * override this, as this is used by all other methods.
+     *
+     * <p>The general contract of {@code next} is that it returns an
+     * {@code int} value and if the argument {@code bits} is between
+     * {@code 1} and {@code 32} (inclusive), then that many low-order
+     * bits of the returned value will be (approximately) independently
+     * chosen bit values, each of which is (approximately) equally
+     * likely to be {@code 0} or {@code 1}. The method {@code next} is
+     * implemented by class {@code Random} by atomically updating the seed to
+     *  <pre>{@code (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)}</pre>
+     * and returning
+     *  <pre>{@code (int)(seed >>> (48 - bits))}.</pre>
+     *
+     * This is a linear congruential pseudorandom number generator, as
+     * defined by D. H. Lehmer and described by Donald E. Knuth in
+     * <i>The Art of Computer Programming,</i> Volume 3:
+     * <i>Seminumerical Algorithms</i>, section 3.2.1.
+     *
+     * @param  bits random bits
+     * @return the next pseudorandom value from this random number
+     *         generator's sequence
+     * @since  1.1
+     */
+    protected int next(int bits) {
+        long oldseed, nextseed;
+        AtomicLong seed = this.seed;
+        do {
+            oldseed = seed.get();
+            nextseed = (oldseed * multiplier + addend) & mask;
+        } while (!seed.compareAndSet(oldseed, nextseed));
+        return (int)(nextseed >>> (48 - bits));
+    }
+
+    /**
+     * Generates random bytes and places them into a user-supplied
+     * byte array.  The number of random bytes produced is equal to
+     * the length of the byte array.
+     *
+     * <p>The method {@code nextBytes} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public void nextBytes(byte[] bytes) {
+     *   for (int i = 0; i < bytes.length; )
+     *     for (int rnd = nextInt(), n = Math.min(bytes.length - i, 4);
+     *          n-- > 0; rnd >>= 8)
+     *       bytes[i++] = (byte)rnd;
+     * }}</pre>
+     *
+     * @param  bytes the byte array to fill with random bytes
+     * @throws NullPointerException if the byte array is null
+     * @since  1.1
+     */
+    public void nextBytes(byte[] bytes) {
+        for (int i = 0, len = bytes.length; i < len; )
+            for (int rnd = nextInt(),
+                     n = Math.min(len - i, Integer.SIZE/Byte.SIZE);
+                 n-- > 0; rnd >>= Byte.SIZE)
+                bytes[i++] = (byte)rnd;
+    }
+
+    /**
+     * The form of nextLong used by LongStream Spliterators.  If
+     * origin is greater than bound, acts as unbounded form of
+     * nextLong, else as bounded form.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final long internalNextLong(long origin, long bound) {
+        long r = nextLong();
+        if (origin < bound) {
+            long n = bound - origin, m = n - 1;
+            if ((n & m) == 0L)  // power of two
+                r = (r & m) + origin;
+            else if (n > 0L) {  // reject over-represented candidates
+                for (long u = r >>> 1;            // ensure nonnegative
+                     u + m - (r = u % n) < 0L;    // rejection check
+                     u = nextLong() >>> 1) // retry
+                    ;
+                r += origin;
+            }
+            else {              // range not representable as long
+                while (r < origin || r >= bound)
+                    r = nextLong();
+            }
+        }
+        return r;
+    }
+
+    /**
+     * The form of nextInt used by IntStream Spliterators.
+     * For the unbounded case: uses nextInt().
+     * For the bounded case with representable range: uses nextInt(int bound)
+     * For the bounded case with unrepresentable range: uses nextInt()
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final int internalNextInt(int origin, int bound) {
+        if (origin < bound) {
+            int n = bound - origin;
+            if (n > 0) {
+                return nextInt(n) + origin;
+            }
+            else {  // range not representable as int
+                int r;
+                do {
+                    r = nextInt();
+                } while (r < origin || r >= bound);
+                return r;
+            }
+        }
+        else {
+            return nextInt();
+        }
+    }
+
+    /**
+     * The form of nextDouble used by DoubleStream Spliterators.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final double internalNextDouble(double origin, double bound) {
+        double r = nextDouble();
+        if (origin < bound) {
+            r = r * (bound - origin) + origin;
+            if (r >= bound) // correct for rounding
+                r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+        }
+        return r;
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed {@code int}
+     * value from this random number generator's sequence. The general
+     * contract of {@code nextInt} is that one {@code int} value is
+     * pseudorandomly generated and returned. All 2<sup>32</sup> possible
+     * {@code int} values are produced with (approximately) equal probability.
+     *
+     * <p>The method {@code nextInt} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public int nextInt() {
+     *   return next(32);
+     * }}</pre>
+     *
+     * @return the next pseudorandom, uniformly distributed {@code int}
+     *         value from this random number generator's sequence
+     */
+    public int nextInt() {
+        return next(32);
+    }
+
+    /**
+     * Returns a pseudorandom, uniformly distributed {@code int} value
+     * between 0 (inclusive) and the specified value (exclusive), drawn from
+     * this random number generator's sequence.  The general contract of
+     * {@code nextInt} is that one {@code int} value in the specified range
+     * is pseudorandomly generated and returned.  All {@code bound} possible
+     * {@code int} values are produced with (approximately) equal
+     * probability.  The method {@code nextInt(int bound)} is implemented by
+     * class {@code Random} as if by:
+     *  <pre> {@code
+     * public int nextInt(int bound) {
+     *   if (bound <= 0)
+     *     throw new IllegalArgumentException("bound must be positive");
+     *
+     *   if ((bound & -bound) == bound)  // i.e., bound is a power of 2
+     *     return (int)((bound * (long)next(31)) >> 31);
+     *
+     *   int bits, val;
+     *   do {
+     *       bits = next(31);
+     *       val = bits % bound;
+     *   } while (bits - val + (bound-1) < 0);
+     *   return val;
+     * }}</pre>
+     *
+     * <p>The hedge "approximately" is used in the foregoing description only
+     * because the next method is only approximately an unbiased source of
+     * independently chosen bits.  If it were a perfect source of randomly
+     * chosen bits, then the algorithm shown would choose {@code int}
+     * values from the stated range with perfect uniformity.
+     * <p>
+     * The algorithm is slightly tricky.  It rejects values that would result
+     * in an uneven distribution (due to the fact that 2^31 is not divisible
+     * by n). The probability of a value being rejected depends on n.  The
+     * worst case is n=2^30+1, for which the probability of a reject is 1/2,
+     * and the expected number of iterations before the loop terminates is 2.
+     * <p>
+     * The algorithm treats the case where n is a power of two specially: it
+     * returns the correct number of high-order bits from the underlying
+     * pseudo-random number generator.  In the absence of special treatment,
+     * the correct number of <i>low-order</i> bits would be returned.  Linear
+     * congruential pseudo-random number generators such as the one
+     * implemented by this class are known to have short periods in the
+     * sequence of values of their low-order bits.  Thus, this special case
+     * greatly increases the length of the sequence of values returned by
+     * successive calls to this method if n is a small power of two.
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return the next pseudorandom, uniformly distributed {@code int}
+     *         value between zero (inclusive) and {@code bound} (exclusive)
+     *         from this random number generator's sequence
+     * @throws IllegalArgumentException if bound is not positive
+     * @since 1.2
+     */
+    public int nextInt(int bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BadBound);
+
+        int r = next(31);
+        int m = bound - 1;
+        if ((bound & m) == 0)  // i.e., bound is a power of 2
+            r = (int)((bound * (long)r) >> 31);
+        else {
+            for (int u = r;
+                 u - (r = u % bound) + m < 0;
+                 u = next(31))
+                ;
+        }
+        return r;
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed {@code long}
+     * value from this random number generator's sequence. The general
+     * contract of {@code nextLong} is that one {@code long} value is
+     * pseudorandomly generated and returned.
+     *
+     * <p>The method {@code nextLong} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public long nextLong() {
+     *   return ((long)next(32) << 32) + next(32);
+     * }}</pre>
+     *
+     * Because class {@code Random} uses a seed with only 48 bits,
+     * this algorithm will not return all possible {@code long} values.
+     *
+     * @return the next pseudorandom, uniformly distributed {@code long}
+     *         value from this random number generator's sequence
+     */
+    public long nextLong() {
+        // it's okay that the bottom word remains signed.
+        return ((long)(next(32)) << 32) + next(32);
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed
+     * {@code boolean} value from this random number generator's
+     * sequence. The general contract of {@code nextBoolean} is that one
+     * {@code boolean} value is pseudorandomly generated and returned.  The
+     * values {@code true} and {@code false} are produced with
+     * (approximately) equal probability.
+     *
+     * <p>The method {@code nextBoolean} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public boolean nextBoolean() {
+     *   return next(1) != 0;
+     * }}</pre>
+     *
+     * @return the next pseudorandom, uniformly distributed
+     *         {@code boolean} value from this random number generator's
+     *         sequence
+     * @since 1.2
+     */
+    public boolean nextBoolean() {
+        return next(1) != 0;
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed {@code float}
+     * value between {@code 0.0} and {@code 1.0} from this random
+     * number generator's sequence.
+     *
+     * <p>The general contract of {@code nextFloat} is that one
+     * {@code float} value, chosen (approximately) uniformly from the
+     * range {@code 0.0f} (inclusive) to {@code 1.0f} (exclusive), is
+     * pseudorandomly generated and returned. All 2<sup>24</sup> possible
+     * {@code float} values of the form <i>m&nbsp;x&nbsp;</i>2<sup>-24</sup>,
+     * where <i>m</i> is a positive integer less than 2<sup>24</sup>, are
+     * produced with (approximately) equal probability.
+     *
+     * <p>The method {@code nextFloat} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public float nextFloat() {
+     *   return next(24) / ((float)(1 << 24));
+     * }}</pre>
+     *
+     * <p>The hedge "approximately" is used in the foregoing description only
+     * because the next method is only approximately an unbiased source of
+     * independently chosen bits. If it were a perfect source of randomly
+     * chosen bits, then the algorithm shown would choose {@code float}
+     * values from the stated range with perfect uniformity.<p>
+     * [In early versions of Java, the result was incorrectly calculated as:
+     *  <pre> {@code
+     *   return next(30) / ((float)(1 << 30));}</pre>
+     * This might seem to be equivalent, if not better, but in fact it
+     * introduced a slight nonuniformity because of the bias in the rounding
+     * of floating-point numbers: it was slightly more likely that the
+     * low-order bit of the significand would be 0 than that it would be 1.]
+     *
+     * @return the next pseudorandom, uniformly distributed {@code float}
+     *         value between {@code 0.0} and {@code 1.0} from this
+     *         random number generator's sequence
+     */
+    public float nextFloat() {
+        return next(24) / ((float)(1 << 24));
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed
+     * {@code double} value between {@code 0.0} and
+     * {@code 1.0} from this random number generator's sequence.
+     *
+     * <p>The general contract of {@code nextDouble} is that one
+     * {@code double} value, chosen (approximately) uniformly from the
+     * range {@code 0.0d} (inclusive) to {@code 1.0d} (exclusive), is
+     * pseudorandomly generated and returned.
+     *
+     * <p>The method {@code nextDouble} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public double nextDouble() {
+     *   return (((long)next(26) << 27) + next(27))
+     *     / (double)(1L << 53);
+     * }}</pre>
+     *
+     * <p>The hedge "approximately" is used in the foregoing description only
+     * because the {@code next} method is only approximately an unbiased
+     * source of independently chosen bits. If it were a perfect source of
+     * randomly chosen bits, then the algorithm shown would choose
+     * {@code double} values from the stated range with perfect uniformity.
+     * <p>[In early versions of Java, the result was incorrectly calculated as:
+     *  <pre> {@code
+     *   return (((long)next(27) << 27) + next(27))
+     *     / (double)(1L << 54);}</pre>
+     * This might seem to be equivalent, if not better, but in fact it
+     * introduced a large nonuniformity because of the bias in the rounding
+     * of floating-point numbers: it was three times as likely that the
+     * low-order bit of the significand would be 0 than that it would be 1!
+     * This nonuniformity probably doesn't matter much in practice, but we
+     * strive for perfection.]
+     *
+     * @return the next pseudorandom, uniformly distributed {@code double}
+     *         value between {@code 0.0} and {@code 1.0} from this
+     *         random number generator's sequence
+     * @see Math#random
+     */
+    public double nextDouble() {
+        return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
+    }
+
+    private double nextNextGaussian;
+    private boolean haveNextNextGaussian = false;
+
+    /**
+     * Returns the next pseudorandom, Gaussian ("normally") distributed
+     * {@code double} value with mean {@code 0.0} and standard
+     * deviation {@code 1.0} from this random number generator's sequence.
+     * <p>
+     * The general contract of {@code nextGaussian} is that one
+     * {@code double} value, chosen from (approximately) the usual
+     * normal distribution with mean {@code 0.0} and standard deviation
+     * {@code 1.0}, is pseudorandomly generated and returned.
+     *
+     * <p>The method {@code nextGaussian} is implemented by class
+     * {@code Random} as if by a threadsafe version of the following:
+     *  <pre> {@code
+     * private double nextNextGaussian;
+     * private boolean haveNextNextGaussian = false;
+     *
+     * public double nextGaussian() {
+     *   if (haveNextNextGaussian) {
+     *     haveNextNextGaussian = false;
+     *     return nextNextGaussian;
+     *   } else {
+     *     double v1, v2, s;
+     *     do {
+     *       v1 = 2 * nextDouble() - 1;   // between -1.0 and 1.0
+     *       v2 = 2 * nextDouble() - 1;   // between -1.0 and 1.0
+     *       s = v1 * v1 + v2 * v2;
+     *     } while (s >= 1 || s == 0);
+     *     double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
+     *     nextNextGaussian = v2 * multiplier;
+     *     haveNextNextGaussian = true;
+     *     return v1 * multiplier;
+     *   }
+     * }}</pre>
+     * This uses the <i>polar method</i> of G. E. P. Box, M. E. Muller, and
+     * G. Marsaglia, as described by Donald E. Knuth in <i>The Art of
+     * Computer Programming</i>, Volume 3: <i>Seminumerical Algorithms</i>,
+     * section 3.4.1, subsection C, algorithm P. Note that it generates two
+     * independent values at the cost of only one call to {@code StrictMath.log}
+     * and one call to {@code StrictMath.sqrt}.
+     *
+     * @return the next pseudorandom, Gaussian ("normally") distributed
+     *         {@code double} value with mean {@code 0.0} and
+     *         standard deviation {@code 1.0} from this random number
+     *         generator's sequence
+     */
+    synchronized public double nextGaussian() {
+        // See Knuth, ACP, Section 3.4.1 Algorithm C.
+        if (haveNextNextGaussian) {
+            haveNextNextGaussian = false;
+            return nextNextGaussian;
+        } else {
+            double v1, v2, s;
+            do {
+                v1 = 2 * nextDouble() - 1; // between -1 and 1
+                v2 = 2 * nextDouble() - 1; // between -1 and 1
+                s = v1 * v1 + v2 * v2;
+            } while (s >= 1 || s == 0);
+            double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
+            nextNextGaussian = v2 * multiplier;
+            haveNextNextGaussian = true;
+            return v1 * multiplier;
+        }
+    }
+
+    // stream methods, coded in a way intended to better isolate for
+    // maintenance purposes the small differences across forms.
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code int} values.
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the method {@link #nextInt()}.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code int} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public IntStream ints(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        return StreamSupport.intStream
+                (new RandomIntsSpliterator
+                         (this, 0L, streamSize, Integer.MAX_VALUE, 0),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code int}
+     * values.
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the method {@link #nextInt()}.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code int} values
+     * @since 1.8
+     */
+    public IntStream ints() {
+        return StreamSupport.intStream
+                (new RandomIntsSpliterator
+                         (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
+                 false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values, each conforming to the given
+     * origin (inclusive) and bound (exclusive).
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the following method with the origin and bound:
+     * <pre> {@code
+     * int nextInt(int origin, int bound) {
+     *   int n = bound - origin;
+     *   if (n > 0) {
+     *     return nextInt(n) + origin;
+     *   }
+     *   else {  // range not representable as int
+     *     int r;
+     *     do {
+     *       r = nextInt();
+     *     } while (r < origin || r >= bound);
+     *     return r;
+     *   }
+     * }}</pre>
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public IntStream ints(long streamSize, int randomNumberOrigin,
+                          int randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.intStream
+                (new RandomIntsSpliterator
+                         (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * int} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the following method with the origin and bound:
+     * <pre> {@code
+     * int nextInt(int origin, int bound) {
+     *   int n = bound - origin;
+     *   if (n > 0) {
+     *     return nextInt(n) + origin;
+     *   }
+     *   else {  // range not representable as int
+     *     int r;
+     *     do {
+     *       r = nextInt();
+     *     } while (r < origin || r >= bound);
+     *     return r;
+     *   }
+     * }}</pre>
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.intStream
+                (new RandomIntsSpliterator
+                         (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long} values.
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the method {@link #nextLong()}.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code long} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public LongStream longs(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        return StreamSupport.longStream
+                (new RandomLongsSpliterator
+                         (this, 0L, streamSize, Long.MAX_VALUE, 0L),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code long}
+     * values.
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the method {@link #nextLong()}.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code long} values
+     * @since 1.8
+     */
+    public LongStream longs() {
+        return StreamSupport.longStream
+                (new RandomLongsSpliterator
+                         (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
+                 false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long}, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * long nextLong(long origin, long bound) {
+     *   long r = nextLong();
+     *   long n = bound - origin, m = n - 1;
+     *   if ((n & m) == 0L)  // power of two
+     *     r = (r & m) + origin;
+     *   else if (n > 0L) {  // reject over-represented candidates
+     *     for (long u = r >>> 1;            // ensure nonnegative
+     *          u + m - (r = u % n) < 0L;    // rejection check
+     *          u = nextLong() >>> 1) // retry
+     *         ;
+     *     r += origin;
+     *   }
+     *   else {              // range not representable as long
+     *     while (r < origin || r >= bound)
+     *       r = nextLong();
+     *   }
+     *   return r;
+     * }}</pre>
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public LongStream longs(long streamSize, long randomNumberOrigin,
+                            long randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.longStream
+                (new RandomLongsSpliterator
+                         (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * long nextLong(long origin, long bound) {
+     *   long r = nextLong();
+     *   long n = bound - origin, m = n - 1;
+     *   if ((n & m) == 0L)  // power of two
+     *     r = (r & m) + origin;
+     *   else if (n > 0L) {  // reject over-represented candidates
+     *     for (long u = r >>> 1;            // ensure nonnegative
+     *          u + m - (r = u % n) < 0L;    // rejection check
+     *          u = nextLong() >>> 1) // retry
+     *         ;
+     *     r += origin;
+     *   }
+     *   else {              // range not representable as long
+     *     while (r < origin || r >= bound)
+     *       r = nextLong();
+     *   }
+     *   return r;
+     * }}</pre>
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.longStream
+                (new RandomLongsSpliterator
+                         (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each between zero
+     * (inclusive) and one (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the method {@link #nextDouble()}.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of {@code double} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public DoubleStream doubles(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        return StreamSupport.doubleStream
+                (new RandomDoublesSpliterator
+                         (this, 0L, streamSize, Double.MAX_VALUE, 0.0),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each between zero (inclusive) and one
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the method {@link #nextDouble()}.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code double} values
+     * @since 1.8
+     */
+    public DoubleStream doubles() {
+        return StreamSupport.doubleStream
+                (new RandomDoublesSpliterator
+                         (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
+                 false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * double nextDouble(double origin, double bound) {
+     *   double r = nextDouble();
+     *   r = r * (bound - origin) + origin;
+     *   if (r >= bound) // correct for rounding
+     *     r = Math.nextDown(bound);
+     *   return r;
+     * }}</pre>
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public DoubleStream doubles(long streamSize, double randomNumberOrigin,
+                                double randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.doubleStream
+                (new RandomDoublesSpliterator
+                         (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * double nextDouble(double origin, double bound) {
+     *   double r = nextDouble();
+     *   r = r * (bound - origin) + origin;
+     *   if (r >= bound) // correct for rounding
+     *     r = Math.nextDown(bound);
+     *   return r;
+     * }}</pre>
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.doubleStream
+                (new RandomDoublesSpliterator
+                         (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Spliterator for int streams.  We multiplex the four int
+     * versions into one class by treating a bound less than origin as
+     * unbounded, and also by treating "infinite" as equivalent to
+     * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
+     * approach. The long and double versions of this class are
+     * identical except for types.
+     */
+    static final class RandomIntsSpliterator implements Spliterator.OfInt {
+        final Random rng;
+        long index;
+        final long fence;
+        final int origin;
+        final int bound;
+        RandomIntsSpliterator(Random rng, long index, long fence,
+                              int origin, int bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomIntsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                   new RandomIntsSpliterator(rng, i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextInt(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                Random r = rng;
+                int o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextInt(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+    /**
+     * Spliterator for long streams.
+     */
+    static final class RandomLongsSpliterator implements Spliterator.OfLong {
+        final Random rng;
+        long index;
+        final long fence;
+        final long origin;
+        final long bound;
+        RandomLongsSpliterator(Random rng, long index, long fence,
+                               long origin, long bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomLongsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                   new RandomLongsSpliterator(rng, i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextLong(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                Random r = rng;
+                long o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextLong(o, b));
+                } while (++i < f);
+            }
+        }
+
+    }
+
+    /**
+     * Spliterator for double streams.
+     */
+    static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
+        final Random rng;
+        long index;
+        final long fence;
+        final double origin;
+        final double bound;
+        RandomDoublesSpliterator(Random rng, long index, long fence,
+                                 double origin, double bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomDoublesSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                   new RandomDoublesSpliterator(rng, i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextDouble(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                Random r = rng;
+                double o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextDouble(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+    /**
+     * Serializable fields for Random.
+     *
+     * @serialField    seed long
+     *              seed for random computations
+     * @serialField    nextNextGaussian double
+     *              next Gaussian to be returned
+     * @serialField      haveNextNextGaussian boolean
+     *              nextNextGaussian is valid
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("seed", Long.TYPE),
+        new ObjectStreamField("nextNextGaussian", Double.TYPE),
+        new ObjectStreamField("haveNextNextGaussian", Boolean.TYPE)
+    };
+
+    /**
+     * Reconstitute the {@code Random} instance from a stream (that is,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        ObjectInputStream.GetField fields = s.readFields();
+
+        // The seed is read in as {@code long} for
+        // historical reasons, but it is converted to an AtomicLong.
+        long seedVal = fields.get("seed", -1L);
+        if (seedVal < 0)
+          throw new java.io.StreamCorruptedException(
+                              "Random: invalid seed");
+        resetSeed(seedVal);
+        nextNextGaussian = fields.get("nextNextGaussian", 0.0);
+        haveNextNextGaussian = fields.get("haveNextNextGaussian", false);
+    }
+
+    /**
+     * Save the {@code Random} instance to a stream.
+     */
+    synchronized private void writeObject(ObjectOutputStream s)
+        throws IOException {
+
+        // set the values of the Serializable fields
+        ObjectOutputStream.PutField fields = s.putFields();
+
+        // The seed is serialized as a long for historical reasons.
+        fields.put("seed", seed.get());
+        fields.put("nextNextGaussian", nextNextGaussian);
+        fields.put("haveNextNextGaussian", haveNextNextGaussian);
+
+        // save them
+        s.writeFields();
+    }
+
+    // Support for resetting seed while deserializing
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static final long seedOffset;
+    static {
+        try {
+            seedOffset = unsafe.objectFieldOffset
+                (Random.class.getDeclaredField("seed"));
+        } catch (Exception ex) { throw new Error(ex); }
+    }
+    private void resetSeed(long seedVal) {
+        unsafe.putObjectVolatile(this, seedOffset, new AtomicLong(seedVal));
+    }
+}
diff --git a/java/util/RandomAccess.java b/java/util/RandomAccess.java
new file mode 100644
index 0000000..09ce29e
--- /dev/null
+++ b/java/util/RandomAccess.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Marker interface used by <tt>List</tt> implementations to indicate that
+ * they support fast (generally constant time) random access.  The primary
+ * purpose of this interface is to allow generic algorithms to alter their
+ * behavior to provide good performance when applied to either random or
+ * sequential access lists.
+ *
+ * <p>The best algorithms for manipulating random access lists (such as
+ * <tt>ArrayList</tt>) can produce quadratic behavior when applied to
+ * sequential access lists (such as <tt>LinkedList</tt>).  Generic list
+ * algorithms are encouraged to check whether the given list is an
+ * <tt>instanceof</tt> this interface before applying an algorithm that would
+ * provide poor performance if it were applied to a sequential access list,
+ * and to alter their behavior if necessary to guarantee acceptable
+ * performance.
+ *
+ * <p>It is recognized that the distinction between random and sequential
+ * access is often fuzzy.  For example, some <tt>List</tt> implementations
+ * provide asymptotically linear access times if they get huge, but constant
+ * access times in practice.  Such a <tt>List</tt> implementation
+ * should generally implement this interface.  As a rule of thumb, a
+ * <tt>List</tt> implementation should implement this interface if,
+ * for typical instances of the class, this loop:
+ * <pre>
+ *     for (int i=0, n=list.size(); i &lt; n; i++)
+ *         list.get(i);
+ * </pre>
+ * runs faster than this loop:
+ * <pre>
+ *     for (Iterator i=list.iterator(); i.hasNext(); )
+ *         i.next();
+ * </pre>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.4
+ */
+public interface RandomAccess {
+}
diff --git a/java/util/RegularEnumSet.java b/java/util/RegularEnumSet.java
new file mode 100644
index 0000000..31a63f1
--- /dev/null
+++ b/java/util/RegularEnumSet.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Private implementation class for EnumSet, for "regular sized" enum types
+ * (i.e., those with 64 or fewer enum constants).
+ *
+ * @author Josh Bloch
+ * @since 1.5
+ * @serial exclude
+ */
+class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
+    private static final long serialVersionUID = 3411599620347842686L;
+    /**
+     * Bit vector representation of this set.  The 2^k bit indicates the
+     * presence of universe[k] in this set.
+     */
+    private long elements = 0L;
+
+    RegularEnumSet(Class<E>elementType, Enum<?>[] universe) {
+        super(elementType, universe);
+    }
+
+    void addRange(E from, E to) {
+        elements = (-1L >>>  (from.ordinal() - to.ordinal() - 1)) << from.ordinal();
+    }
+
+    void addAll() {
+        if (universe.length != 0)
+            elements = -1L >>> -universe.length;
+    }
+
+    void complement() {
+        if (universe.length != 0) {
+            elements = ~elements;
+            elements &= -1L >>> -universe.length;  // Mask unused bits
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements contained in this set.  The
+     * iterator traverses the elements in their <i>natural order</i> (which is
+     * the order in which the enum constants are declared). The returned
+     * Iterator is a "snapshot" iterator that will never throw {@link
+     * ConcurrentModificationException}; the elements are traversed as they
+     * existed when this call was invoked.
+     *
+     * @return an iterator over the elements contained in this set
+     */
+    public Iterator<E> iterator() {
+        return new EnumSetIterator<>();
+    }
+
+    private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
+        /**
+         * A bit vector representing the elements in the set not yet
+         * returned by this iterator.
+         */
+        long unseen;
+
+        /**
+         * The bit representing the last element returned by this iterator
+         * but not removed, or zero if no such element exists.
+         */
+        long lastReturned = 0;
+
+        EnumSetIterator() {
+            unseen = elements;
+        }
+
+        public boolean hasNext() {
+            return unseen != 0;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (unseen == 0)
+                throw new NoSuchElementException();
+            lastReturned = unseen & -unseen;
+            unseen -= lastReturned;
+            return (E) universe[Long.numberOfTrailingZeros(lastReturned)];
+        }
+
+        public void remove() {
+            if (lastReturned == 0)
+                throw new IllegalStateException();
+            elements &= ~lastReturned;
+            lastReturned = 0;
+        }
+    }
+
+    /**
+     * Returns the number of elements in this set.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return Long.bitCount(elements);
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains no elements.
+     *
+     * @return <tt>true</tt> if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return elements == 0;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains the specified element.
+     *
+     * @param e element to be checked for containment in this collection
+     * @return <tt>true</tt> if this set contains the specified element
+     */
+    public boolean contains(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+
+        return (elements & (1L << ((Enum<?>)e).ordinal())) != 0;
+    }
+
+    // Modification Operations
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     *
+     * @param e element to be added to this set
+     * @return <tt>true</tt> if the set changed as a result of the call
+     *
+     * @throws NullPointerException if <tt>e</tt> is null
+     */
+    public boolean add(E e) {
+        typeCheck(e);
+
+        long oldElements = elements;
+        elements |= (1L << ((Enum<?>)e).ordinal());
+        return elements != oldElements;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     *
+     * @param e element to be removed from this set, if present
+     * @return <tt>true</tt> if the set contained the specified element
+     */
+    public boolean remove(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+
+        long oldElements = elements;
+        elements &= ~(1L << ((Enum<?>)e).ordinal());
+        return elements != oldElements;
+    }
+
+    // Bulk Operations
+
+    /**
+     * Returns <tt>true</tt> if this set contains all of the elements
+     * in the specified collection.
+     *
+     * @param c collection to be checked for containment in this set
+     * @return <tt>true</tt> if this set contains all of the elements
+     *        in the specified collection
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean containsAll(Collection<?> c) {
+        if (!(c instanceof RegularEnumSet))
+            return super.containsAll(c);
+
+        RegularEnumSet<?> es = (RegularEnumSet<?>)c;
+        if (es.elementType != elementType)
+            return es.isEmpty();
+
+        return (es.elements & ~elements) == 0;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set.
+     *
+     * @param c collection whose elements are to be added to this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *     of its elements are null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (!(c instanceof RegularEnumSet))
+            return super.addAll(c);
+
+        RegularEnumSet<?> es = (RegularEnumSet<?>)c;
+        if (es.elementType != elementType) {
+            if (es.isEmpty())
+                return false;
+            else
+                throw new ClassCastException(
+                    es.elementType + " != " + elementType);
+        }
+
+        long oldElements = elements;
+        elements |= es.elements;
+        return elements != oldElements;
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in
+     * the specified collection.
+     *
+     * @param c elements to be removed from this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean removeAll(Collection<?> c) {
+        if (!(c instanceof RegularEnumSet))
+            return super.removeAll(c);
+
+        RegularEnumSet<?> es = (RegularEnumSet<?>)c;
+        if (es.elementType != elementType)
+            return false;
+
+        long oldElements = elements;
+        elements &= ~es.elements;
+        return elements != oldElements;
+    }
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection.
+     *
+     * @param c elements to be retained in this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean retainAll(Collection<?> c) {
+        if (!(c instanceof RegularEnumSet))
+            return super.retainAll(c);
+
+        RegularEnumSet<?> es = (RegularEnumSet<?>)c;
+        if (es.elementType != elementType) {
+            boolean changed = (elements != 0);
+            elements = 0;
+            return changed;
+        }
+
+        long oldElements = elements;
+        elements &= es.elements;
+        return elements != oldElements;
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     */
+    public void clear() {
+        elements = 0;
+    }
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * <tt>true</tt> if the given object is also a set, the two sets have
+     * the same size, and every member of the given set is contained in
+     * this set.
+     *
+     * @param o object to be compared for equality with this set
+     * @return <tt>true</tt> if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        if (!(o instanceof RegularEnumSet))
+            return super.equals(o);
+
+        RegularEnumSet<?> es = (RegularEnumSet<?>)o;
+        if (es.elementType != elementType)
+            return elements == 0 && es.elements == 0;
+        return es.elements == elements;
+    }
+}
diff --git a/java/util/ResourceBundle.java b/java/util/ResourceBundle.java
new file mode 100644
index 0000000..dd07452
--- /dev/null
+++ b/java/util/ResourceBundle.java
@@ -0,0 +1,3000 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.jar.JarEntry;
+
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+import sun.util.locale.BaseLocale;
+import sun.util.locale.LocaleObjectCache;
+
+
+// Android-removed: Support for ResourceBundleControlProvider.
+// Removed references to ResourceBundleControlProvider from the documentation.
+// The service provider interface ResourceBundleControlProvider is not
+// available on Android.
+/**
+ *
+ * Resource bundles contain locale-specific objects.  When your program needs a
+ * locale-specific resource, a <code>String</code> for example, your program can
+ * load it from the resource bundle that is appropriate for the current user's
+ * locale. In this way, you can write program code that is largely independent
+ * of the user's locale isolating most, if not all, of the locale-specific
+ * information in resource bundles.
+ *
+ * <p>
+ * This allows you to write programs that can:
+ * <UL>
+ * <LI> be easily localized, or translated, into different languages
+ * <LI> handle multiple locales at once
+ * <LI> be easily modified later to support even more locales
+ * </UL>
+ *
+ * <P>
+ * Resource bundles belong to families whose members share a common base
+ * name, but whose names also have additional components that identify
+ * their locales. For example, the base name of a family of resource
+ * bundles might be "MyResources". The family should have a default
+ * resource bundle which simply has the same name as its family -
+ * "MyResources" - and will be used as the bundle of last resort if a
+ * specific locale is not supported. The family can then provide as
+ * many locale-specific members as needed, for example a German one
+ * named "MyResources_de".
+ *
+ * <P>
+ * Each resource bundle in a family contains the same items, but the items have
+ * been translated for the locale represented by that resource bundle.
+ * For example, both "MyResources" and "MyResources_de" may have a
+ * <code>String</code> that's used on a button for canceling operations.
+ * In "MyResources" the <code>String</code> may contain "Cancel" and in
+ * "MyResources_de" it may contain "Abbrechen".
+ *
+ * <P>
+ * If there are different resources for different countries, you
+ * can make specializations: for example, "MyResources_de_CH" contains objects for
+ * the German language (de) in Switzerland (CH). If you want to only
+ * modify some of the resources
+ * in the specialization, you can do so.
+ *
+ * <P>
+ * When your program needs a locale-specific object, it loads
+ * the <code>ResourceBundle</code> class using the
+ * {@link #getBundle(java.lang.String, java.util.Locale) getBundle}
+ * method:
+ * <blockquote>
+ * <pre>
+ * ResourceBundle myResources =
+ *      ResourceBundle.getBundle("MyResources", currentLocale);
+ * </pre>
+ * </blockquote>
+ *
+ * <P>
+ * Resource bundles contain key/value pairs. The keys uniquely
+ * identify a locale-specific object in the bundle. Here's an
+ * example of a <code>ListResourceBundle</code> that contains
+ * two key/value pairs:
+ * <blockquote>
+ * <pre>
+ * public class MyResources extends ListResourceBundle {
+ *     protected Object[][] getContents() {
+ *         return new Object[][] {
+ *             // LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
+ *             {"OkKey", "OK"},
+ *             {"CancelKey", "Cancel"},
+ *             // END OF MATERIAL TO LOCALIZE
+ *        };
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
+ * Keys are always <code>String</code>s.
+ * In this example, the keys are "OkKey" and "CancelKey".
+ * In the above example, the values
+ * are also <code>String</code>s--"OK" and "Cancel"--but
+ * they don't have to be. The values can be any type of object.
+ *
+ * <P>
+ * You retrieve an object from resource bundle using the appropriate
+ * getter method. Because "OkKey" and "CancelKey"
+ * are both strings, you would use <code>getString</code> to retrieve them:
+ * <blockquote>
+ * <pre>
+ * button1 = new Button(myResources.getString("OkKey"));
+ * button2 = new Button(myResources.getString("CancelKey"));
+ * </pre>
+ * </blockquote>
+ * The getter methods all require the key as an argument and return
+ * the object if found. If the object is not found, the getter method
+ * throws a <code>MissingResourceException</code>.
+ *
+ * <P>
+ * Besides <code>getString</code>, <code>ResourceBundle</code> also provides
+ * a method for getting string arrays, <code>getStringArray</code>,
+ * as well as a generic <code>getObject</code> method for any other
+ * type of object. When using <code>getObject</code>, you'll
+ * have to cast the result to the appropriate type. For example:
+ * <blockquote>
+ * <pre>
+ * int[] myIntegers = (int[]) myResources.getObject("intList");
+ * </pre>
+ * </blockquote>
+ *
+ * <P>
+ * The Java Platform provides two subclasses of <code>ResourceBundle</code>,
+ * <code>ListResourceBundle</code> and <code>PropertyResourceBundle</code>,
+ * that provide a fairly simple way to create resources.
+ * As you saw briefly in a previous example, <code>ListResourceBundle</code>
+ * manages its resource as a list of key/value pairs.
+ * <code>PropertyResourceBundle</code> uses a properties file to manage
+ * its resources.
+ *
+ * <p>
+ * If <code>ListResourceBundle</code> or <code>PropertyResourceBundle</code>
+ * do not suit your needs, you can write your own <code>ResourceBundle</code>
+ * subclass.  Your subclasses must override two methods: <code>handleGetObject</code>
+ * and <code>getKeys()</code>.
+ *
+ * <p>
+ * The implementation of a {@code ResourceBundle} subclass must be thread-safe
+ * if it's simultaneously used by multiple threads. The default implementations
+ * of the non-abstract methods in this class, and the methods in the direct
+ * known concrete subclasses {@code ListResourceBundle} and
+ * {@code PropertyResourceBundle} are thread-safe.
+ *
+ * <h3>ResourceBundle.Control</h3>
+ *
+ * The {@link ResourceBundle.Control} class provides information necessary
+ * to perform the bundle loading process by the <code>getBundle</code>
+ * factory methods that take a <code>ResourceBundle.Control</code>
+ * instance. You can implement your own subclass in order to enable
+ * non-standard resource bundle formats, change the search strategy, or
+ * define caching parameters. Refer to the descriptions of the class and the
+ * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
+ * factory method for details.
+ *
+ * <h3>Cache Management</h3>
+ *
+ * Resource bundle instances created by the <code>getBundle</code> factory
+ * methods are cached by default, and the factory methods return the same
+ * resource bundle instance multiple times if it has been
+ * cached. <code>getBundle</code> clients may clear the cache, manage the
+ * lifetime of cached resource bundle instances using time-to-live values,
+ * or specify not to cache resource bundle instances. Refer to the
+ * descriptions of the {@linkplain #getBundle(String, Locale, ClassLoader,
+ * Control) <code>getBundle</code> factory method}, {@link
+ * #clearCache(ClassLoader) clearCache}, {@link
+ * Control#getTimeToLive(String, Locale)
+ * ResourceBundle.Control.getTimeToLive}, and {@link
+ * Control#needsReload(String, Locale, String, ClassLoader, ResourceBundle,
+ * long) ResourceBundle.Control.needsReload} for details.
+ *
+ * <h3>Example</h3>
+ *
+ * The following is a very simple example of a <code>ResourceBundle</code>
+ * subclass, <code>MyResources</code>, that manages two resources (for a larger number of
+ * resources you would probably use a <code>Map</code>).
+ * Notice that you don't need to supply a value if
+ * a "parent-level" <code>ResourceBundle</code> handles the same
+ * key with the same value (as for the okKey below).
+ * <blockquote>
+ * <pre>
+ * // default (English language, United States)
+ * public class MyResources extends ResourceBundle {
+ *     public Object handleGetObject(String key) {
+ *         if (key.equals("okKey")) return "Ok";
+ *         if (key.equals("cancelKey")) return "Cancel";
+ *         return null;
+ *     }
+ *
+ *     public Enumeration&lt;String&gt; getKeys() {
+ *         return Collections.enumeration(keySet());
+ *     }
+ *
+ *     // Overrides handleKeySet() so that the getKeys() implementation
+ *     // can rely on the keySet() value.
+ *     protected Set&lt;String&gt; handleKeySet() {
+ *         return new HashSet&lt;String&gt;(Arrays.asList("okKey", "cancelKey"));
+ *     }
+ * }
+ *
+ * // German language
+ * public class MyResources_de extends MyResources {
+ *     public Object handleGetObject(String key) {
+ *         // don't need okKey, since parent level handles it.
+ *         if (key.equals("cancelKey")) return "Abbrechen";
+ *         return null;
+ *     }
+ *
+ *     protected Set&lt;String&gt; handleKeySet() {
+ *         return new HashSet&lt;String&gt;(Arrays.asList("cancelKey"));
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
+ * You do not have to restrict yourself to using a single family of
+ * <code>ResourceBundle</code>s. For example, you could have a set of bundles for
+ * exception messages, <code>ExceptionResources</code>
+ * (<code>ExceptionResources_fr</code>, <code>ExceptionResources_de</code>, ...),
+ * and one for widgets, <code>WidgetResource</code> (<code>WidgetResources_fr</code>,
+ * <code>WidgetResources_de</code>, ...); breaking up the resources however you like.
+ *
+ * @see ListResourceBundle
+ * @see PropertyResourceBundle
+ * @see MissingResourceException
+ * @since JDK1.1
+ */
+public abstract class ResourceBundle {
+
+    /** initial size of the bundle cache */
+    private static final int INITIAL_CACHE_SIZE = 32;
+
+    /** constant indicating that no resource bundle exists */
+    private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() {
+            public Enumeration<String> getKeys() { return null; }
+            protected Object handleGetObject(String key) { return null; }
+            public String toString() { return "NONEXISTENT_BUNDLE"; }
+        };
+
+
+    /**
+     * The cache is a map from cache keys (with bundle base name, locale, and
+     * class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a
+     * BundleReference.
+     *
+     * The cache is a ConcurrentMap, allowing the cache to be searched
+     * concurrently by multiple threads.  This will also allow the cache keys
+     * to be reclaimed along with the ClassLoaders they reference.
+     *
+     * This variable would be better named "cache", but we keep the old
+     * name for compatibility with some workarounds for bug 4212439.
+     */
+    private static final ConcurrentMap<CacheKey, BundleReference> cacheList
+        = new ConcurrentHashMap<>(INITIAL_CACHE_SIZE);
+
+    /**
+     * Queue for reference objects referring to class loaders or bundles.
+     */
+    private static final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
+
+    /**
+     * Returns the base name of this bundle, if known, or {@code null} if unknown.
+     *
+     * If not null, then this is the value of the {@code baseName} parameter
+     * that was passed to the {@code ResourceBundle.getBundle(...)} method
+     * when the resource bundle was loaded.
+     *
+     * @return The base name of the resource bundle, as provided to and expected
+     * by the {@code ResourceBundle.getBundle(...)} methods.
+     *
+     * @see #getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader)
+     *
+     * @since 1.8
+     */
+    public String getBaseBundleName() {
+        return name;
+    }
+
+    /**
+     * The parent bundle of this bundle.
+     * The parent bundle is searched by {@link #getObject getObject}
+     * when this bundle does not contain a particular resource.
+     */
+    protected ResourceBundle parent = null;
+
+    /**
+     * The locale for this bundle.
+     */
+    private Locale locale = null;
+
+    /**
+     * The base bundle name for this bundle.
+     */
+    private String name;
+
+    /**
+     * The flag indicating this bundle has expired in the cache.
+     */
+    private volatile boolean expired;
+
+    /**
+     * The back link to the cache key. null if this bundle isn't in
+     * the cache (yet) or has expired.
+     */
+    private volatile CacheKey cacheKey;
+
+    /**
+     * A Set of the keys contained only in this ResourceBundle.
+     */
+    private volatile Set<String> keySet;
+
+    // Android-removed: Support for ResourceBundleControlProvider.
+    /*
+    private static final List<ResourceBundleControlProvider> providers;
+
+    static {
+        List<ResourceBundleControlProvider> list = null;
+        ServiceLoader<ResourceBundleControlProvider> serviceLoaders
+                = ServiceLoader.loadInstalled(ResourceBundleControlProvider.class);
+        for (ResourceBundleControlProvider provider : serviceLoaders) {
+            if (list == null) {
+                list = new ArrayList<>();
+            }
+            list.add(provider);
+        }
+        providers = list;
+    }
+    */
+
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public ResourceBundle() {
+    }
+
+    /**
+     * Gets a string for the given key from this resource bundle or one of its parents.
+     * Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>(String) {@link #getObject(java.lang.String) getObject}(key)</code>.
+     * </blockquote>
+     *
+     * @param key the key for the desired string
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @exception MissingResourceException if no object for the given key can be found
+     * @exception ClassCastException if the object found for the given key is not a string
+     * @return the string for the given key
+     */
+    public final String getString(String key) {
+        return (String) getObject(key);
+    }
+
+    /**
+     * Gets a string array for the given key from this resource bundle or one of its parents.
+     * Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>(String[]) {@link #getObject(java.lang.String) getObject}(key)</code>.
+     * </blockquote>
+     *
+     * @param key the key for the desired string array
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @exception MissingResourceException if no object for the given key can be found
+     * @exception ClassCastException if the object found for the given key is not a string array
+     * @return the string array for the given key
+     */
+    public final String[] getStringArray(String key) {
+        return (String[]) getObject(key);
+    }
+
+    /**
+     * Gets an object for the given key from this resource bundle or one of its parents.
+     * This method first tries to obtain the object from this resource bundle using
+     * {@link #handleGetObject(java.lang.String) handleGetObject}.
+     * If not successful, and the parent resource bundle is not null,
+     * it calls the parent's <code>getObject</code> method.
+     * If still not successful, it throws a MissingResourceException.
+     *
+     * @param key the key for the desired object
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @exception MissingResourceException if no object for the given key can be found
+     * @return the object for the given key
+     */
+    public final Object getObject(String key) {
+        Object obj = handleGetObject(key);
+        if (obj == null) {
+            if (parent != null) {
+                obj = parent.getObject(key);
+            }
+            if (obj == null) {
+                throw new MissingResourceException("Can't find resource for bundle "
+                                                   +this.getClass().getName()
+                                                   +", key "+key,
+                                                   this.getClass().getName(),
+                                                   key);
+            }
+        }
+        return obj;
+    }
+
+    /**
+     * Returns the locale of this resource bundle. This method can be used after a
+     * call to getBundle() to determine whether the resource bundle returned really
+     * corresponds to the requested locale or is a fallback.
+     *
+     * @return the locale of this resource bundle
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+    /*
+     * Automatic determination of the ClassLoader to be used to load
+     * resources on behalf of the client.
+     */
+    private static ClassLoader getLoader(Class<?> caller) {
+        ClassLoader cl = caller == null ? null : caller.getClassLoader();
+        if (cl == null) {
+            // When the caller's loader is the boot class loader, cl is null
+            // here. In that case, ClassLoader.getSystemClassLoader() may
+            // return the same class loader that the application is
+            // using. We therefore use a wrapper ClassLoader to create a
+            // separate scope for bundles loaded on behalf of the Java
+            // runtime so that these bundles cannot be returned from the
+            // cache to the application (5048280).
+            cl = RBClassLoader.INSTANCE;
+        }
+        return cl;
+    }
+
+    /**
+     * A wrapper of ClassLoader.getSystemClassLoader().
+     */
+    private static class RBClassLoader extends ClassLoader {
+        private static final RBClassLoader INSTANCE = AccessController.doPrivileged(
+                    new PrivilegedAction<RBClassLoader>() {
+                        public RBClassLoader run() {
+                            return new RBClassLoader();
+                        }
+                    });
+        private static final ClassLoader loader = ClassLoader.getSystemClassLoader();
+
+        private RBClassLoader() {
+        }
+        public Class<?> loadClass(String name) throws ClassNotFoundException {
+            if (loader != null) {
+                return loader.loadClass(name);
+            }
+            return Class.forName(name);
+        }
+        public URL getResource(String name) {
+            if (loader != null) {
+                return loader.getResource(name);
+            }
+            return ClassLoader.getSystemResource(name);
+        }
+        public InputStream getResourceAsStream(String name) {
+            if (loader != null) {
+                return loader.getResourceAsStream(name);
+            }
+            return ClassLoader.getSystemResourceAsStream(name);
+        }
+    }
+
+    /**
+     * Sets the parent bundle of this bundle.
+     * The parent bundle is searched by {@link #getObject getObject}
+     * when this bundle does not contain a particular resource.
+     *
+     * @param parent this bundle's parent bundle.
+     */
+    protected void setParent(ResourceBundle parent) {
+        assert parent != NONEXISTENT_BUNDLE;
+        this.parent = parent;
+    }
+
+    /**
+     * Key used for cached resource bundles.  The key checks the base
+     * name, the locale, and the class loader to determine if the
+     * resource is a match to the requested one. The loader may be
+     * null, but the base name and the locale must have a non-null
+     * value.
+     */
+    private static class CacheKey implements Cloneable {
+        // These three are the actual keys for lookup in Map.
+        private String name;
+        private Locale locale;
+        private LoaderReference loaderRef;
+
+        // bundle format which is necessary for calling
+        // Control.needsReload().
+        private String format;
+
+        // These time values are in CacheKey so that NONEXISTENT_BUNDLE
+        // doesn't need to be cloned for caching.
+
+        // The time when the bundle has been loaded
+        private volatile long loadTime;
+
+        // The time when the bundle expires in the cache, or either
+        // Control.TTL_DONT_CACHE or Control.TTL_NO_EXPIRATION_CONTROL.
+        private volatile long expirationTime;
+
+        // Placeholder for an error report by a Throwable
+        private Throwable cause;
+
+        // Hash code value cache to avoid recalculating the hash code
+        // of this instance.
+        private int hashCodeCache;
+
+        CacheKey(String baseName, Locale locale, ClassLoader loader) {
+            this.name = baseName;
+            this.locale = locale;
+            if (loader == null) {
+                this.loaderRef = null;
+            } else {
+                loaderRef = new LoaderReference(loader, referenceQueue, this);
+            }
+            calculateHashCode();
+        }
+
+        String getName() {
+            return name;
+        }
+
+        CacheKey setName(String baseName) {
+            if (!this.name.equals(baseName)) {
+                this.name = baseName;
+                calculateHashCode();
+            }
+            return this;
+        }
+
+        Locale getLocale() {
+            return locale;
+        }
+
+        CacheKey setLocale(Locale locale) {
+            if (!this.locale.equals(locale)) {
+                this.locale = locale;
+                calculateHashCode();
+            }
+            return this;
+        }
+
+        ClassLoader getLoader() {
+            return (loaderRef != null) ? loaderRef.get() : null;
+        }
+
+        public boolean equals(Object other) {
+            if (this == other) {
+                return true;
+            }
+            try {
+                final CacheKey otherEntry = (CacheKey)other;
+                //quick check to see if they are not equal
+                if (hashCodeCache != otherEntry.hashCodeCache) {
+                    return false;
+                }
+                //are the names the same?
+                if (!name.equals(otherEntry.name)) {
+                    return false;
+                }
+                // are the locales the same?
+                if (!locale.equals(otherEntry.locale)) {
+                    return false;
+                }
+                //are refs (both non-null) or (both null)?
+                if (loaderRef == null) {
+                    return otherEntry.loaderRef == null;
+                }
+                ClassLoader loader = loaderRef.get();
+                return (otherEntry.loaderRef != null)
+                        // with a null reference we can no longer find
+                        // out which class loader was referenced; so
+                        // treat it as unequal
+                        && (loader != null)
+                        && (loader == otherEntry.loaderRef.get());
+            } catch (    NullPointerException | ClassCastException e) {
+            }
+            return false;
+        }
+
+        public int hashCode() {
+            return hashCodeCache;
+        }
+
+        private void calculateHashCode() {
+            hashCodeCache = name.hashCode() << 3;
+            hashCodeCache ^= locale.hashCode();
+            ClassLoader loader = getLoader();
+            if (loader != null) {
+                hashCodeCache ^= loader.hashCode();
+            }
+        }
+
+        public Object clone() {
+            try {
+                CacheKey clone = (CacheKey) super.clone();
+                if (loaderRef != null) {
+                    clone.loaderRef = new LoaderReference(loaderRef.get(),
+                                                          referenceQueue, clone);
+                }
+                // Clear the reference to a Throwable
+                clone.cause = null;
+                return clone;
+            } catch (CloneNotSupportedException e) {
+                //this should never happen
+                throw new InternalError(e);
+            }
+        }
+
+        String getFormat() {
+            return format;
+        }
+
+        void setFormat(String format) {
+            this.format = format;
+        }
+
+        private void setCause(Throwable cause) {
+            if (this.cause == null) {
+                this.cause = cause;
+            } else {
+                // Override the cause if the previous one is
+                // ClassNotFoundException.
+                if (this.cause instanceof ClassNotFoundException) {
+                    this.cause = cause;
+                }
+            }
+        }
+
+        private Throwable getCause() {
+            return cause;
+        }
+
+        public String toString() {
+            String l = locale.toString();
+            if (l.length() == 0) {
+                if (locale.getVariant().length() != 0) {
+                    l = "__" + locale.getVariant();
+                } else {
+                    l = "\"\"";
+                }
+            }
+            return "CacheKey[" + name + ", lc=" + l + ", ldr=" + getLoader()
+                + "(format=" + format + ")]";
+        }
+    }
+
+    /**
+     * The common interface to get a CacheKey in LoaderReference and
+     * BundleReference.
+     */
+    private static interface CacheKeyReference {
+        public CacheKey getCacheKey();
+    }
+
+    /**
+     * References to class loaders are weak references, so that they can be
+     * garbage collected when nobody else is using them. The ResourceBundle
+     * class has no reason to keep class loaders alive.
+     */
+    private static class LoaderReference extends WeakReference<ClassLoader>
+                                         implements CacheKeyReference {
+        private CacheKey cacheKey;
+
+        LoaderReference(ClassLoader referent, ReferenceQueue<Object> q, CacheKey key) {
+            super(referent, q);
+            cacheKey = key;
+        }
+
+        public CacheKey getCacheKey() {
+            return cacheKey;
+        }
+    }
+
+    /**
+     * References to bundles are soft references so that they can be garbage
+     * collected when they have no hard references.
+     */
+    private static class BundleReference extends SoftReference<ResourceBundle>
+                                         implements CacheKeyReference {
+        private CacheKey cacheKey;
+
+        BundleReference(ResourceBundle referent, ReferenceQueue<Object> q, CacheKey key) {
+            super(referent, q);
+            cacheKey = key;
+        }
+
+        public CacheKey getCacheKey() {
+            return cacheKey;
+        }
+    }
+
+    /**
+     * Gets a resource bundle using the specified base name, the default locale,
+     * and the caller's class loader. Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())</code>,
+     * </blockquote>
+     * except that <code>getClassLoader()</code> is run with the security
+     * privileges of <code>ResourceBundle</code>.
+     * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
+     * for a complete description of the search and instantiation strategy.
+     *
+     * @param baseName the base name of the resource bundle, a fully qualified class name
+     * @exception java.lang.NullPointerException
+     *     if <code>baseName</code> is <code>null</code>
+     * @exception MissingResourceException
+     *     if no resource bundle for the specified base name can be found
+     * @return a resource bundle for the given base name and the default locale
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName)
+    {
+        return getBundleImpl(baseName, Locale.getDefault(),
+                             getLoader(Reflection.getCallerClass()),
+                             getDefaultControl(baseName));
+    }
+
+    /**
+     * Returns a resource bundle using the specified base name, the
+     * default locale and the specified control. Calling this method
+     * is equivalent to calling
+     * <pre>
+     * getBundle(baseName, Locale.getDefault(),
+     *           this.getClass().getClassLoader(), control),
+     * </pre>
+     * except that <code>getClassLoader()</code> is run with the security
+     * privileges of <code>ResourceBundle</code>.  See {@link
+     * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
+     * complete description of the resource bundle loading process with a
+     * <code>ResourceBundle.Control</code>.
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified class
+     *        name
+     * @param control
+     *        the control which gives information for the resource bundle
+     *        loading process
+     * @return a resource bundle for the given base name and the default
+     *        locale
+     * @exception NullPointerException
+     *        if <code>baseName</code> or <code>control</code> is
+     *        <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name can be found
+     * @exception IllegalArgumentException
+     *        if the given <code>control</code> doesn't perform properly
+     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *        Note that validation of <code>control</code> is performed as
+     *        needed.
+     * @since 1.6
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName,
+                                                 Control control) {
+        return getBundleImpl(baseName, Locale.getDefault(),
+                             getLoader(Reflection.getCallerClass()),
+                             control);
+    }
+
+    /**
+     * Gets a resource bundle using the specified base name and locale,
+     * and the caller's class loader. Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>getBundle(baseName, locale, this.getClass().getClassLoader())</code>,
+     * </blockquote>
+     * except that <code>getClassLoader()</code> is run with the security
+     * privileges of <code>ResourceBundle</code>.
+     * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
+     * for a complete description of the search and instantiation strategy.
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified class name
+     * @param locale
+     *        the locale for which a resource bundle is desired
+     * @exception NullPointerException
+     *        if <code>baseName</code> or <code>locale</code> is <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name can be found
+     * @return a resource bundle for the given base name and locale
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName,
+                                                 Locale locale)
+    {
+        return getBundleImpl(baseName, locale,
+                             getLoader(Reflection.getCallerClass()),
+                             getDefaultControl(baseName));
+    }
+
+    /**
+     * Returns a resource bundle using the specified base name, target
+     * locale and control, and the caller's class loader. Calling this
+     * method is equivalent to calling
+     * <pre>
+     * getBundle(baseName, targetLocale, this.getClass().getClassLoader(),
+     *           control),
+     * </pre>
+     * except that <code>getClassLoader()</code> is run with the security
+     * privileges of <code>ResourceBundle</code>.  See {@link
+     * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
+     * complete description of the resource bundle loading process with a
+     * <code>ResourceBundle.Control</code>.
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified
+     *        class name
+     * @param targetLocale
+     *        the locale for which a resource bundle is desired
+     * @param control
+     *        the control which gives information for the resource
+     *        bundle loading process
+     * @return a resource bundle for the given base name and a
+     *        <code>Locale</code> in <code>locales</code>
+     * @exception NullPointerException
+     *        if <code>baseName</code>, <code>locales</code> or
+     *        <code>control</code> is <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name in any
+     *        of the <code>locales</code> can be found.
+     * @exception IllegalArgumentException
+     *        if the given <code>control</code> doesn't perform properly
+     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *        Note that validation of <code>control</code> is performed as
+     *        needed.
+     * @since 1.6
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
+                                                 Control control) {
+        return getBundleImpl(baseName, targetLocale,
+                             getLoader(Reflection.getCallerClass()),
+                             control);
+    }
+
+    // Android-removed: Support for ResourceBundleControlProvider.
+    // Removed documentation referring to that SPI.
+    /**
+     * Gets a resource bundle using the specified base name, locale, and class
+     * loader.
+     *
+     * <p>This method behaves the same as calling
+     * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
+     * default instance of {@link Control}.
+     *
+     * <p><code>getBundle</code> uses the base name, the specified locale, and
+     * the default locale (obtained from {@link java.util.Locale#getDefault()
+     * Locale.getDefault}) to generate a sequence of <a
+     * name="candidates"><em>candidate bundle names</em></a>.  If the specified
+     * locale's language, script, country, and variant are all empty strings,
+     * then the base name is the only candidate bundle name.  Otherwise, a list
+     * of candidate locales is generated from the attribute values of the
+     * specified locale (language, script, country and variant) and appended to
+     * the base name.  Typically, this will look like the following:
+     *
+     * <pre>
+     *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
+     *     baseName + "_" + language + "_" + script + "_" + country
+     *     baseName + "_" + language + "_" + script
+     *     baseName + "_" + language + "_" + country + "_" + variant
+     *     baseName + "_" + language + "_" + country
+     *     baseName + "_" + language
+     * </pre>
+     *
+     * <p>Candidate bundle names where the final component is an empty string
+     * are omitted, along with the underscore.  For example, if country is an
+     * empty string, the second and the fifth candidate bundle names above
+     * would be omitted.  Also, if script is an empty string, the candidate names
+     * including script are omitted.  For example, a locale with language "de"
+     * and variant "JAVA" will produce candidate names with base name
+     * "MyResource" below.
+     *
+     * <pre>
+     *     MyResource_de__JAVA
+     *     MyResource_de
+     * </pre>
+     *
+     * In the case that the variant contains one or more underscores ('_'), a
+     * sequence of bundle names generated by truncating the last underscore and
+     * the part following it is inserted after a candidate bundle name with the
+     * original variant.  For example, for a locale with language "en", script
+     * "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name
+     * "MyResource", the list of candidate bundle names below is generated:
+     *
+     * <pre>
+     * MyResource_en_Latn_US_WINDOWS_VISTA
+     * MyResource_en_Latn_US_WINDOWS
+     * MyResource_en_Latn_US
+     * MyResource_en_Latn
+     * MyResource_en_US_WINDOWS_VISTA
+     * MyResource_en_US_WINDOWS
+     * MyResource_en_US
+     * MyResource_en
+     * </pre>
+     *
+     * <blockquote><b>Note:</b> For some <code>Locale</code>s, the list of
+     * candidate bundle names contains extra names, or the order of bundle names
+     * is slightly modified.  See the description of the default implementation
+     * of {@link Control#getCandidateLocales(String, Locale)
+     * getCandidateLocales} for details.</blockquote>
+     *
+     * <p><code>getBundle</code> then iterates over the candidate bundle names
+     * to find the first one for which it can <em>instantiate</em> an actual
+     * resource bundle. It uses the default controls' {@link Control#getFormats
+     * getFormats} method, which generates two bundle names for each generated
+     * name, the first a class name and the second a properties file name. For
+     * each candidate bundle name, it attempts to create a resource bundle:
+     *
+     * <ul><li>First, it attempts to load a class using the generated class name.
+     * If such a class can be found and loaded using the specified class
+     * loader, is assignment compatible with ResourceBundle, is accessible from
+     * ResourceBundle, and can be instantiated, <code>getBundle</code> creates a
+     * new instance of this class and uses it as the <em>result resource
+     * bundle</em>.
+     *
+     * <li>Otherwise, <code>getBundle</code> attempts to locate a property
+     * resource file using the generated properties file name.  It generates a
+     * path name from the candidate bundle name by replacing all "." characters
+     * with "/" and appending the string ".properties".  It attempts to find a
+     * "resource" with this name using {@link
+     * java.lang.ClassLoader#getResource(java.lang.String)
+     * ClassLoader.getResource}.  (Note that a "resource" in the sense of
+     * <code>getResource</code> has nothing to do with the contents of a
+     * resource bundle, it is just a container of data, such as a file.)  If it
+     * finds a "resource", it attempts to create a new {@link
+     * PropertyResourceBundle} instance from its contents.  If successful, this
+     * instance becomes the <em>result resource bundle</em>.  </ul>
+     *
+     * <p>This continues until a result resource bundle is instantiated or the
+     * list of candidate bundle names is exhausted.  If no matching resource
+     * bundle is found, the default control's {@link Control#getFallbackLocale
+     * getFallbackLocale} method is called, which returns the current default
+     * locale.  A new sequence of candidate locale names is generated using this
+     * locale and and searched again, as above.
+     *
+     * <p>If still no result bundle is found, the base name alone is looked up. If
+     * this still fails, a <code>MissingResourceException</code> is thrown.
+     *
+     * <p><a name="parent_chain"> Once a result resource bundle has been found,
+     * its <em>parent chain</em> is instantiated</a>.  If the result bundle already
+     * has a parent (perhaps because it was returned from a cache) the chain is
+     * complete.
+     *
+     * <p>Otherwise, <code>getBundle</code> examines the remainder of the
+     * candidate locale list that was used during the pass that generated the
+     * result resource bundle.  (As before, candidate bundle names where the
+     * final component is an empty string are omitted.)  When it comes to the
+     * end of the candidate list, it tries the plain bundle name.  With each of the
+     * candidate bundle names it attempts to instantiate a resource bundle (first
+     * looking for a class and then a properties file, as described above).
+     *
+     * <p>Whenever it succeeds, it calls the previously instantiated resource
+     * bundle's {@link #setParent(java.util.ResourceBundle) setParent} method
+     * with the new resource bundle.  This continues until the list of names
+     * is exhausted or the current bundle already has a non-null parent.
+     *
+     * <p>Once the parent chain is complete, the bundle is returned.
+     *
+     * <p><b>Note:</b> <code>getBundle</code> caches instantiated resource
+     * bundles and might return the same resource bundle instance multiple times.
+     *
+     * <p><b>Note:</b>The <code>baseName</code> argument should be a fully
+     * qualified class name. However, for compatibility with earlier versions,
+     * Sun's Java SE Runtime Environments do not verify this, and so it is
+     * possible to access <code>PropertyResourceBundle</code>s by specifying a
+     * path name (using "/") instead of a fully qualified class name (using
+     * ".").
+     *
+     * <p><a name="default_behavior_example">
+     * <strong>Example:</strong></a>
+     * <p>
+     * The following class and property files are provided:
+     * <pre>
+     *     MyResources.class
+     *     MyResources.properties
+     *     MyResources_fr.properties
+     *     MyResources_fr_CH.class
+     *     MyResources_fr_CH.properties
+     *     MyResources_en.properties
+     *     MyResources_es_ES.class
+     * </pre>
+     *
+     * The contents of all files are valid (that is, public non-abstract
+     * subclasses of <code>ResourceBundle</code> for the ".class" files,
+     * syntactically correct ".properties" files).  The default locale is
+     * <code>Locale("en", "GB")</code>.
+     *
+     * <p>Calling <code>getBundle</code> with the locale arguments below will
+     * instantiate resource bundles as follows:
+     *
+     * <table summary="getBundle() locale to resource bundle mapping">
+     * <tr><td>Locale("fr", "CH")</td><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr>
+     * <tr><td>Locale("fr", "FR")</td><td>MyResources_fr.properties, parent MyResources.class</td></tr>
+     * <tr><td>Locale("de", "DE")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
+     * <tr><td>Locale("en", "US")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
+     * <tr><td>Locale("es", "ES")</td><td>MyResources_es_ES.class, parent MyResources.class</td></tr>
+     * </table>
+     *
+     * <p>The file MyResources_fr_CH.properties is never used because it is
+     * hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties
+     * is also hidden by MyResources.class.
+     *
+     * @param baseName the base name of the resource bundle, a fully qualified class name
+     * @param locale the locale for which a resource bundle is desired
+     * @param loader the class loader from which to load the resource bundle
+     * @return a resource bundle for the given base name and locale
+     * @exception java.lang.NullPointerException
+     *        if <code>baseName</code>, <code>locale</code>, or <code>loader</code> is <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name can be found
+     * @since 1.2
+     */
+    public static ResourceBundle getBundle(String baseName, Locale locale,
+                                           ClassLoader loader)
+    {
+        if (loader == null) {
+            throw new NullPointerException();
+        }
+        return getBundleImpl(baseName, locale, loader, getDefaultControl(baseName));
+    }
+
+    /**
+     * Returns a resource bundle using the specified base name, target
+     * locale, class loader and control. Unlike the {@linkplain
+     * #getBundle(String, Locale, ClassLoader) <code>getBundle</code>
+     * factory methods with no <code>control</code> argument}, the given
+     * <code>control</code> specifies how to locate and instantiate resource
+     * bundles. Conceptually, the bundle loading process with the given
+     * <code>control</code> is performed in the following steps.
+     *
+     * <ol>
+     * <li>This factory method looks up the resource bundle in the cache for
+     * the specified <code>baseName</code>, <code>targetLocale</code> and
+     * <code>loader</code>.  If the requested resource bundle instance is
+     * found in the cache and the time-to-live periods of the instance and
+     * all of its parent instances have not expired, the instance is returned
+     * to the caller. Otherwise, this factory method proceeds with the
+     * loading process below.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#getFormats(String)
+     * control.getFormats} method is called to get resource bundle formats
+     * to produce bundle or resource names. The strings
+     * <code>"java.class"</code> and <code>"java.properties"</code>
+     * designate class-based and {@linkplain PropertyResourceBundle
+     * property}-based resource bundles, respectively. Other strings
+     * starting with <code>"java."</code> are reserved for future extensions
+     * and must not be used for application-defined formats. Other strings
+     * designate application-defined formats.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#getCandidateLocales(String,
+     * Locale) control.getCandidateLocales} method is called with the target
+     * locale to get a list of <em>candidate <code>Locale</code>s</em> for
+     * which resource bundles are searched.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#newBundle(String, Locale,
+     * String, ClassLoader, boolean) control.newBundle} method is called to
+     * instantiate a <code>ResourceBundle</code> for the base bundle name, a
+     * candidate locale, and a format. (Refer to the note on the cache
+     * lookup below.) This step is iterated over all combinations of the
+     * candidate locales and formats until the <code>newBundle</code> method
+     * returns a <code>ResourceBundle</code> instance or the iteration has
+     * used up all the combinations. For example, if the candidate locales
+     * are <code>Locale("de", "DE")</code>, <code>Locale("de")</code> and
+     * <code>Locale("")</code> and the formats are <code>"java.class"</code>
+     * and <code>"java.properties"</code>, then the following is the
+     * sequence of locale-format combinations to be used to call
+     * <code>control.newBundle</code>.
+     *
+     * <table style="width: 50%; text-align: left; margin-left: 40px;"
+     *  border="0" cellpadding="2" cellspacing="2" summary="locale-format combinations for newBundle">
+     * <tbody>
+     * <tr>
+     * <td
+     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;"><code>Locale</code><br>
+     * </td>
+     * <td
+     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;"><code>format</code><br>
+     * </td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de", "DE")</code><br>
+     * </td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.class</code><br>
+     * </td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de", "DE")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.properties</code><br>
+     * </td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.class</code></td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.properties</code></td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("")</code><br>
+     * </td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.class</code></td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.properties</code></td>
+     * </tr>
+     * </tbody>
+     * </table>
+     * </li>
+     *
+     * <li>If the previous step has found no resource bundle, proceed to
+     * Step 6. If a bundle has been found that is a base bundle (a bundle
+     * for <code>Locale("")</code>), and the candidate locale list only contained
+     * <code>Locale("")</code>, return the bundle to the caller. If a bundle
+     * has been found that is a base bundle, but the candidate locale list
+     * contained locales other than Locale(""), put the bundle on hold and
+     * proceed to Step 6. If a bundle has been found that is not a base
+     * bundle, proceed to Step 7.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#getFallbackLocale(String,
+     * Locale) control.getFallbackLocale} method is called to get a fallback
+     * locale (alternative to the current target locale) to try further
+     * finding a resource bundle. If the method returns a non-null locale,
+     * it becomes the next target locale and the loading process starts over
+     * from Step 3. Otherwise, if a base bundle was found and put on hold in
+     * a previous Step 5, it is returned to the caller now. Otherwise, a
+     * MissingResourceException is thrown.</li>
+     *
+     * <li>At this point, we have found a resource bundle that's not the
+     * base bundle. If this bundle set its parent during its instantiation,
+     * it is returned to the caller. Otherwise, its <a
+     * href="./ResourceBundle.html#parent_chain">parent chain</a> is
+     * instantiated based on the list of candidate locales from which it was
+     * found. Finally, the bundle is returned to the caller.</li>
+     * </ol>
+     *
+     * <p>During the resource bundle loading process above, this factory
+     * method looks up the cache before calling the {@link
+     * Control#newBundle(String, Locale, String, ClassLoader, boolean)
+     * control.newBundle} method.  If the time-to-live period of the
+     * resource bundle found in the cache has expired, the factory method
+     * calls the {@link ResourceBundle.Control#needsReload(String, Locale,
+     * String, ClassLoader, ResourceBundle, long) control.needsReload}
+     * method to determine whether the resource bundle needs to be reloaded.
+     * If reloading is required, the factory method calls
+     * <code>control.newBundle</code> to reload the resource bundle.  If
+     * <code>control.newBundle</code> returns <code>null</code>, the factory
+     * method puts a dummy resource bundle in the cache as a mark of
+     * nonexistent resource bundles in order to avoid lookup overhead for
+     * subsequent requests. Such dummy resource bundles are under the same
+     * expiration control as specified by <code>control</code>.
+     *
+     * <p>All resource bundles loaded are cached by default. Refer to
+     * {@link Control#getTimeToLive(String,Locale)
+     * control.getTimeToLive} for details.
+     *
+     * <p>The following is an example of the bundle loading process with the
+     * default <code>ResourceBundle.Control</code> implementation.
+     *
+     * <p>Conditions:
+     * <ul>
+     * <li>Base bundle name: <code>foo.bar.Messages</code>
+     * <li>Requested <code>Locale</code>: {@link Locale#ITALY}</li>
+     * <li>Default <code>Locale</code>: {@link Locale#FRENCH}</li>
+     * <li>Available resource bundles:
+     * <code>foo/bar/Messages_fr.properties</code> and
+     * <code>foo/bar/Messages.properties</code></li>
+     * </ul>
+     *
+     * <p>First, <code>getBundle</code> tries loading a resource bundle in
+     * the following sequence.
+     *
+     * <ul>
+     * <li>class <code>foo.bar.Messages_it_IT</code>
+     * <li>file <code>foo/bar/Messages_it_IT.properties</code>
+     * <li>class <code>foo.bar.Messages_it</code></li>
+     * <li>file <code>foo/bar/Messages_it.properties</code></li>
+     * <li>class <code>foo.bar.Messages</code></li>
+     * <li>file <code>foo/bar/Messages.properties</code></li>
+     * </ul>
+     *
+     * <p>At this point, <code>getBundle</code> finds
+     * <code>foo/bar/Messages.properties</code>, which is put on hold
+     * because it's the base bundle.  <code>getBundle</code> calls {@link
+     * Control#getFallbackLocale(String, Locale)
+     * control.getFallbackLocale("foo.bar.Messages", Locale.ITALY)} which
+     * returns <code>Locale.FRENCH</code>. Next, <code>getBundle</code>
+     * tries loading a bundle in the following sequence.
+     *
+     * <ul>
+     * <li>class <code>foo.bar.Messages_fr</code></li>
+     * <li>file <code>foo/bar/Messages_fr.properties</code></li>
+     * <li>class <code>foo.bar.Messages</code></li>
+     * <li>file <code>foo/bar/Messages.properties</code></li>
+     * </ul>
+     *
+     * <p><code>getBundle</code> finds
+     * <code>foo/bar/Messages_fr.properties</code> and creates a
+     * <code>ResourceBundle</code> instance. Then, <code>getBundle</code>
+     * sets up its parent chain from the list of the candidate locales.  Only
+     * <code>foo/bar/Messages.properties</code> is found in the list and
+     * <code>getBundle</code> creates a <code>ResourceBundle</code> instance
+     * that becomes the parent of the instance for
+     * <code>foo/bar/Messages_fr.properties</code>.
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified
+     *        class name
+     * @param targetLocale
+     *        the locale for which a resource bundle is desired
+     * @param loader
+     *        the class loader from which to load the resource bundle
+     * @param control
+     *        the control which gives information for the resource
+     *        bundle loading process
+     * @return a resource bundle for the given base name and locale
+     * @exception NullPointerException
+     *        if <code>baseName</code>, <code>targetLocale</code>,
+     *        <code>loader</code>, or <code>control</code> is
+     *        <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name can be found
+     * @exception IllegalArgumentException
+     *        if the given <code>control</code> doesn't perform properly
+     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *        Note that validation of <code>control</code> is performed as
+     *        needed.
+     * @since 1.6
+     */
+    public static ResourceBundle getBundle(String baseName, Locale targetLocale,
+                                           ClassLoader loader, Control control) {
+        if (loader == null || control == null) {
+            throw new NullPointerException();
+        }
+        return getBundleImpl(baseName, targetLocale, loader, control);
+    }
+
+    private static Control getDefaultControl(String baseName) {
+        // Android-removed: Support for ResourceBundleControlProvider.
+        /*
+        if (providers != null) {
+            for (ResourceBundleControlProvider provider : providers) {
+                Control control = provider.getControl(baseName);
+                if (control != null) {
+                    return control;
+                }
+            }
+        }
+        */
+        return Control.INSTANCE;
+    }
+
+    private static ResourceBundle getBundleImpl(String baseName, Locale locale,
+                                                ClassLoader loader, Control control) {
+        if (locale == null || control == null) {
+            throw new NullPointerException();
+        }
+
+        // We create a CacheKey here for use by this call. The base
+        // name and loader will never change during the bundle loading
+        // process. We have to make sure that the locale is set before
+        // using it as a cache key.
+        CacheKey cacheKey = new CacheKey(baseName, locale, loader);
+        ResourceBundle bundle = null;
+
+        // Quick lookup of the cache.
+        BundleReference bundleRef = cacheList.get(cacheKey);
+        if (bundleRef != null) {
+            bundle = bundleRef.get();
+            bundleRef = null;
+        }
+
+        // If this bundle and all of its parents are valid (not expired),
+        // then return this bundle. If any of the bundles is expired, we
+        // don't call control.needsReload here but instead drop into the
+        // complete loading process below.
+        if (isValidBundle(bundle) && hasValidParentChain(bundle)) {
+            return bundle;
+        }
+
+        // No valid bundle was found in the cache, so we need to load the
+        // resource bundle and its parents.
+
+        boolean isKnownControl = (control == Control.INSTANCE) ||
+                                   (control instanceof SingleFormatControl);
+        List<String> formats = control.getFormats(baseName);
+        if (!isKnownControl && !checkList(formats)) {
+            throw new IllegalArgumentException("Invalid Control: getFormats");
+        }
+
+        ResourceBundle baseBundle = null;
+        for (Locale targetLocale = locale;
+             targetLocale != null;
+             targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
+            List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
+            if (!isKnownControl && !checkList(candidateLocales)) {
+                throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
+            }
+
+            bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle);
+
+            // If the loaded bundle is the base bundle and exactly for the
+            // requested locale or the only candidate locale, then take the
+            // bundle as the resulting one. If the loaded bundle is the base
+            // bundle, it's put on hold until we finish processing all
+            // fallback locales.
+            if (isValidBundle(bundle)) {
+                boolean isBaseBundle = Locale.ROOT.equals(bundle.locale);
+                if (!isBaseBundle || bundle.locale.equals(locale)
+                    || (candidateLocales.size() == 1
+                        && bundle.locale.equals(candidateLocales.get(0)))) {
+                    break;
+                }
+
+                // If the base bundle has been loaded, keep the reference in
+                // baseBundle so that we can avoid any redundant loading in case
+                // the control specify not to cache bundles.
+                if (isBaseBundle && baseBundle == null) {
+                    baseBundle = bundle;
+                }
+            }
+        }
+
+        if (bundle == null) {
+            if (baseBundle == null) {
+                throwMissingResourceException(baseName, locale, cacheKey.getCause());
+            }
+            bundle = baseBundle;
+        }
+
+        return bundle;
+    }
+
+    /**
+     * Checks if the given <code>List</code> is not null, not empty,
+     * not having null in its elements.
+     */
+    private static boolean checkList(List<?> a) {
+        boolean valid = (a != null && !a.isEmpty());
+        if (valid) {
+            int size = a.size();
+            for (int i = 0; valid && i < size; i++) {
+                valid = (a.get(i) != null);
+            }
+        }
+        return valid;
+    }
+
+    private static ResourceBundle findBundle(CacheKey cacheKey,
+                                             List<Locale> candidateLocales,
+                                             List<String> formats,
+                                             int index,
+                                             Control control,
+                                             ResourceBundle baseBundle) {
+        Locale targetLocale = candidateLocales.get(index);
+        ResourceBundle parent = null;
+        if (index != candidateLocales.size() - 1) {
+            parent = findBundle(cacheKey, candidateLocales, formats, index + 1,
+                                control, baseBundle);
+        } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) {
+            return baseBundle;
+        }
+
+        // Before we do the real loading work, see whether we need to
+        // do some housekeeping: If references to class loaders or
+        // resource bundles have been nulled out, remove all related
+        // information from the cache.
+        Object ref;
+        while ((ref = referenceQueue.poll()) != null) {
+            cacheList.remove(((CacheKeyReference)ref).getCacheKey());
+        }
+
+        // flag indicating the resource bundle has expired in the cache
+        boolean expiredBundle = false;
+
+        // First, look up the cache to see if it's in the cache, without
+        // attempting to load bundle.
+        cacheKey.setLocale(targetLocale);
+        ResourceBundle bundle = findBundleInCache(cacheKey, control);
+        if (isValidBundle(bundle)) {
+            expiredBundle = bundle.expired;
+            if (!expiredBundle) {
+                // If its parent is the one asked for by the candidate
+                // locales (the runtime lookup path), we can take the cached
+                // one. (If it's not identical, then we'd have to check the
+                // parent's parents to be consistent with what's been
+                // requested.)
+                if (bundle.parent == parent) {
+                    return bundle;
+                }
+                // Otherwise, remove the cached one since we can't keep
+                // the same bundles having different parents.
+                BundleReference bundleRef = cacheList.get(cacheKey);
+                if (bundleRef != null && bundleRef.get() == bundle) {
+                    cacheList.remove(cacheKey, bundleRef);
+                }
+            }
+        }
+
+        if (bundle != NONEXISTENT_BUNDLE) {
+            CacheKey constKey = (CacheKey) cacheKey.clone();
+
+            try {
+                bundle = loadBundle(cacheKey, formats, control, expiredBundle);
+                if (bundle != null) {
+                    if (bundle.parent == null) {
+                        bundle.setParent(parent);
+                    }
+                    bundle.locale = targetLocale;
+                    bundle = putBundleInCache(cacheKey, bundle, control);
+                    return bundle;
+                }
+
+                // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
+                // instance for the locale.
+                putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
+            } finally {
+                if (constKey.getCause() instanceof InterruptedException) {
+                    Thread.currentThread().interrupt();
+                }
+            }
+        }
+        return parent;
+    }
+
+    private static ResourceBundle loadBundle(CacheKey cacheKey,
+                                             List<String> formats,
+                                             Control control,
+                                             boolean reload) {
+
+        // Here we actually load the bundle in the order of formats
+        // specified by the getFormats() value.
+        Locale targetLocale = cacheKey.getLocale();
+
+        ResourceBundle bundle = null;
+        int size = formats.size();
+        for (int i = 0; i < size; i++) {
+            String format = formats.get(i);
+            try {
+                bundle = control.newBundle(cacheKey.getName(), targetLocale, format,
+                                           cacheKey.getLoader(), reload);
+            } catch (LinkageError error) {
+                // We need to handle the LinkageError case due to
+                // inconsistent case-sensitivity in ClassLoader.
+                // See 6572242 for details.
+                cacheKey.setCause(error);
+            } catch (Exception cause) {
+                cacheKey.setCause(cause);
+            }
+            if (bundle != null) {
+                // Set the format in the cache key so that it can be
+                // used when calling needsReload later.
+                cacheKey.setFormat(format);
+                bundle.name = cacheKey.getName();
+                bundle.locale = targetLocale;
+                // Bundle provider might reuse instances. So we should make
+                // sure to clear the expired flag here.
+                bundle.expired = false;
+                break;
+            }
+        }
+
+        return bundle;
+    }
+
+    private static boolean isValidBundle(ResourceBundle bundle) {
+        return bundle != null && bundle != NONEXISTENT_BUNDLE;
+    }
+
+    /**
+     * Determines whether any of resource bundles in the parent chain,
+     * including the leaf, have expired.
+     */
+    private static boolean hasValidParentChain(ResourceBundle bundle) {
+        long now = System.currentTimeMillis();
+        while (bundle != null) {
+            if (bundle.expired) {
+                return false;
+            }
+            CacheKey key = bundle.cacheKey;
+            if (key != null) {
+                long expirationTime = key.expirationTime;
+                if (expirationTime >= 0 && expirationTime <= now) {
+                    return false;
+                }
+            }
+            bundle = bundle.parent;
+        }
+        return true;
+    }
+
+    /**
+     * Throw a MissingResourceException with proper message
+     */
+    private static void throwMissingResourceException(String baseName,
+                                                      Locale locale,
+                                                      Throwable cause) {
+        // If the cause is a MissingResourceException, avoid creating
+        // a long chain. (6355009)
+        if (cause instanceof MissingResourceException) {
+            cause = null;
+        }
+        throw new MissingResourceException("Can't find bundle for base name "
+                                           + baseName + ", locale " + locale,
+                                           baseName + "_" + locale, // className
+                                           "",                      // key
+                                           cause);
+    }
+
+    /**
+     * Finds a bundle in the cache. Any expired bundles are marked as
+     * `expired' and removed from the cache upon return.
+     *
+     * @param cacheKey the key to look up the cache
+     * @param control the Control to be used for the expiration control
+     * @return the cached bundle, or null if the bundle is not found in the
+     * cache or its parent has expired. <code>bundle.expire</code> is true
+     * upon return if the bundle in the cache has expired.
+     */
+    private static ResourceBundle findBundleInCache(CacheKey cacheKey,
+                                                    Control control) {
+        BundleReference bundleRef = cacheList.get(cacheKey);
+        if (bundleRef == null) {
+            return null;
+        }
+        ResourceBundle bundle = bundleRef.get();
+        if (bundle == null) {
+            return null;
+        }
+        ResourceBundle p = bundle.parent;
+        assert p != NONEXISTENT_BUNDLE;
+        // If the parent has expired, then this one must also expire. We
+        // check only the immediate parent because the actual loading is
+        // done from the root (base) to leaf (child) and the purpose of
+        // checking is to propagate expiration towards the leaf. For
+        // example, if the requested locale is ja_JP_JP and there are
+        // bundles for all of the candidates in the cache, we have a list,
+        //
+        // base <- ja <- ja_JP <- ja_JP_JP
+        //
+        // If ja has expired, then it will reload ja and the list becomes a
+        // tree.
+        //
+        // base <- ja (new)
+        //  "   <- ja (expired) <- ja_JP <- ja_JP_JP
+        //
+        // When looking up ja_JP in the cache, it finds ja_JP in the cache
+        // which references to the expired ja. Then, ja_JP is marked as
+        // expired and removed from the cache. This will be propagated to
+        // ja_JP_JP.
+        //
+        // Now, it's possible, for example, that while loading new ja_JP,
+        // someone else has started loading the same bundle and finds the
+        // base bundle has expired. Then, what we get from the first
+        // getBundle call includes the expired base bundle. However, if
+        // someone else didn't start its loading, we wouldn't know if the
+        // base bundle has expired at the end of the loading process. The
+        // expiration control doesn't guarantee that the returned bundle and
+        // its parents haven't expired.
+        //
+        // We could check the entire parent chain to see if there's any in
+        // the chain that has expired. But this process may never end. An
+        // extreme case would be that getTimeToLive returns 0 and
+        // needsReload always returns true.
+        if (p != null && p.expired) {
+            assert bundle != NONEXISTENT_BUNDLE;
+            bundle.expired = true;
+            bundle.cacheKey = null;
+            cacheList.remove(cacheKey, bundleRef);
+            bundle = null;
+        } else {
+            CacheKey key = bundleRef.getCacheKey();
+            long expirationTime = key.expirationTime;
+            if (!bundle.expired && expirationTime >= 0 &&
+                expirationTime <= System.currentTimeMillis()) {
+                // its TTL period has expired.
+                if (bundle != NONEXISTENT_BUNDLE) {
+                    // Synchronize here to call needsReload to avoid
+                    // redundant concurrent calls for the same bundle.
+                    synchronized (bundle) {
+                        expirationTime = key.expirationTime;
+                        if (!bundle.expired && expirationTime >= 0 &&
+                            expirationTime <= System.currentTimeMillis()) {
+                            try {
+                                bundle.expired = control.needsReload(key.getName(),
+                                                                     key.getLocale(),
+                                                                     key.getFormat(),
+                                                                     key.getLoader(),
+                                                                     bundle,
+                                                                     key.loadTime);
+                            } catch (Exception e) {
+                                cacheKey.setCause(e);
+                            }
+                            if (bundle.expired) {
+                                // If the bundle needs to be reloaded, then
+                                // remove the bundle from the cache, but
+                                // return the bundle with the expired flag
+                                // on.
+                                bundle.cacheKey = null;
+                                cacheList.remove(cacheKey, bundleRef);
+                            } else {
+                                // Update the expiration control info. and reuse
+                                // the same bundle instance
+                                setExpirationTime(key, control);
+                            }
+                        }
+                    }
+                } else {
+                    // We just remove NONEXISTENT_BUNDLE from the cache.
+                    cacheList.remove(cacheKey, bundleRef);
+                    bundle = null;
+                }
+            }
+        }
+        return bundle;
+    }
+
+    /**
+     * Put a new bundle in the cache.
+     *
+     * @param cacheKey the key for the resource bundle
+     * @param bundle the resource bundle to be put in the cache
+     * @return the ResourceBundle for the cacheKey; if someone has put
+     * the bundle before this call, the one found in the cache is
+     * returned.
+     */
+    private static ResourceBundle putBundleInCache(CacheKey cacheKey,
+                                                   ResourceBundle bundle,
+                                                   Control control) {
+        setExpirationTime(cacheKey, control);
+        if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) {
+            CacheKey key = (CacheKey) cacheKey.clone();
+            BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key);
+            bundle.cacheKey = key;
+
+            // Put the bundle in the cache if it's not been in the cache.
+            BundleReference result = cacheList.putIfAbsent(key, bundleRef);
+
+            // If someone else has put the same bundle in the cache before
+            // us and it has not expired, we should use the one in the cache.
+            if (result != null) {
+                ResourceBundle rb = result.get();
+                if (rb != null && !rb.expired) {
+                    // Clear the back link to the cache key
+                    bundle.cacheKey = null;
+                    bundle = rb;
+                    // Clear the reference in the BundleReference so that
+                    // it won't be enqueued.
+                    bundleRef.clear();
+                } else {
+                    // Replace the invalid (garbage collected or expired)
+                    // instance with the valid one.
+                    cacheList.put(key, bundleRef);
+                }
+            }
+        }
+        return bundle;
+    }
+
+    private static void setExpirationTime(CacheKey cacheKey, Control control) {
+        long ttl = control.getTimeToLive(cacheKey.getName(),
+                                         cacheKey.getLocale());
+        if (ttl >= 0) {
+            // If any expiration time is specified, set the time to be
+            // expired in the cache.
+            long now = System.currentTimeMillis();
+            cacheKey.loadTime = now;
+            cacheKey.expirationTime = now + ttl;
+        } else if (ttl >= Control.TTL_NO_EXPIRATION_CONTROL) {
+            cacheKey.expirationTime = ttl;
+        } else {
+            throw new IllegalArgumentException("Invalid Control: TTL=" + ttl);
+        }
+    }
+
+    /**
+     * Removes all resource bundles from the cache that have been loaded
+     * using the caller's class loader.
+     *
+     * @since 1.6
+     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
+     */
+    @CallerSensitive
+    public static final void clearCache() {
+        clearCache(getLoader(Reflection.getCallerClass()));
+    }
+
+    /**
+     * Removes all resource bundles from the cache that have been loaded
+     * using the given class loader.
+     *
+     * @param loader the class loader
+     * @exception NullPointerException if <code>loader</code> is null
+     * @since 1.6
+     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
+     */
+    public static final void clearCache(ClassLoader loader) {
+        if (loader == null) {
+            throw new NullPointerException();
+        }
+        Set<CacheKey> set = cacheList.keySet();
+        for (CacheKey key : set) {
+            if (key.getLoader() == loader) {
+                set.remove(key);
+            }
+        }
+    }
+
+    /**
+     * Gets an object for the given key from this resource bundle.
+     * Returns null if this resource bundle does not contain an
+     * object for the given key.
+     *
+     * @param key the key for the desired object
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @return the object for the given key, or null
+     */
+    protected abstract Object handleGetObject(String key);
+
+    /**
+     * Returns an enumeration of the keys.
+     *
+     * @return an <code>Enumeration</code> of the keys contained in
+     *         this <code>ResourceBundle</code> and its parent bundles.
+     */
+    public abstract Enumeration<String> getKeys();
+
+    /**
+     * Determines whether the given <code>key</code> is contained in
+     * this <code>ResourceBundle</code> or its parent bundles.
+     *
+     * @param key
+     *        the resource <code>key</code>
+     * @return <code>true</code> if the given <code>key</code> is
+     *        contained in this <code>ResourceBundle</code> or its
+     *        parent bundles; <code>false</code> otherwise.
+     * @exception NullPointerException
+     *         if <code>key</code> is <code>null</code>
+     * @since 1.6
+     */
+    public boolean containsKey(String key) {
+        if (key == null) {
+            throw new NullPointerException();
+        }
+        for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
+            if (rb.handleKeySet().contains(key)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a <code>Set</code> of all keys contained in this
+     * <code>ResourceBundle</code> and its parent bundles.
+     *
+     * @return a <code>Set</code> of all keys contained in this
+     *         <code>ResourceBundle</code> and its parent bundles.
+     * @since 1.6
+     */
+    public Set<String> keySet() {
+        Set<String> keys = new HashSet<>();
+        for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
+            keys.addAll(rb.handleKeySet());
+        }
+        return keys;
+    }
+
+    /**
+     * Returns a <code>Set</code> of the keys contained <em>only</em>
+     * in this <code>ResourceBundle</code>.
+     *
+     * <p>The default implementation returns a <code>Set</code> of the
+     * keys returned by the {@link #getKeys() getKeys} method except
+     * for the ones for which the {@link #handleGetObject(String)
+     * handleGetObject} method returns <code>null</code>. Once the
+     * <code>Set</code> has been created, the value is kept in this
+     * <code>ResourceBundle</code> in order to avoid producing the
+     * same <code>Set</code> in subsequent calls. Subclasses can
+     * override this method for faster handling.
+     *
+     * @return a <code>Set</code> of the keys contained only in this
+     *        <code>ResourceBundle</code>
+     * @since 1.6
+     */
+    protected Set<String> handleKeySet() {
+        if (keySet == null) {
+            synchronized (this) {
+                if (keySet == null) {
+                    Set<String> keys = new HashSet<>();
+                    Enumeration<String> enumKeys = getKeys();
+                    while (enumKeys.hasMoreElements()) {
+                        String key = enumKeys.nextElement();
+                        if (handleGetObject(key) != null) {
+                            keys.add(key);
+                        }
+                    }
+                    keySet = keys;
+                }
+            }
+        }
+        return keySet;
+    }
+
+
+
+    /**
+     * <code>ResourceBundle.Control</code> defines a set of callback methods
+     * that are invoked by the {@link ResourceBundle#getBundle(String,
+     * Locale, ClassLoader, Control) ResourceBundle.getBundle} factory
+     * methods during the bundle loading process. In other words, a
+     * <code>ResourceBundle.Control</code> collaborates with the factory
+     * methods for loading resource bundles. The default implementation of
+     * the callback methods provides the information necessary for the
+     * factory methods to perform the <a
+     * href="./ResourceBundle.html#default_behavior">default behavior</a>.
+     *
+     * <p>In addition to the callback methods, the {@link
+     * #toBundleName(String, Locale) toBundleName} and {@link
+     * #toResourceName(String, String) toResourceName} methods are defined
+     * primarily for convenience in implementing the callback
+     * methods. However, the <code>toBundleName</code> method could be
+     * overridden to provide different conventions in the organization and
+     * packaging of localized resources.  The <code>toResourceName</code>
+     * method is <code>final</code> to avoid use of wrong resource and class
+     * name separators.
+     *
+     * <p>Two factory methods, {@link #getControl(List)} and {@link
+     * #getNoFallbackControl(List)}, provide
+     * <code>ResourceBundle.Control</code> instances that implement common
+     * variations of the default bundle loading process.
+     *
+     * <p>The formats returned by the {@link Control#getFormats(String)
+     * getFormats} method and candidate locales returned by the {@link
+     * ResourceBundle.Control#getCandidateLocales(String, Locale)
+     * getCandidateLocales} method must be consistent in all
+     * <code>ResourceBundle.getBundle</code> invocations for the same base
+     * bundle. Otherwise, the <code>ResourceBundle.getBundle</code> methods
+     * may return unintended bundles. For example, if only
+     * <code>"java.class"</code> is returned by the <code>getFormats</code>
+     * method for the first call to <code>ResourceBundle.getBundle</code>
+     * and only <code>"java.properties"</code> for the second call, then the
+     * second call will return the class-based one that has been cached
+     * during the first call.
+     *
+     * <p>A <code>ResourceBundle.Control</code> instance must be thread-safe
+     * if it's simultaneously used by multiple threads.
+     * <code>ResourceBundle.getBundle</code> does not synchronize to call
+     * the <code>ResourceBundle.Control</code> methods. The default
+     * implementations of the methods are thread-safe.
+     *
+     * <p>Applications can specify <code>ResourceBundle.Control</code>
+     * instances returned by the <code>getControl</code> factory methods or
+     * created from a subclass of <code>ResourceBundle.Control</code> to
+     * customize the bundle loading process. The following are examples of
+     * changing the default bundle loading process.
+     *
+     * <p><b>Example 1</b>
+     *
+     * <p>The following code lets <code>ResourceBundle.getBundle</code> look
+     * up only properties-based resources.
+     *
+     * <pre>
+     * import java.util.*;
+     * import static java.util.ResourceBundle.Control.*;
+     * ...
+     * ResourceBundle bundle =
+     *   ResourceBundle.getBundle("MyResources", new Locale("fr", "CH"),
+     *                            ResourceBundle.Control.getControl(FORMAT_PROPERTIES));
+     * </pre>
+     *
+     * Given the resource bundles in the <a
+     * href="./ResourceBundle.html#default_behavior_example">example</a> in
+     * the <code>ResourceBundle.getBundle</code> description, this
+     * <code>ResourceBundle.getBundle</code> call loads
+     * <code>MyResources_fr_CH.properties</code> whose parent is
+     * <code>MyResources_fr.properties</code> whose parent is
+     * <code>MyResources.properties</code>. (<code>MyResources_fr_CH.properties</code>
+     * is not hidden, but <code>MyResources_fr_CH.class</code> is.)
+     *
+     * <p><b>Example 2</b>
+     *
+     * <p>The following is an example of loading XML-based bundles
+     * using {@link Properties#loadFromXML(java.io.InputStream)
+     * Properties.loadFromXML}.
+     *
+     * <pre>
+     * ResourceBundle rb = ResourceBundle.getBundle("Messages",
+     *     new ResourceBundle.Control() {
+     *         public List&lt;String&gt; getFormats(String baseName) {
+     *             if (baseName == null)
+     *                 throw new NullPointerException();
+     *             return Arrays.asList("xml");
+     *         }
+     *         public ResourceBundle newBundle(String baseName,
+     *                                         Locale locale,
+     *                                         String format,
+     *                                         ClassLoader loader,
+     *                                         boolean reload)
+     *                          throws IllegalAccessException,
+     *                                 InstantiationException,
+     *                                 IOException {
+     *             if (baseName == null || locale == null
+     *                   || format == null || loader == null)
+     *                 throw new NullPointerException();
+     *             ResourceBundle bundle = null;
+     *             if (format.equals("xml")) {
+     *                 String bundleName = toBundleName(baseName, locale);
+     *                 String resourceName = toResourceName(bundleName, format);
+     *                 InputStream stream = null;
+     *                 if (reload) {
+     *                     URL url = loader.getResource(resourceName);
+     *                     if (url != null) {
+     *                         URLConnection connection = url.openConnection();
+     *                         if (connection != null) {
+     *                             // Disable caches to get fresh data for
+     *                             // reloading.
+     *                             connection.setUseCaches(false);
+     *                             stream = connection.getInputStream();
+     *                         }
+     *                     }
+     *                 } else {
+     *                     stream = loader.getResourceAsStream(resourceName);
+     *                 }
+     *                 if (stream != null) {
+     *                     BufferedInputStream bis = new BufferedInputStream(stream);
+     *                     bundle = new XMLResourceBundle(bis);
+     *                     bis.close();
+     *                 }
+     *             }
+     *             return bundle;
+     *         }
+     *     });
+     *
+     * ...
+     *
+     * private static class XMLResourceBundle extends ResourceBundle {
+     *     private Properties props;
+     *     XMLResourceBundle(InputStream stream) throws IOException {
+     *         props = new Properties();
+     *         props.loadFromXML(stream);
+     *     }
+     *     protected Object handleGetObject(String key) {
+     *         return props.getProperty(key);
+     *     }
+     *     public Enumeration&lt;String&gt; getKeys() {
+     *         ...
+     *     }
+     * }
+     * </pre>
+     *
+     * @since 1.6
+     */
+    public static class Control {
+        /**
+         * The default format <code>List</code>, which contains the strings
+         * <code>"java.class"</code> and <code>"java.properties"</code>, in
+         * this order. This <code>List</code> is {@linkplain
+         * Collections#unmodifiableList(List) unmodifiable}.
+         *
+         * @see #getFormats(String)
+         */
+        public static final List<String> FORMAT_DEFAULT
+            = Collections.unmodifiableList(Arrays.asList("java.class",
+                                                         "java.properties"));
+
+        /**
+         * The class-only format <code>List</code> containing
+         * <code>"java.class"</code>. This <code>List</code> is {@linkplain
+         * Collections#unmodifiableList(List) unmodifiable}.
+         *
+         * @see #getFormats(String)
+         */
+        public static final List<String> FORMAT_CLASS
+            = Collections.unmodifiableList(Arrays.asList("java.class"));
+
+        /**
+         * The properties-only format <code>List</code> containing
+         * <code>"java.properties"</code>. This <code>List</code> is
+         * {@linkplain Collections#unmodifiableList(List) unmodifiable}.
+         *
+         * @see #getFormats(String)
+         */
+        public static final List<String> FORMAT_PROPERTIES
+            = Collections.unmodifiableList(Arrays.asList("java.properties"));
+
+        /**
+         * The time-to-live constant for not caching loaded resource bundle
+         * instances.
+         *
+         * @see #getTimeToLive(String, Locale)
+         */
+        public static final long TTL_DONT_CACHE = -1;
+
+        /**
+         * The time-to-live constant for disabling the expiration control
+         * for loaded resource bundle instances in the cache.
+         *
+         * @see #getTimeToLive(String, Locale)
+         */
+        public static final long TTL_NO_EXPIRATION_CONTROL = -2;
+
+        private static final Control INSTANCE = new Control();
+
+        /**
+         * Sole constructor. (For invocation by subclass constructors,
+         * typically implicit.)
+         */
+        protected Control() {
+        }
+
+        /**
+         * Returns a <code>ResourceBundle.Control</code> in which the {@link
+         * #getFormats(String) getFormats} method returns the specified
+         * <code>formats</code>. The <code>formats</code> must be equal to
+         * one of {@link Control#FORMAT_PROPERTIES}, {@link
+         * Control#FORMAT_CLASS} or {@link
+         * Control#FORMAT_DEFAULT}. <code>ResourceBundle.Control</code>
+         * instances returned by this method are singletons and thread-safe.
+         *
+         * <p>Specifying {@link Control#FORMAT_DEFAULT} is equivalent to
+         * instantiating the <code>ResourceBundle.Control</code> class,
+         * except that this method returns a singleton.
+         *
+         * @param formats
+         *        the formats to be returned by the
+         *        <code>ResourceBundle.Control.getFormats</code> method
+         * @return a <code>ResourceBundle.Control</code> supporting the
+         *        specified <code>formats</code>
+         * @exception NullPointerException
+         *        if <code>formats</code> is <code>null</code>
+         * @exception IllegalArgumentException
+         *        if <code>formats</code> is unknown
+         */
+        public static final Control getControl(List<String> formats) {
+            if (formats.equals(Control.FORMAT_PROPERTIES)) {
+                return SingleFormatControl.PROPERTIES_ONLY;
+            }
+            if (formats.equals(Control.FORMAT_CLASS)) {
+                return SingleFormatControl.CLASS_ONLY;
+            }
+            if (formats.equals(Control.FORMAT_DEFAULT)) {
+                return Control.INSTANCE;
+            }
+            throw new IllegalArgumentException();
+        }
+
+        /**
+         * Returns a <code>ResourceBundle.Control</code> in which the {@link
+         * #getFormats(String) getFormats} method returns the specified
+         * <code>formats</code> and the {@link
+         * Control#getFallbackLocale(String, Locale) getFallbackLocale}
+         * method returns <code>null</code>. The <code>formats</code> must
+         * be equal to one of {@link Control#FORMAT_PROPERTIES}, {@link
+         * Control#FORMAT_CLASS} or {@link Control#FORMAT_DEFAULT}.
+         * <code>ResourceBundle.Control</code> instances returned by this
+         * method are singletons and thread-safe.
+         *
+         * @param formats
+         *        the formats to be returned by the
+         *        <code>ResourceBundle.Control.getFormats</code> method
+         * @return a <code>ResourceBundle.Control</code> supporting the
+         *        specified <code>formats</code> with no fallback
+         *        <code>Locale</code> support
+         * @exception NullPointerException
+         *        if <code>formats</code> is <code>null</code>
+         * @exception IllegalArgumentException
+         *        if <code>formats</code> is unknown
+         */
+        public static final Control getNoFallbackControl(List<String> formats) {
+            if (formats.equals(Control.FORMAT_DEFAULT)) {
+                return NoFallbackControl.NO_FALLBACK;
+            }
+            if (formats.equals(Control.FORMAT_PROPERTIES)) {
+                return NoFallbackControl.PROPERTIES_ONLY_NO_FALLBACK;
+            }
+            if (formats.equals(Control.FORMAT_CLASS)) {
+                return NoFallbackControl.CLASS_ONLY_NO_FALLBACK;
+            }
+            throw new IllegalArgumentException();
+        }
+
+        /**
+         * Returns a <code>List</code> of <code>String</code>s containing
+         * formats to be used to load resource bundles for the given
+         * <code>baseName</code>. The <code>ResourceBundle.getBundle</code>
+         * factory method tries to load resource bundles with formats in the
+         * order specified by the list. The list returned by this method
+         * must have at least one <code>String</code>. The predefined
+         * formats are <code>"java.class"</code> for class-based resource
+         * bundles and <code>"java.properties"</code> for {@linkplain
+         * PropertyResourceBundle properties-based} ones. Strings starting
+         * with <code>"java."</code> are reserved for future extensions and
+         * must not be used by application-defined formats.
+         *
+         * <p>It is not a requirement to return an immutable (unmodifiable)
+         * <code>List</code>.  However, the returned <code>List</code> must
+         * not be mutated after it has been returned by
+         * <code>getFormats</code>.
+         *
+         * <p>The default implementation returns {@link #FORMAT_DEFAULT} so
+         * that the <code>ResourceBundle.getBundle</code> factory method
+         * looks up first class-based resource bundles, then
+         * properties-based ones.
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully qualified class
+         *        name
+         * @return a <code>List</code> of <code>String</code>s containing
+         *        formats for loading resource bundles.
+         * @exception NullPointerException
+         *        if <code>baseName</code> is null
+         * @see #FORMAT_DEFAULT
+         * @see #FORMAT_CLASS
+         * @see #FORMAT_PROPERTIES
+         */
+        public List<String> getFormats(String baseName) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            return FORMAT_DEFAULT;
+        }
+
+        /**
+         * Returns a <code>List</code> of <code>Locale</code>s as candidate
+         * locales for <code>baseName</code> and <code>locale</code>. This
+         * method is called by the <code>ResourceBundle.getBundle</code>
+         * factory method each time the factory method tries finding a
+         * resource bundle for a target <code>Locale</code>.
+         *
+         * <p>The sequence of the candidate locales also corresponds to the
+         * runtime resource lookup path (also known as the <I>parent
+         * chain</I>), if the corresponding resource bundles for the
+         * candidate locales exist and their parents are not defined by
+         * loaded resource bundles themselves.  The last element of the list
+         * must be a {@linkplain Locale#ROOT root locale} if it is desired to
+         * have the base bundle as the terminal of the parent chain.
+         *
+         * <p>If the given locale is equal to <code>Locale.ROOT</code> (the
+         * root locale), a <code>List</code> containing only the root
+         * <code>Locale</code> must be returned. In this case, the
+         * <code>ResourceBundle.getBundle</code> factory method loads only
+         * the base bundle as the resulting resource bundle.
+         *
+         * <p>It is not a requirement to return an immutable (unmodifiable)
+         * <code>List</code>. However, the returned <code>List</code> must not
+         * be mutated after it has been returned by
+         * <code>getCandidateLocales</code>.
+         *
+         * <p>The default implementation returns a <code>List</code> containing
+         * <code>Locale</code>s using the rules described below.  In the
+         * description below, <em>L</em>, <em>S</em>, <em>C</em> and <em>V</em>
+         * respectively represent non-empty language, script, country, and
+         * variant.  For example, [<em>L</em>, <em>C</em>] represents a
+         * <code>Locale</code> that has non-empty values only for language and
+         * country.  The form <em>L</em>("xx") represents the (non-empty)
+         * language value is "xx".  For all cases, <code>Locale</code>s whose
+         * final component values are empty strings are omitted.
+         *
+         * <ol><li>For an input <code>Locale</code> with an empty script value,
+         * append candidate <code>Locale</code>s by omitting the final component
+         * one by one as below:
+         *
+         * <ul>
+         * <li> [<em>L</em>, <em>C</em>, <em>V</em>] </li>
+         * <li> [<em>L</em>, <em>C</em>] </li>
+         * <li> [<em>L</em>] </li>
+         * <li> <code>Locale.ROOT</code> </li>
+         * </ul></li>
+         *
+         * <li>For an input <code>Locale</code> with a non-empty script value,
+         * append candidate <code>Locale</code>s by omitting the final component
+         * up to language, then append candidates generated from the
+         * <code>Locale</code> with country and variant restored:
+         *
+         * <ul>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
+         *
+         * <li>For an input <code>Locale</code> with a variant value consisting
+         * of multiple subtags separated by underscore, generate candidate
+         * <code>Locale</code>s by omitting the variant subtags one by one, then
+         * insert them after every occurrence of <code> Locale</code>s with the
+         * full variant value in the original list.  For example, if the
+         * the variant consists of two subtags <em>V1</em> and <em>V2</em>:
+         *
+         * <ul>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
+         *
+         * <li>Special cases for Chinese.  When an input <code>Locale</code> has the
+         * language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or
+         * "Hant" (Traditional) might be supplied, depending on the country.
+         * When the country is "CN" (China) or "SG" (Singapore), "Hans" is supplied.
+         * When the country is "HK" (Hong Kong SAR China), "MO" (Macau SAR China),
+         * or "TW" (Taiwan), "Hant" is supplied.  For all other countries or when the country
+         * is empty, no script is supplied.  For example, for <code>Locale("zh", "CN")
+         * </code>, the candidate list will be:
+         * <ul>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]</li>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]</li>
+         * <li> [<em>L</em>("zh"), <em>C</em>("CN")]</li>
+         * <li> [<em>L</em>("zh")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul>
+         *
+         * For <code>Locale("zh", "TW")</code>, the candidate list will be:
+         * <ul>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]</li>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]</li>
+         * <li> [<em>L</em>("zh"), <em>C</em>("TW")]</li>
+         * <li> [<em>L</em>("zh")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
+         *
+         * <li>Special cases for Norwegian.  Both <code>Locale("no", "NO",
+         * "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian
+         * Nynorsk.  When a locale's language is "nn", the standard candidate
+         * list is generated up to [<em>L</em>("nn")], and then the following
+         * candidates are added:
+         *
+         * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("no")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul>
+         *
+         * If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first
+         * converted to <code>Locale("nn", "NO")</code> and then the above procedure is
+         * followed.
+         *
+         * <p>Also, Java treats the language "no" as a synonym of Norwegian
+         * Bokm&#xE5;l "nb".  Except for the single case <code>Locale("no",
+         * "NO", "NY")</code> (handled above), when an input <code>Locale</code>
+         * has language "no" or "nb", candidate <code>Locale</code>s with
+         * language code "no" and "nb" are interleaved, first using the
+         * requested language, then using its synonym. For example,
+         * <code>Locale("nb", "NO", "POSIX")</code> generates the following
+         * candidate list:
+         *
+         * <ul>
+         * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]</li>
+         * <li> [<em>L</em>("nb"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("nb")]</li>
+         * <li> [<em>L</em>("no")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul>
+         *
+         * <code>Locale("no", "NO", "POSIX")</code> would generate the same list
+         * except that locales with "no" would appear before the corresponding
+         * locales with "nb".</li>
+         * </ol>
+         *
+         * <p>The default implementation uses an {@link ArrayList} that
+         * overriding implementations may modify before returning it to the
+         * caller. However, a subclass must not modify it after it has
+         * been returned by <code>getCandidateLocales</code>.
+         *
+         * <p>For example, if the given <code>baseName</code> is "Messages"
+         * and the given <code>locale</code> is
+         * <code>Locale("ja",&nbsp;"",&nbsp;"XX")</code>, then a
+         * <code>List</code> of <code>Locale</code>s:
+         * <pre>
+         *     Locale("ja", "", "XX")
+         *     Locale("ja")
+         *     Locale.ROOT
+         * </pre>
+         * is returned. And if the resource bundles for the "ja" and
+         * "" <code>Locale</code>s are found, then the runtime resource
+         * lookup path (parent chain) is:
+         * <pre>{@code
+         *     Messages_ja -> Messages
+         * }</pre>
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully
+         *        qualified class name
+         * @param locale
+         *        the locale for which a resource bundle is desired
+         * @return a <code>List</code> of candidate
+         *        <code>Locale</code>s for the given <code>locale</code>
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code> is
+         *        <code>null</code>
+         */
+        public List<Locale> getCandidateLocales(String baseName, Locale locale) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            return new ArrayList<>(CANDIDATES_CACHE.get(locale.getBaseLocale()));
+        }
+
+        private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
+
+        private static class CandidateListCache extends LocaleObjectCache<BaseLocale, List<Locale>> {
+            protected List<Locale> createObject(BaseLocale base) {
+                String language = base.getLanguage();
+                String script = base.getScript();
+                String region = base.getRegion();
+                String variant = base.getVariant();
+
+                // Special handling for Norwegian
+                boolean isNorwegianBokmal = false;
+                boolean isNorwegianNynorsk = false;
+                if (language.equals("no")) {
+                    if (region.equals("NO") && variant.equals("NY")) {
+                        variant = "";
+                        isNorwegianNynorsk = true;
+                    } else {
+                        isNorwegianBokmal = true;
+                    }
+                }
+                if (language.equals("nb") || isNorwegianBokmal) {
+                    List<Locale> tmpList = getDefaultList("nb", script, region, variant);
+                    // Insert a locale replacing "nb" with "no" for every list entry
+                    List<Locale> bokmalList = new LinkedList<>();
+                    for (Locale l : tmpList) {
+                        bokmalList.add(l);
+                        if (l.getLanguage().length() == 0) {
+                            break;
+                        }
+                        bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(),
+                                l.getVariant(), null));
+                    }
+                    return bokmalList;
+                } else if (language.equals("nn") || isNorwegianNynorsk) {
+                    // Insert no_NO_NY, no_NO, no after nn
+                    List<Locale> nynorskList = getDefaultList("nn", script, region, variant);
+                    int idx = nynorskList.size() - 1;
+                    nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
+                    nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
+                    nynorskList.add(idx++, Locale.getInstance("no", "", ""));
+                    return nynorskList;
+                }
+                // Special handling for Chinese
+                else if (language.equals("zh")) {
+                    if (script.length() == 0 && region.length() > 0) {
+                        // Supply script for users who want to use zh_Hans/zh_Hant
+                        // as bundle names (recommended for Java7+)
+                        switch (region) {
+                        case "TW":
+                        case "HK":
+                        case "MO":
+                            script = "Hant";
+                            break;
+                        case "CN":
+                        case "SG":
+                            script = "Hans";
+                            break;
+                        }
+                    } else if (script.length() > 0 && region.length() == 0) {
+                        // Supply region(country) for users who still package Chinese
+                        // bundles using old convension.
+                        switch (script) {
+                        case "Hans":
+                            region = "CN";
+                            break;
+                        case "Hant":
+                            region = "TW";
+                            break;
+                        }
+                    }
+                }
+
+                return getDefaultList(language, script, region, variant);
+            }
+
+            private static List<Locale> getDefaultList(String language, String script, String region, String variant) {
+                List<String> variants = null;
+
+                if (variant.length() > 0) {
+                    variants = new LinkedList<>();
+                    int idx = variant.length();
+                    while (idx != -1) {
+                        variants.add(variant.substring(0, idx));
+                        idx = variant.lastIndexOf('_', --idx);
+                    }
+                }
+
+                List<Locale> list = new LinkedList<>();
+
+                if (variants != null) {
+                    for (String v : variants) {
+                        list.add(Locale.getInstance(language, script, region, v, null));
+                    }
+                }
+                if (region.length() > 0) {
+                    list.add(Locale.getInstance(language, script, region, "", null));
+                }
+                if (script.length() > 0) {
+                    list.add(Locale.getInstance(language, script, "", "", null));
+
+                    // With script, after truncating variant, region and script,
+                    // start over without script.
+                    if (variants != null) {
+                        for (String v : variants) {
+                            list.add(Locale.getInstance(language, "", region, v, null));
+                        }
+                    }
+                    if (region.length() > 0) {
+                        list.add(Locale.getInstance(language, "", region, "", null));
+                    }
+                }
+                if (language.length() > 0) {
+                    list.add(Locale.getInstance(language, "", "", "", null));
+                }
+                // Add root locale at the end
+                list.add(Locale.ROOT);
+
+                return list;
+            }
+        }
+
+        /**
+         * Returns a <code>Locale</code> to be used as a fallback locale for
+         * further resource bundle searches by the
+         * <code>ResourceBundle.getBundle</code> factory method. This method
+         * is called from the factory method every time when no resulting
+         * resource bundle has been found for <code>baseName</code> and
+         * <code>locale</code>, where locale is either the parameter for
+         * <code>ResourceBundle.getBundle</code> or the previous fallback
+         * locale returned by this method.
+         *
+         * <p>The method returns <code>null</code> if no further fallback
+         * search is desired.
+         *
+         * <p>The default implementation returns the {@linkplain
+         * Locale#getDefault() default <code>Locale</code>} if the given
+         * <code>locale</code> isn't the default one.  Otherwise,
+         * <code>null</code> is returned.
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully
+         *        qualified class name for which
+         *        <code>ResourceBundle.getBundle</code> has been
+         *        unable to find any resource bundles (except for the
+         *        base bundle)
+         * @param locale
+         *        the <code>Locale</code> for which
+         *        <code>ResourceBundle.getBundle</code> has been
+         *        unable to find any resource bundles (except for the
+         *        base bundle)
+         * @return a <code>Locale</code> for the fallback search,
+         *        or <code>null</code> if no further fallback search
+         *        is desired.
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code>
+         *        is <code>null</code>
+         */
+        public Locale getFallbackLocale(String baseName, Locale locale) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            Locale defaultLocale = Locale.getDefault();
+            return locale.equals(defaultLocale) ? null : defaultLocale;
+        }
+
+        /**
+         * Instantiates a resource bundle for the given bundle name of the
+         * given format and locale, using the given class loader if
+         * necessary. This method returns <code>null</code> if there is no
+         * resource bundle available for the given parameters. If a resource
+         * bundle can't be instantiated due to an unexpected error, the
+         * error must be reported by throwing an <code>Error</code> or
+         * <code>Exception</code> rather than simply returning
+         * <code>null</code>.
+         *
+         * <p>If the <code>reload</code> flag is <code>true</code>, it
+         * indicates that this method is being called because the previously
+         * loaded resource bundle has expired.
+         *
+         * <p>The default implementation instantiates a
+         * <code>ResourceBundle</code> as follows.
+         *
+         * <ul>
+         *
+         * <li>The bundle name is obtained by calling {@link
+         * #toBundleName(String, Locale) toBundleName(baseName,
+         * locale)}.</li>
+         *
+         * <li>If <code>format</code> is <code>"java.class"</code>, the
+         * {@link Class} specified by the bundle name is loaded by calling
+         * {@link ClassLoader#loadClass(String)}. Then, a
+         * <code>ResourceBundle</code> is instantiated by calling {@link
+         * Class#newInstance()}.  Note that the <code>reload</code> flag is
+         * ignored for loading class-based resource bundles in this default
+         * implementation.</li>
+         *
+         * <li>If <code>format</code> is <code>"java.properties"</code>,
+         * {@link #toResourceName(String, String) toResourceName(bundlename,
+         * "properties")} is called to get the resource name.
+         * If <code>reload</code> is <code>true</code>, {@link
+         * ClassLoader#getResource(String) load.getResource} is called
+         * to get a {@link URL} for creating a {@link
+         * URLConnection}. This <code>URLConnection</code> is used to
+         * {@linkplain URLConnection#setUseCaches(boolean) disable the
+         * caches} of the underlying resource loading layers,
+         * and to {@linkplain URLConnection#getInputStream() get an
+         * <code>InputStream</code>}.
+         * Otherwise, {@link ClassLoader#getResourceAsStream(String)
+         * loader.getResourceAsStream} is called to get an {@link
+         * InputStream}. Then, a {@link
+         * PropertyResourceBundle} is constructed with the
+         * <code>InputStream</code>.</li>
+         *
+         * <li>If <code>format</code> is neither <code>"java.class"</code>
+         * nor <code>"java.properties"</code>, an
+         * <code>IllegalArgumentException</code> is thrown.</li>
+         *
+         * </ul>
+         *
+         * @param baseName
+         *        the base bundle name of the resource bundle, a fully
+         *        qualified class name
+         * @param locale
+         *        the locale for which the resource bundle should be
+         *        instantiated
+         * @param format
+         *        the resource bundle format to be loaded
+         * @param loader
+         *        the <code>ClassLoader</code> to use to load the bundle
+         * @param reload
+         *        the flag to indicate bundle reloading; <code>true</code>
+         *        if reloading an expired resource bundle,
+         *        <code>false</code> otherwise
+         * @return the resource bundle instance,
+         *        or <code>null</code> if none could be found.
+         * @exception NullPointerException
+         *        if <code>bundleName</code>, <code>locale</code>,
+         *        <code>format</code>, or <code>loader</code> is
+         *        <code>null</code>, or if <code>null</code> is returned by
+         *        {@link #toBundleName(String, Locale) toBundleName}
+         * @exception IllegalArgumentException
+         *        if <code>format</code> is unknown, or if the resource
+         *        found for the given parameters contains malformed data.
+         * @exception ClassCastException
+         *        if the loaded class cannot be cast to <code>ResourceBundle</code>
+         * @exception IllegalAccessException
+         *        if the class or its nullary constructor is not
+         *        accessible.
+         * @exception InstantiationException
+         *        if the instantiation of a class fails for some other
+         *        reason.
+         * @exception ExceptionInInitializerError
+         *        if the initialization provoked by this method fails.
+         * @exception SecurityException
+         *        If a security manager is present and creation of new
+         *        instances is denied. See {@link Class#newInstance()}
+         *        for details.
+         * @exception IOException
+         *        if an error occurred when reading resources using
+         *        any I/O operations
+         */
+        public ResourceBundle newBundle(String baseName, Locale locale, String format,
+                                        ClassLoader loader, boolean reload)
+                    throws IllegalAccessException, InstantiationException, IOException {
+            String bundleName = toBundleName(baseName, locale);
+            ResourceBundle bundle = null;
+            if (format.equals("java.class")) {
+                try {
+                    @SuppressWarnings("unchecked")
+                    Class<? extends ResourceBundle> bundleClass
+                        = (Class<? extends ResourceBundle>)loader.loadClass(bundleName);
+
+                    // If the class isn't a ResourceBundle subclass, throw a
+                    // ClassCastException.
+                    if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
+                        bundle = bundleClass.newInstance();
+                    } else {
+                        throw new ClassCastException(bundleClass.getName()
+                                     + " cannot be cast to ResourceBundle");
+                    }
+                } catch (ClassNotFoundException e) {
+                }
+            } else if (format.equals("java.properties")) {
+                final String resourceName = toResourceName0(bundleName, "properties");
+                if (resourceName == null) {
+                    return bundle;
+                }
+                final ClassLoader classLoader = loader;
+                final boolean reloadFlag = reload;
+                InputStream stream = null;
+                try {
+                    stream = AccessController.doPrivileged(
+                        new PrivilegedExceptionAction<InputStream>() {
+                            public InputStream run() throws IOException {
+                                InputStream is = null;
+                                if (reloadFlag) {
+                                    URL url = classLoader.getResource(resourceName);
+                                    if (url != null) {
+                                        URLConnection connection = url.openConnection();
+                                        if (connection != null) {
+                                            // Disable caches to get fresh data for
+                                            // reloading.
+                                            connection.setUseCaches(false);
+                                            is = connection.getInputStream();
+                                        }
+                                    }
+                                } else {
+                                    is = classLoader.getResourceAsStream(resourceName);
+                                }
+                                return is;
+                            }
+                        });
+                } catch (PrivilegedActionException e) {
+                    throw (IOException) e.getException();
+                }
+                if (stream != null) {
+                    try {
+                        // Android-changed: Use UTF-8 for property based resources. b/26879578
+                        // bundle = new PropertyResourceBundle(stream);
+                        bundle = new PropertyResourceBundle(
+                                new InputStreamReader(stream, StandardCharsets.UTF_8));
+                    } finally {
+                        stream.close();
+                    }
+                }
+            } else {
+                throw new IllegalArgumentException("unknown format: " + format);
+            }
+            return bundle;
+        }
+
+        /**
+         * Returns the time-to-live (TTL) value for resource bundles that
+         * are loaded under this
+         * <code>ResourceBundle.Control</code>. Positive time-to-live values
+         * specify the number of milliseconds a bundle can remain in the
+         * cache without being validated against the source data from which
+         * it was constructed. The value 0 indicates that a bundle must be
+         * validated each time it is retrieved from the cache. {@link
+         * #TTL_DONT_CACHE} specifies that loaded resource bundles are not
+         * put in the cache. {@link #TTL_NO_EXPIRATION_CONTROL} specifies
+         * that loaded resource bundles are put in the cache with no
+         * expiration control.
+         *
+         * <p>The expiration affects only the bundle loading process by the
+         * <code>ResourceBundle.getBundle</code> factory method.  That is,
+         * if the factory method finds a resource bundle in the cache that
+         * has expired, the factory method calls the {@link
+         * #needsReload(String, Locale, String, ClassLoader, ResourceBundle,
+         * long) needsReload} method to determine whether the resource
+         * bundle needs to be reloaded. If <code>needsReload</code> returns
+         * <code>true</code>, the cached resource bundle instance is removed
+         * from the cache. Otherwise, the instance stays in the cache,
+         * updated with the new TTL value returned by this method.
+         *
+         * <p>All cached resource bundles are subject to removal from the
+         * cache due to memory constraints of the runtime environment.
+         * Returning a large positive value doesn't mean to lock loaded
+         * resource bundles in the cache.
+         *
+         * <p>The default implementation returns {@link #TTL_NO_EXPIRATION_CONTROL}.
+         *
+         * @param baseName
+         *        the base name of the resource bundle for which the
+         *        expiration value is specified.
+         * @param locale
+         *        the locale of the resource bundle for which the
+         *        expiration value is specified.
+         * @return the time (0 or a positive millisecond offset from the
+         *        cached time) to get loaded bundles expired in the cache,
+         *        {@link #TTL_NO_EXPIRATION_CONTROL} to disable the
+         *        expiration control, or {@link #TTL_DONT_CACHE} to disable
+         *        caching.
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code> is
+         *        <code>null</code>
+         */
+        public long getTimeToLive(String baseName, Locale locale) {
+            if (baseName == null || locale == null) {
+                throw new NullPointerException();
+            }
+            return TTL_NO_EXPIRATION_CONTROL;
+        }
+
+        /**
+         * Determines if the expired <code>bundle</code> in the cache needs
+         * to be reloaded based on the loading time given by
+         * <code>loadTime</code> or some other criteria. The method returns
+         * <code>true</code> if reloading is required; <code>false</code>
+         * otherwise. <code>loadTime</code> is a millisecond offset since
+         * the <a href="Calendar.html#Epoch"> <code>Calendar</code>
+         * Epoch</a>.
+         *
+         * The calling <code>ResourceBundle.getBundle</code> factory method
+         * calls this method on the <code>ResourceBundle.Control</code>
+         * instance used for its current invocation, not on the instance
+         * used in the invocation that originally loaded the resource
+         * bundle.
+         *
+         * <p>The default implementation compares <code>loadTime</code> and
+         * the last modified time of the source data of the resource
+         * bundle. If it's determined that the source data has been modified
+         * since <code>loadTime</code>, <code>true</code> is
+         * returned. Otherwise, <code>false</code> is returned. This
+         * implementation assumes that the given <code>format</code> is the
+         * same string as its file suffix if it's not one of the default
+         * formats, <code>"java.class"</code> or
+         * <code>"java.properties"</code>.
+         *
+         * @param baseName
+         *        the base bundle name of the resource bundle, a
+         *        fully qualified class name
+         * @param locale
+         *        the locale for which the resource bundle
+         *        should be instantiated
+         * @param format
+         *        the resource bundle format to be loaded
+         * @param loader
+         *        the <code>ClassLoader</code> to use to load the bundle
+         * @param bundle
+         *        the resource bundle instance that has been expired
+         *        in the cache
+         * @param loadTime
+         *        the time when <code>bundle</code> was loaded and put
+         *        in the cache
+         * @return <code>true</code> if the expired bundle needs to be
+         *        reloaded; <code>false</code> otherwise.
+         * @exception NullPointerException
+         *        if <code>baseName</code>, <code>locale</code>,
+         *        <code>format</code>, <code>loader</code>, or
+         *        <code>bundle</code> is <code>null</code>
+         */
+        public boolean needsReload(String baseName, Locale locale,
+                                   String format, ClassLoader loader,
+                                   ResourceBundle bundle, long loadTime) {
+            if (bundle == null) {
+                throw new NullPointerException();
+            }
+            if (format.equals("java.class") || format.equals("java.properties")) {
+                format = format.substring(5);
+            }
+            boolean result = false;
+            try {
+                String resourceName = toResourceName0(toBundleName(baseName, locale), format);
+                if (resourceName == null) {
+                    return result;
+                }
+                URL url = loader.getResource(resourceName);
+                if (url != null) {
+                    long lastModified = 0;
+                    URLConnection connection = url.openConnection();
+                    if (connection != null) {
+                        // disable caches to get the correct data
+                        connection.setUseCaches(false);
+                        if (connection instanceof JarURLConnection) {
+                            JarEntry ent = ((JarURLConnection)connection).getJarEntry();
+                            if (ent != null) {
+                                lastModified = ent.getTime();
+                                if (lastModified == -1) {
+                                    lastModified = 0;
+                                }
+                            }
+                        } else {
+                            lastModified = connection.getLastModified();
+                        }
+                    }
+                    result = lastModified >= loadTime;
+                }
+            } catch (NullPointerException npe) {
+                throw npe;
+            } catch (Exception e) {
+                // ignore other exceptions
+            }
+            return result;
+        }
+
+        /**
+         * Converts the given <code>baseName</code> and <code>locale</code>
+         * to the bundle name. This method is called from the default
+         * implementation of the {@link #newBundle(String, Locale, String,
+         * ClassLoader, boolean) newBundle} and {@link #needsReload(String,
+         * Locale, String, ClassLoader, ResourceBundle, long) needsReload}
+         * methods.
+         *
+         * <p>This implementation returns the following value:
+         * <pre>
+         *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
+         * </pre>
+         * where <code>language</code>, <code>script</code>, <code>country</code>,
+         * and <code>variant</code> are the language, script, country, and variant
+         * values of <code>locale</code>, respectively. Final component values that
+         * are empty Strings are omitted along with the preceding '_'.  When the
+         * script is empty, the script value is omitted along with the preceding '_'.
+         * If all of the values are empty strings, then <code>baseName</code>
+         * is returned.
+         *
+         * <p>For example, if <code>baseName</code> is
+         * <code>"baseName"</code> and <code>locale</code> is
+         * <code>Locale("ja",&nbsp;"",&nbsp;"XX")</code>, then
+         * <code>"baseName_ja_&thinsp;_XX"</code> is returned. If the given
+         * locale is <code>Locale("en")</code>, then
+         * <code>"baseName_en"</code> is returned.
+         *
+         * <p>Overriding this method allows applications to use different
+         * conventions in the organization and packaging of localized
+         * resources.
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully
+         *        qualified class name
+         * @param locale
+         *        the locale for which a resource bundle should be
+         *        loaded
+         * @return the bundle name for the resource bundle
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code>
+         *        is <code>null</code>
+         */
+        public String toBundleName(String baseName, Locale locale) {
+            if (locale == Locale.ROOT) {
+                return baseName;
+            }
+
+            String language = locale.getLanguage();
+            String script = locale.getScript();
+            String country = locale.getCountry();
+            String variant = locale.getVariant();
+
+            if (language == "" && country == "" && variant == "") {
+                return baseName;
+            }
+
+            StringBuilder sb = new StringBuilder(baseName);
+            sb.append('_');
+            if (script != "") {
+                if (variant != "") {
+                    sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant);
+                } else if (country != "") {
+                    sb.append(language).append('_').append(script).append('_').append(country);
+                } else {
+                    sb.append(language).append('_').append(script);
+                }
+            } else {
+                if (variant != "") {
+                    sb.append(language).append('_').append(country).append('_').append(variant);
+                } else if (country != "") {
+                    sb.append(language).append('_').append(country);
+                } else {
+                    sb.append(language);
+                }
+            }
+            return sb.toString();
+
+        }
+
+        /**
+         * Converts the given <code>bundleName</code> to the form required
+         * by the {@link ClassLoader#getResource ClassLoader.getResource}
+         * method by replacing all occurrences of <code>'.'</code> in
+         * <code>bundleName</code> with <code>'/'</code> and appending a
+         * <code>'.'</code> and the given file <code>suffix</code>. For
+         * example, if <code>bundleName</code> is
+         * <code>"foo.bar.MyResources_ja_JP"</code> and <code>suffix</code>
+         * is <code>"properties"</code>, then
+         * <code>"foo/bar/MyResources_ja_JP.properties"</code> is returned.
+         *
+         * @param bundleName
+         *        the bundle name
+         * @param suffix
+         *        the file type suffix
+         * @return the converted resource name
+         * @exception NullPointerException
+         *         if <code>bundleName</code> or <code>suffix</code>
+         *         is <code>null</code>
+         */
+        public final String toResourceName(String bundleName, String suffix) {
+            StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
+            sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
+            return sb.toString();
+        }
+
+        private String toResourceName0(String bundleName, String suffix) {
+            // application protocol check
+            if (bundleName.contains("://")) {
+                return null;
+            } else {
+                return toResourceName(bundleName, suffix);
+            }
+        }
+    }
+
+    private static class SingleFormatControl extends Control {
+        private static final Control PROPERTIES_ONLY
+            = new SingleFormatControl(FORMAT_PROPERTIES);
+
+        private static final Control CLASS_ONLY
+            = new SingleFormatControl(FORMAT_CLASS);
+
+        private final List<String> formats;
+
+        protected SingleFormatControl(List<String> formats) {
+            this.formats = formats;
+        }
+
+        public List<String> getFormats(String baseName) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            return formats;
+        }
+    }
+
+    private static final class NoFallbackControl extends SingleFormatControl {
+        private static final Control NO_FALLBACK
+            = new NoFallbackControl(FORMAT_DEFAULT);
+
+        private static final Control PROPERTIES_ONLY_NO_FALLBACK
+            = new NoFallbackControl(FORMAT_PROPERTIES);
+
+        private static final Control CLASS_ONLY_NO_FALLBACK
+            = new NoFallbackControl(FORMAT_CLASS);
+
+        protected NoFallbackControl(List<String> formats) {
+            super(formats);
+        }
+
+        public Locale getFallbackLocale(String baseName, Locale locale) {
+            if (baseName == null || locale == null) {
+                throw new NullPointerException();
+            }
+            return null;
+        }
+    }
+}
diff --git a/java/util/Scanner.java b/java/util/Scanner.java
new file mode 100644
index 0000000..15ad8e8
--- /dev/null
+++ b/java/util/Scanner.java
@@ -0,0 +1,2644 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.util.regex.*;
+import java.io.*;
+import java.math.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.nio.charset.*;
+import java.text.*;
+import java.util.Locale;
+
+import sun.misc.LRUCache;
+
+/**
+ * A simple text scanner which can parse primitive types and strings using
+ * regular expressions.
+ *
+ * <p>A <code>Scanner</code> breaks its input into tokens using a
+ * delimiter pattern, which by default matches whitespace. The resulting
+ * tokens may then be converted into values of different types using the
+ * various <tt>next</tt> methods.
+ *
+ * <p>For example, this code allows a user to read a number from
+ * <tt>System.in</tt>:
+ * <blockquote><pre>{@code
+ *     Scanner sc = new Scanner(System.in);
+ *     int i = sc.nextInt();
+ * }</pre></blockquote>
+ *
+ * <p>As another example, this code allows <code>long</code> types to be
+ * assigned from entries in a file <code>myNumbers</code>:
+ * <blockquote><pre>{@code
+ *      Scanner sc = new Scanner(new File("myNumbers"));
+ *      while (sc.hasNextLong()) {
+ *          long aLong = sc.nextLong();
+ *      }
+ * }</pre></blockquote>
+ *
+ * <p>The scanner can also use delimiters other than whitespace. This
+ * example reads several items in from a string:
+ * <blockquote><pre>{@code
+ *     String input = "1 fish 2 fish red fish blue fish";
+ *     Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*");
+ *     System.out.println(s.nextInt());
+ *     System.out.println(s.nextInt());
+ *     System.out.println(s.next());
+ *     System.out.println(s.next());
+ *     s.close();
+ * }</pre></blockquote>
+ * <p>
+ * prints the following output:
+ * <blockquote><pre>{@code
+ *     1
+ *     2
+ *     red
+ *     blue
+ * }</pre></blockquote>
+ *
+ * <p>The same output can be generated with this code, which uses a regular
+ * expression to parse all four tokens at once:
+ * <blockquote><pre>{@code
+ *     String input = "1 fish 2 fish red fish blue fish";
+ *     Scanner s = new Scanner(input);
+ *     s.findInLine("(\\d+) fish (\\d+) fish (\\w+) fish (\\w+)");
+ *     MatchResult result = s.match();
+ *     for (int i=1; i<=result.groupCount(); i++)
+ *         System.out.println(result.group(i));
+ *     s.close();
+ * }</pre></blockquote>
+ *
+ * <p>The <a name="default-delimiter">default whitespace delimiter</a> used
+ * by a scanner is as recognized by {@link java.lang.Character}.{@link
+ * java.lang.Character#isWhitespace(char) isWhitespace}. The {@link #reset}
+ * method will reset the value of the scanner's delimiter to the default
+ * whitespace delimiter regardless of whether it was previously changed.
+ *
+ * <p>A scanning operation may block waiting for input.
+ *
+ * <p>The {@link #next} and {@link #hasNext} methods and their
+ * primitive-type companion methods (such as {@link #nextInt} and
+ * {@link #hasNextInt}) first skip any input that matches the delimiter
+ * pattern, and then attempt to return the next token. Both <tt>hasNext</tt>
+ * and <tt>next</tt> methods may block waiting for further input.  Whether a
+ * <tt>hasNext</tt> method blocks has no connection to whether or not its
+ * associated <tt>next</tt> method will block.
+ *
+ * <p> The {@link #findInLine}, {@link #findWithinHorizon}, and {@link #skip}
+ * methods operate independently of the delimiter pattern. These methods will
+ * attempt to match the specified pattern with no regard to delimiters in the
+ * input and thus can be used in special circumstances where delimiters are
+ * not relevant. These methods may block waiting for more input.
+ *
+ * <p>When a scanner throws an {@link InputMismatchException}, the scanner
+ * will not pass the token that caused the exception, so that it may be
+ * retrieved or skipped via some other method.
+ *
+ * <p>Depending upon the type of delimiting pattern, empty tokens may be
+ * returned. For example, the pattern <tt>"\\s+"</tt> will return no empty
+ * tokens since it matches multiple instances of the delimiter. The delimiting
+ * pattern <tt>"\\s"</tt> could return empty tokens since it only passes one
+ * space at a time.
+ *
+ * <p> A scanner can read text from any object which implements the {@link
+ * java.lang.Readable} interface.  If an invocation of the underlying
+ * readable's {@link java.lang.Readable#read} method throws an {@link
+ * java.io.IOException} then the scanner assumes that the end of the input
+ * has been reached.  The most recent <tt>IOException</tt> thrown by the
+ * underlying readable can be retrieved via the {@link #ioException} method.
+ *
+ * <p>When a <code>Scanner</code> is closed, it will close its input source
+ * if the source implements the {@link java.io.Closeable} interface.
+ *
+ * <p>A <code>Scanner</code> is not safe for multithreaded use without
+ * external synchronization.
+ *
+ * <p>Unless otherwise mentioned, passing a <code>null</code> parameter into
+ * any method of a <code>Scanner</code> will cause a
+ * <code>NullPointerException</code> to be thrown.
+ *
+ * <p>A scanner will default to interpreting numbers as decimal unless a
+ * different radix has been set by using the {@link #useRadix} method. The
+ * {@link #reset} method will reset the value of the scanner's radix to
+ * <code>10</code> regardless of whether it was previously changed.
+ *
+ * <h3> <a name="localized-numbers">Localized numbers</a> </h3>
+ *
+ * <p> An instance of this class is capable of scanning numbers in the standard
+ * formats as well as in the formats of the scanner's locale. A scanner's
+ * <a name="initial-locale">initial locale </a>is the value returned by the {@link
+ * java.util.Locale#getDefault(Locale.Category)
+ * Locale.getDefault(Locale.Category.FORMAT)} method; it may be changed via the {@link
+ * #useLocale} method. The {@link #reset} method will reset the value of the
+ * scanner's locale to the initial locale regardless of whether it was
+ * previously changed.
+ *
+ * <p>The localized formats are defined in terms of the following parameters,
+ * which for a particular locale are taken from that locale's {@link
+ * java.text.DecimalFormat DecimalFormat} object, <tt>df</tt>, and its and
+ * {@link java.text.DecimalFormatSymbols DecimalFormatSymbols} object,
+ * <tt>dfs</tt>.
+ *
+ * <blockquote><dl>
+ *     <dt><i>LocalGroupSeparator&nbsp;&nbsp;</i>
+ *         <dd>The character used to separate thousands groups,
+ *         <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
+ *         java.text.DecimalFormatSymbols#getGroupingSeparator
+ *         getGroupingSeparator()}
+ *     <dt><i>LocalDecimalSeparator&nbsp;&nbsp;</i>
+ *         <dd>The character used for the decimal point,
+ *     <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
+ *     java.text.DecimalFormatSymbols#getDecimalSeparator
+ *     getDecimalSeparator()}
+ *     <dt><i>LocalPositivePrefix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears before a positive number (may
+ *         be empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
+ *         java.text.DecimalFormat#getPositivePrefix
+ *         getPositivePrefix()}
+ *     <dt><i>LocalPositiveSuffix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears after a positive number (may be
+ *         empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
+ *         java.text.DecimalFormat#getPositiveSuffix
+ *         getPositiveSuffix()}
+ *     <dt><i>LocalNegativePrefix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears before a negative number (may
+ *         be empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
+ *         java.text.DecimalFormat#getNegativePrefix
+ *         getNegativePrefix()}
+ *     <dt><i>LocalNegativeSuffix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears after a negative number (may be
+ *         empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
+ *     java.text.DecimalFormat#getNegativeSuffix
+ *     getNegativeSuffix()}
+ *     <dt><i>LocalNaN&nbsp;&nbsp;</i>
+ *         <dd>The string that represents not-a-number for
+ *         floating-point values,
+ *         <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
+ *         java.text.DecimalFormatSymbols#getNaN
+ *         getNaN()}
+ *     <dt><i>LocalInfinity&nbsp;&nbsp;</i>
+ *         <dd>The string that represents infinity for floating-point
+ *         values, <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
+ *         java.text.DecimalFormatSymbols#getInfinity
+ *         getInfinity()}
+ * </dl></blockquote>
+ *
+ * <h4> <a name="number-syntax">Number syntax</a> </h4>
+ *
+ * <p> The strings that can be parsed as numbers by an instance of this class
+ * are specified in terms of the following regular-expression grammar, where
+ * Rmax is the highest digit in the radix being used (for example, Rmax is 9 in base 10).
+ *
+ * <dl>
+ *   <dt><i>NonAsciiDigit</i>:
+ *       <dd>A non-ASCII character c for which
+ *            {@link java.lang.Character#isDigit Character.isDigit}<tt>(c)</tt>
+ *                        returns&nbsp;true
+ *
+ *   <dt><i>Non0Digit</i>:
+ *       <dd><tt>[1-</tt><i>Rmax</i><tt>] | </tt><i>NonASCIIDigit</i>
+ *
+ *   <dt><i>Digit</i>:
+ *       <dd><tt>[0-</tt><i>Rmax</i><tt>] | </tt><i>NonASCIIDigit</i>
+ *
+ *   <dt><i>GroupedNumeral</i>:
+ *       <dd><tt>(&nbsp;</tt><i>Non0Digit</i>
+ *                   <i>Digit</i><tt>?
+ *                   </tt><i>Digit</i><tt>?</tt>
+ *       <dd>&nbsp;&nbsp;&nbsp;&nbsp;<tt>(&nbsp;</tt><i>LocalGroupSeparator</i>
+ *                         <i>Digit</i>
+ *                         <i>Digit</i>
+ *                         <i>Digit</i><tt> )+ )</tt>
+ *
+ *   <dt><i>Numeral</i>:
+ *       <dd><tt>( ( </tt><i>Digit</i><tt>+ )
+ *               | </tt><i>GroupedNumeral</i><tt> )</tt>
+ *
+ *   <dt><a name="Integer-regex"><i>Integer</i>:</a>
+ *       <dd><tt>( [-+]? ( </tt><i>Numeral</i><tt>
+ *                               ) )</tt>
+ *       <dd><tt>| </tt><i>LocalPositivePrefix</i> <i>Numeral</i>
+ *                      <i>LocalPositiveSuffix</i>
+ *       <dd><tt>| </tt><i>LocalNegativePrefix</i> <i>Numeral</i>
+ *                 <i>LocalNegativeSuffix</i>
+ *
+ *   <dt><i>DecimalNumeral</i>:
+ *       <dd><i>Numeral</i>
+ *       <dd><tt>| </tt><i>Numeral</i>
+ *                 <i>LocalDecimalSeparator</i>
+ *                 <i>Digit</i><tt>*</tt>
+ *       <dd><tt>| </tt><i>LocalDecimalSeparator</i>
+ *                 <i>Digit</i><tt>+</tt>
+ *
+ *   <dt><i>Exponent</i>:
+ *       <dd><tt>( [eE] [+-]? </tt><i>Digit</i><tt>+ )</tt>
+ *
+ *   <dt><a name="Decimal-regex"><i>Decimal</i>:</a>
+ *       <dd><tt>( [-+]? </tt><i>DecimalNumeral</i>
+ *                         <i>Exponent</i><tt>? )</tt>
+ *       <dd><tt>| </tt><i>LocalPositivePrefix</i>
+ *                 <i>DecimalNumeral</i>
+ *                 <i>LocalPositiveSuffix</i>
+ *                 <i>Exponent</i><tt>?</tt>
+ *       <dd><tt>| </tt><i>LocalNegativePrefix</i>
+ *                 <i>DecimalNumeral</i>
+ *                 <i>LocalNegativeSuffix</i>
+ *                 <i>Exponent</i><tt>?</tt>
+ *
+ *   <dt><i>HexFloat</i>:
+ *       <dd><tt>[-+]? 0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+
+ *                 ([pP][-+]?[0-9]+)?</tt>
+ *
+ *   <dt><i>NonNumber</i>:
+ *       <dd><tt>NaN
+ *                          | </tt><i>LocalNan</i><tt>
+ *                          | Infinity
+ *                          | </tt><i>LocalInfinity</i>
+ *
+ *   <dt><i>SignedNonNumber</i>:
+ *       <dd><tt>( [-+]? </tt><i>NonNumber</i><tt> )</tt>
+ *       <dd><tt>| </tt><i>LocalPositivePrefix</i>
+ *                 <i>NonNumber</i>
+ *                 <i>LocalPositiveSuffix</i>
+ *       <dd><tt>| </tt><i>LocalNegativePrefix</i>
+ *                 <i>NonNumber</i>
+ *                 <i>LocalNegativeSuffix</i>
+ *
+ *   <dt><a name="Float-regex"><i>Float</i></a>:
+ *       <dd><i>Decimal</i>
+ *           <tt>| </tt><i>HexFloat</i>
+ *           <tt>| </tt><i>SignedNonNumber</i>
+ *
+ * </dl>
+ * <p>Whitespace is not significant in the above regular expressions.
+ *
+ * @since   1.5
+ */
+public final class Scanner implements Iterator<String>, Closeable {
+
+    // Internal buffer used to hold input
+    private CharBuffer buf;
+
+    // Size of internal character buffer
+    private static final int BUFFER_SIZE = 1024; // change to 1024;
+
+    // The index into the buffer currently held by the Scanner
+    private int position;
+
+    // Internal matcher used for finding delimiters
+    private Matcher matcher;
+
+    // Pattern used to delimit tokens
+    private Pattern delimPattern;
+
+    // Pattern found in last hasNext operation
+    private Pattern hasNextPattern;
+
+    // Position after last hasNext operation
+    private int hasNextPosition;
+
+    // Result after last hasNext operation
+    private String hasNextResult;
+
+    // The input source
+    private Readable source;
+
+    // Boolean is true if source is done
+    private boolean sourceClosed = false;
+
+    // Boolean indicating more input is required
+    private boolean needInput = false;
+
+    // Boolean indicating if a delim has been skipped this operation
+    private boolean skipped = false;
+
+    // A store of a position that the scanner may fall back to
+    private int savedScannerPosition = -1;
+
+    // A cache of the last primitive type scanned
+    private Object typeCache = null;
+
+    // Boolean indicating if a match result is available
+    private boolean matchValid = false;
+
+    // Boolean indicating if this scanner has been closed
+    private boolean closed = false;
+
+    // The current radix used by this scanner
+    private int radix = 10;
+
+    // The default radix for this scanner
+    private int defaultRadix = 10;
+
+    // The locale used by this scanner
+    private Locale locale = null;
+
+    // A cache of the last few recently used Patterns
+    private LRUCache<String,Pattern> patternCache =
+    new LRUCache<String,Pattern>(7) {
+        protected Pattern create(String s) {
+            return Pattern.compile(s);
+        }
+        protected boolean hasName(Pattern p, String s) {
+            return p.pattern().equals(s);
+        }
+    };
+
+    // A holder of the last IOException encountered
+    private IOException lastException;
+
+    // A pattern for java whitespace
+    private static Pattern WHITESPACE_PATTERN = Pattern.compile(
+                                                "\\p{javaWhitespace}+");
+
+    // A pattern for any token
+    private static Pattern FIND_ANY_PATTERN = Pattern.compile("(?s).*");
+
+    // A pattern for non-ASCII digits
+    private static Pattern NON_ASCII_DIGIT = Pattern.compile(
+        "[\\p{javaDigit}&&[^0-9]]");
+
+    // Fields and methods to support scanning primitive types
+
+    /**
+     * Locale dependent values used to scan numbers
+     */
+    private String groupSeparator = "\\,";
+    private String decimalSeparator = "\\.";
+    private String nanString = "NaN";
+    private String infinityString = "Infinity";
+    private String positivePrefix = "";
+    private String negativePrefix = "\\-";
+    private String positiveSuffix = "";
+    private String negativeSuffix = "";
+
+    /**
+     * Fields and an accessor method to match booleans
+     */
+    private static volatile Pattern boolPattern;
+    private static final String BOOLEAN_PATTERN = "true|false";
+    private static Pattern boolPattern() {
+        Pattern bp = boolPattern;
+        if (bp == null)
+            boolPattern = bp = Pattern.compile(BOOLEAN_PATTERN,
+                                          Pattern.CASE_INSENSITIVE);
+        return bp;
+    }
+
+    /**
+     * Fields and methods to match bytes, shorts, ints, and longs
+     */
+    private Pattern integerPattern;
+    private String digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+    private String non0Digit = "[\\p{javaDigit}&&[^0]]";
+    private int SIMPLE_GROUP_INDEX = 5;
+    private String buildIntegerPatternString() {
+        String radixDigits = digits.substring(0, radix);
+        // \\p{javaDigit} is not guaranteed to be appropriate
+        // here but what can we do? The final authority will be
+        // whatever parse method is invoked, so ultimately the
+        // Scanner will do the right thing
+        String digit = "((?i)["+radixDigits+"]|\\p{javaDigit})";
+        // BEGIN Android-changed: Support non-decimal starting digits.
+        // Ie., in addition to 1-9, a-z are also valid radix digits.
+        /*
+        String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
+                                groupSeparator+digit+digit+digit+")+)";
+        */
+        String non0RadixDigits = "((?i)[" + digits.substring(1, radix) + "]|(" + non0Digit + "))";
+        String groupedNumeral = "("+non0RadixDigits+digit+"?"+digit+"?("+
+                                groupSeparator+digit+digit+digit+")+)";
+        // END Android-changed: Support non-decimal starting digits.
+        // digit++ is the possessive form which is necessary for reducing
+        // backtracking that would otherwise cause unacceptable performance
+        String numeral = "(("+ digit+"++)|"+groupedNumeral+")";
+        String javaStyleInteger = "([-+]?(" + numeral + "))";
+        String negativeInteger = negativePrefix + numeral + negativeSuffix;
+        String positiveInteger = positivePrefix + numeral + positiveSuffix;
+        return "("+ javaStyleInteger + ")|(" +
+            positiveInteger + ")|(" +
+            negativeInteger + ")";
+    }
+    private Pattern integerPattern() {
+        if (integerPattern == null) {
+            integerPattern = patternCache.forName(buildIntegerPatternString());
+        }
+        return integerPattern;
+    }
+
+    /**
+     * Fields and an accessor method to match line separators
+     */
+    private static volatile Pattern separatorPattern;
+    private static volatile Pattern linePattern;
+    private static final String LINE_SEPARATOR_PATTERN =
+                                           "\r\n|[\n\r\u2028\u2029\u0085]";
+    private static final String LINE_PATTERN = ".*("+LINE_SEPARATOR_PATTERN+")|.+$";
+
+    private static Pattern separatorPattern() {
+        Pattern sp = separatorPattern;
+        if (sp == null)
+            separatorPattern = sp = Pattern.compile(LINE_SEPARATOR_PATTERN);
+        return sp;
+    }
+
+    private static Pattern linePattern() {
+        Pattern lp = linePattern;
+        if (lp == null)
+            linePattern = lp = Pattern.compile(LINE_PATTERN);
+        return lp;
+    }
+
+    /**
+     * Fields and methods to match floats and doubles
+     */
+    private Pattern floatPattern;
+    private Pattern decimalPattern;
+    private void buildFloatAndDecimalPattern() {
+        // \\p{javaDigit} may not be perfect, see above
+        String digit = "([0-9]|(\\p{javaDigit}))";
+        String exponent = "([eE][+-]?"+digit+"+)?";
+        String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
+                                groupSeparator+digit+digit+digit+")+)";
+        // Once again digit++ is used for performance, as above
+        String numeral = "(("+digit+"++)|"+groupedNumeral+")";
+        String decimalNumeral = "("+numeral+"|"+numeral +
+            decimalSeparator + digit + "*+|"+ decimalSeparator +
+            digit + "++)";
+        String nonNumber = "(NaN|"+nanString+"|Infinity|"+
+                               infinityString+")";
+        String positiveFloat = "(" + positivePrefix + decimalNumeral +
+                            positiveSuffix + exponent + ")";
+        String negativeFloat = "(" + negativePrefix + decimalNumeral +
+                            negativeSuffix + exponent + ")";
+        String decimal = "(([-+]?" + decimalNumeral + exponent + ")|"+
+            positiveFloat + "|" + negativeFloat + ")";
+        String hexFloat =
+            "[-+]?0[xX][0-9a-fA-F]*\\.[0-9a-fA-F]+([pP][-+]?[0-9]+)?";
+        String positiveNonNumber = "(" + positivePrefix + nonNumber +
+                            positiveSuffix + ")";
+        String negativeNonNumber = "(" + negativePrefix + nonNumber +
+                            negativeSuffix + ")";
+        String signedNonNumber = "(([-+]?"+nonNumber+")|" +
+                                 positiveNonNumber + "|" +
+                                 negativeNonNumber + ")";
+        floatPattern = Pattern.compile(decimal + "|" + hexFloat + "|" +
+                                       signedNonNumber);
+        decimalPattern = Pattern.compile(decimal);
+    }
+    private Pattern floatPattern() {
+        if (floatPattern == null) {
+            buildFloatAndDecimalPattern();
+        }
+        return floatPattern;
+    }
+    private Pattern decimalPattern() {
+        if (decimalPattern == null) {
+            buildFloatAndDecimalPattern();
+        }
+        return decimalPattern;
+    }
+
+    // Constructors
+
+    /**
+     * Constructs a <code>Scanner</code> that returns values scanned
+     * from the specified source delimited by the specified pattern.
+     *
+     * @param source A character source implementing the Readable interface
+     * @param pattern A delimiting pattern
+     */
+    private Scanner(Readable source, Pattern pattern) {
+        assert source != null : "source should not be null";
+        assert pattern != null : "pattern should not be null";
+        this.source = source;
+        delimPattern = pattern;
+        buf = CharBuffer.allocate(BUFFER_SIZE);
+        buf.limit(0);
+        matcher = delimPattern.matcher(buf);
+        matcher.useTransparentBounds(true);
+        matcher.useAnchoringBounds(false);
+        useLocale(Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified source.
+     *
+     * @param  source A character source implementing the {@link Readable}
+     *         interface
+     */
+    public Scanner(Readable source) {
+        this(Objects.requireNonNull(source, "source"), WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified input stream. Bytes from the stream are converted
+     * into characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param  source An input stream to be scanned
+     */
+    public Scanner(InputStream source) {
+        this(new InputStreamReader(source), WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified input stream. Bytes from the stream are converted
+     * into characters using the specified charset.
+     *
+     * @param  source An input stream to be scanned
+     * @param charsetName The encoding type used to convert bytes from the
+     *        stream into characters to be scanned
+     * @throws IllegalArgumentException if the specified character set
+     *         does not exist
+     */
+    public Scanner(InputStream source, String charsetName) {
+        this(makeReadable(Objects.requireNonNull(source, "source"), toCharset(charsetName)),
+             WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Returns a charset object for the given charset name.
+     * @throws NullPointerException          is csn is null
+     * @throws IllegalArgumentException      if the charset is not supported
+     */
+    private static Charset toCharset(String csn) {
+        Objects.requireNonNull(csn, "charsetName");
+        try {
+            return Charset.forName(csn);
+        } catch (IllegalCharsetNameException|UnsupportedCharsetException e) {
+            // IllegalArgumentException should be thrown
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    private static Readable makeReadable(InputStream source, Charset charset) {
+        return new InputStreamReader(source, charset);
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param  source A file to be scanned
+     * @throws FileNotFoundException if source is not found
+     */
+    public Scanner(File source) throws FileNotFoundException {
+        this((ReadableByteChannel)(new FileInputStream(source).getChannel()));
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the specified charset.
+     *
+     * @param  source A file to be scanned
+     * @param charsetName The encoding type used to convert bytes from the file
+     *        into characters to be scanned
+     * @throws FileNotFoundException if source is not found
+     * @throws IllegalArgumentException if the specified encoding is
+     *         not found
+     */
+    public Scanner(File source, String charsetName)
+        throws FileNotFoundException
+    {
+        this(Objects.requireNonNull(source), toDecoder(charsetName));
+    }
+
+    private Scanner(File source, CharsetDecoder dec)
+        throws FileNotFoundException
+    {
+        this(makeReadable((ReadableByteChannel)(new FileInputStream(source).getChannel()), dec));
+    }
+
+    private static CharsetDecoder toDecoder(String charsetName) {
+        // Android-changed: Throw an IAE instead of an NPE.
+        // Objects.requireNonNull(charsetName, "charsetName");
+        if (charsetName == null) {
+            throw new IllegalArgumentException("charsetName == null");
+        }
+        try {
+            return Charset.forName(charsetName).newDecoder();
+        } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
+            throw new IllegalArgumentException(charsetName);
+        }
+    }
+
+    private static Readable makeReadable(ReadableByteChannel source,
+                                         CharsetDecoder dec) {
+        return Channels.newReader(source, dec, -1);
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param   source
+     *          the path to the file to be scanned
+     * @throws  IOException
+     *          if an I/O error occurs opening source
+     *
+     * @since   1.7
+     */
+    public Scanner(Path source)
+        throws IOException
+    {
+        this(Files.newInputStream(source));
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the specified charset.
+     *
+     * @param   source
+     *          the path to the file to be scanned
+     * @param   charsetName
+     *          The encoding type used to convert bytes from the file
+     *          into characters to be scanned
+     * @throws  IOException
+     *          if an I/O error occurs opening source
+     * @throws  IllegalArgumentException
+     *          if the specified encoding is not found
+     * @since   1.7
+     */
+    public Scanner(Path source, String charsetName) throws IOException {
+        this(Objects.requireNonNull(source), toCharset(charsetName));
+    }
+
+    private Scanner(Path source, Charset charset)  throws IOException {
+        this(makeReadable(Files.newInputStream(source), charset));
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified string.
+     *
+     * @param  source A string to scan
+     */
+    public Scanner(String source) {
+        this(new StringReader(source), WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified channel. Bytes from the source are converted into
+     * characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param  source A channel to scan
+     */
+    public Scanner(ReadableByteChannel source) {
+        this(makeReadable(Objects.requireNonNull(source, "source")),
+             WHITESPACE_PATTERN);
+    }
+
+    private static Readable makeReadable(ReadableByteChannel source) {
+        return makeReadable(source, Charset.defaultCharset().newDecoder());
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified channel. Bytes from the source are converted into
+     * characters using the specified charset.
+     *
+     * @param  source A channel to scan
+     * @param charsetName The encoding type used to convert bytes from the
+     *        channel into characters to be scanned
+     * @throws IllegalArgumentException if the specified character set
+     *         does not exist
+     */
+    public Scanner(ReadableByteChannel source, String charsetName) {
+        this(makeReadable(Objects.requireNonNull(source, "source"), toDecoder(charsetName)),
+             WHITESPACE_PATTERN);
+    }
+
+    // Private primitives used to support scanning
+
+    private void saveState() {
+        savedScannerPosition = position;
+    }
+
+    private void revertState() {
+        this.position = savedScannerPosition;
+        savedScannerPosition = -1;
+        skipped = false;
+    }
+
+    private boolean revertState(boolean b) {
+        this.position = savedScannerPosition;
+        savedScannerPosition = -1;
+        skipped = false;
+        return b;
+    }
+
+    private void cacheResult() {
+        hasNextResult = matcher.group();
+        hasNextPosition = matcher.end();
+        hasNextPattern = matcher.pattern();
+    }
+
+    private void cacheResult(String result) {
+        hasNextResult = result;
+        hasNextPosition = matcher.end();
+        hasNextPattern = matcher.pattern();
+    }
+
+    // Clears both regular cache and type cache
+    private void clearCaches() {
+        hasNextPattern = null;
+        typeCache = null;
+    }
+
+    // Also clears both the regular cache and the type cache
+    private String getCachedResult() {
+        position = hasNextPosition;
+        hasNextPattern = null;
+        typeCache = null;
+        return hasNextResult;
+    }
+
+    // Also clears both the regular cache and the type cache
+    private void useTypeCache() {
+        if (closed)
+            throw new IllegalStateException("Scanner closed");
+        position = hasNextPosition;
+        hasNextPattern = null;
+        typeCache = null;
+    }
+
+    // Tries to read more input. May block.
+    private void readInput() {
+        if (buf.limit() == buf.capacity())
+            makeSpace();
+
+        // Prepare to receive data
+        int p = buf.position();
+        buf.position(buf.limit());
+        buf.limit(buf.capacity());
+
+        int n = 0;
+        try {
+            n = source.read(buf);
+        } catch (IOException ioe) {
+            lastException = ioe;
+            n = -1;
+        }
+
+        if (n == -1) {
+            sourceClosed = true;
+            needInput = false;
+        }
+
+        if (n > 0)
+            needInput = false;
+
+        // Restore current position and limit for reading
+        buf.limit(buf.position());
+        buf.position(p);
+        // Android-added: reset() the matcher after reading.
+        // The matcher implementation eagerly calls toString() so we'll have
+        // to update its input whenever the buffer limit, position etc. changes.
+        matcher.reset(buf);
+    }
+
+    // After this method is called there will either be an exception
+    // or else there will be space in the buffer
+    private boolean makeSpace() {
+        clearCaches();
+        int offset = savedScannerPosition == -1 ?
+            position : savedScannerPosition;
+        buf.position(offset);
+        // Gain space by compacting buffer
+        if (offset > 0) {
+            buf.compact();
+            translateSavedIndexes(offset);
+            position -= offset;
+            buf.flip();
+            return true;
+        }
+        // Gain space by growing buffer
+        int newSize = buf.capacity() * 2;
+        CharBuffer newBuf = CharBuffer.allocate(newSize);
+        newBuf.put(buf);
+        newBuf.flip();
+        translateSavedIndexes(offset);
+        position -= offset;
+        buf = newBuf;
+        matcher.reset(buf);
+        return true;
+    }
+
+    // When a buffer compaction/reallocation occurs the saved indexes must
+    // be modified appropriately
+    private void translateSavedIndexes(int offset) {
+        if (savedScannerPosition != -1)
+            savedScannerPosition -= offset;
+    }
+
+    // If we are at the end of input then NoSuchElement;
+    // If there is still input left then InputMismatch
+    private void throwFor() {
+        skipped = false;
+        if ((sourceClosed) && (position == buf.limit()))
+            throw new NoSuchElementException();
+        else
+            throw new InputMismatchException();
+    }
+
+    // Returns true if a complete token or partial token is in the buffer.
+    // It is not necessary to find a complete token since a partial token
+    // means that there will be another token with or without more input.
+    private boolean hasTokenInBuffer() {
+        matchValid = false;
+        matcher.usePattern(delimPattern);
+        matcher.region(position, buf.limit());
+
+        // Skip delims first
+        if (matcher.lookingAt())
+            position = matcher.end();
+
+        // If we are sitting at the end, no more tokens in buffer
+        if (position == buf.limit())
+            return false;
+
+        return true;
+    }
+
+    /*
+     * Returns a "complete token" that matches the specified pattern
+     *
+     * A token is complete if surrounded by delims; a partial token
+     * is prefixed by delims but not postfixed by them
+     *
+     * The position is advanced to the end of that complete token
+     *
+     * Pattern == null means accept any token at all
+     *
+     * Triple return:
+     * 1. valid string means it was found
+     * 2. null with needInput=false means we won't ever find it
+     * 3. null with needInput=true means try again after readInput
+     */
+    private String getCompleteTokenInBuffer(Pattern pattern) {
+        matchValid = false;
+
+        // Skip delims first
+        matcher.usePattern(delimPattern);
+        if (!skipped) { // Enforcing only one skip of leading delims
+            matcher.region(position, buf.limit());
+            if (matcher.lookingAt()) {
+                // If more input could extend the delimiters then we must wait
+                // for more input
+                if (matcher.hitEnd() && !sourceClosed) {
+                    needInput = true;
+                    return null;
+                }
+                // The delims were whole and the matcher should skip them
+                skipped = true;
+                position = matcher.end();
+            }
+        }
+
+        // If we are sitting at the end, no more tokens in buffer
+        if (position == buf.limit()) {
+            if (sourceClosed)
+                return null;
+            needInput = true;
+            return null;
+        }
+
+        // Must look for next delims. Simply attempting to match the
+        // pattern at this point may find a match but it might not be
+        // the first longest match because of missing input, or it might
+        // match a partial token instead of the whole thing.
+
+        // Then look for next delims
+        matcher.region(position, buf.limit());
+        boolean foundNextDelim = matcher.find();
+        if (foundNextDelim && (matcher.end() == position)) {
+            // Zero length delimiter match; we should find the next one
+            // using the automatic advance past a zero length match;
+            // Otherwise we have just found the same one we just skipped
+            foundNextDelim = matcher.find();
+        }
+        if (foundNextDelim) {
+            // In the rare case that more input could cause the match
+            // to be lost and there is more input coming we must wait
+            // for more input. Note that hitting the end is okay as long
+            // as the match cannot go away. It is the beginning of the
+            // next delims we want to be sure about, we don't care if
+            // they potentially extend further.
+            if (matcher.requireEnd() && !sourceClosed) {
+                needInput = true;
+                return null;
+            }
+            int tokenEnd = matcher.start();
+            // There is a complete token.
+            if (pattern == null) {
+                // Must continue with match to provide valid MatchResult
+                pattern = FIND_ANY_PATTERN;
+            }
+            //  Attempt to match against the desired pattern
+            matcher.usePattern(pattern);
+            matcher.region(position, tokenEnd);
+            if (matcher.matches()) {
+                String s = matcher.group();
+                position = matcher.end();
+                return s;
+            } else { // Complete token but it does not match
+                return null;
+            }
+        }
+
+        // If we can't find the next delims but no more input is coming,
+        // then we can treat the remainder as a whole token
+        if (sourceClosed) {
+            if (pattern == null) {
+                // Must continue with match to provide valid MatchResult
+                pattern = FIND_ANY_PATTERN;
+            }
+            // Last token; Match the pattern here or throw
+            matcher.usePattern(pattern);
+            matcher.region(position, buf.limit());
+            if (matcher.matches()) {
+                String s = matcher.group();
+                position = matcher.end();
+                return s;
+            }
+            // Last piece does not match
+            return null;
+        }
+
+        // There is a partial token in the buffer; must read more
+        // to complete it
+        needInput = true;
+        return null;
+    }
+
+    // Finds the specified pattern in the buffer up to horizon.
+    // Returns a match for the specified input pattern.
+    private String findPatternInBuffer(Pattern pattern, int horizon) {
+        matchValid = false;
+        matcher.usePattern(pattern);
+        int bufferLimit = buf.limit();
+        int horizonLimit = -1;
+        int searchLimit = bufferLimit;
+        if (horizon > 0) {
+            horizonLimit = position + horizon;
+            if (horizonLimit < bufferLimit)
+                searchLimit = horizonLimit;
+        }
+        matcher.region(position, searchLimit);
+        if (matcher.find()) {
+            if (matcher.hitEnd() && (!sourceClosed)) {
+                // The match may be longer if didn't hit horizon or real end
+                if (searchLimit != horizonLimit) {
+                     // Hit an artificial end; try to extend the match
+                    needInput = true;
+                    return null;
+                }
+                // The match could go away depending on what is next
+                if ((searchLimit == horizonLimit) && matcher.requireEnd()) {
+                    // Rare case: we hit the end of input and it happens
+                    // that it is at the horizon and the end of input is
+                    // required for the match.
+                    needInput = true;
+                    return null;
+                }
+            }
+            // Did not hit end, or hit real end, or hit horizon
+            position = matcher.end();
+            return matcher.group();
+        }
+
+        if (sourceClosed)
+            return null;
+
+        // If there is no specified horizon, or if we have not searched
+        // to the specified horizon yet, get more input
+        if ((horizon == 0) || (searchLimit != horizonLimit))
+            needInput = true;
+        return null;
+    }
+
+    // Returns a match for the specified input pattern anchored at
+    // the current position
+    private String matchPatternInBuffer(Pattern pattern) {
+        matchValid = false;
+        matcher.usePattern(pattern);
+        matcher.region(position, buf.limit());
+        if (matcher.lookingAt()) {
+            if (matcher.hitEnd() && (!sourceClosed)) {
+                // Get more input and try again
+                needInput = true;
+                return null;
+            }
+            position = matcher.end();
+            return matcher.group();
+        }
+
+        if (sourceClosed)
+            return null;
+
+        // Read more to find pattern
+        needInput = true;
+        return null;
+    }
+
+    // Throws if the scanner is closed
+    private void ensureOpen() {
+        if (closed)
+            throw new IllegalStateException("Scanner closed");
+    }
+
+    // Public methods
+
+    /**
+     * Closes this scanner.
+     *
+     * <p> If this scanner has not yet been closed then if its underlying
+     * {@linkplain java.lang.Readable readable} also implements the {@link
+     * java.io.Closeable} interface then the readable's <tt>close</tt> method
+     * will be invoked.  If this scanner is already closed then invoking this
+     * method will have no effect.
+     *
+     * <p>Attempting to perform search operations after a scanner has
+     * been closed will result in an {@link IllegalStateException}.
+     *
+     */
+    public void close() {
+        if (closed)
+            return;
+        if (source instanceof Closeable) {
+            try {
+                ((Closeable)source).close();
+            } catch (IOException ioe) {
+                lastException = ioe;
+            }
+        }
+        sourceClosed = true;
+        source = null;
+        closed = true;
+    }
+
+    /**
+     * Returns the <code>IOException</code> last thrown by this
+     * <code>Scanner</code>'s underlying <code>Readable</code>. This method
+     * returns <code>null</code> if no such exception exists.
+     *
+     * @return the last exception thrown by this scanner's readable
+     */
+    public IOException ioException() {
+        return lastException;
+    }
+
+    /**
+     * Returns the <code>Pattern</code> this <code>Scanner</code> is currently
+     * using to match delimiters.
+     *
+     * @return this scanner's delimiting pattern.
+     */
+    public Pattern delimiter() {
+        return delimPattern;
+    }
+
+    /**
+     * Sets this scanner's delimiting pattern to the specified pattern.
+     *
+     * @param pattern A delimiting pattern
+     * @return this scanner
+     */
+    public Scanner useDelimiter(Pattern pattern) {
+        delimPattern = pattern;
+        return this;
+    }
+
+    /**
+     * Sets this scanner's delimiting pattern to a pattern constructed from
+     * the specified <code>String</code>.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>useDelimiter(pattern)</tt> behaves in exactly the same way as the
+     * invocation <tt>useDelimiter(Pattern.compile(pattern))</tt>.
+     *
+     * <p> Invoking the {@link #reset} method will set the scanner's delimiter
+     * to the <a href= "#default-delimiter">default</a>.
+     *
+     * @param pattern A string specifying a delimiting pattern
+     * @return this scanner
+     */
+    public Scanner useDelimiter(String pattern) {
+        delimPattern = patternCache.forName(pattern);
+        return this;
+    }
+
+    /**
+     * Returns this scanner's locale.
+     *
+     * <p>A scanner's locale affects many elements of its default
+     * primitive matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * @return this scanner's locale
+     */
+    public Locale locale() {
+        return this.locale;
+    }
+
+    /**
+     * Sets this scanner's locale to the specified locale.
+     *
+     * <p>A scanner's locale affects many elements of its default
+     * primitive matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * <p>Invoking the {@link #reset} method will set the scanner's locale to
+     * the <a href= "#initial-locale">initial locale</a>.
+     *
+     * @param locale A string specifying the locale to use
+     * @return this scanner
+     */
+    public Scanner useLocale(Locale locale) {
+        if (locale.equals(this.locale))
+            return this;
+
+        this.locale = locale;
+        DecimalFormat df =
+            (DecimalFormat)NumberFormat.getNumberInstance(locale);
+        DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
+
+        // These must be literalized to avoid collision with regex
+        // metacharacters such as dot or parenthesis
+        groupSeparator =   "\\" + dfs.getGroupingSeparator();
+        decimalSeparator = "\\" + dfs.getDecimalSeparator();
+
+        // Quoting the nonzero length locale-specific things
+        // to avoid potential conflict with metacharacters
+        nanString = "\\Q" + dfs.getNaN() + "\\E";
+        infinityString = "\\Q" + dfs.getInfinity() + "\\E";
+        positivePrefix = df.getPositivePrefix();
+        if (positivePrefix.length() > 0)
+            positivePrefix = "\\Q" + positivePrefix + "\\E";
+        negativePrefix = df.getNegativePrefix();
+        if (negativePrefix.length() > 0)
+            negativePrefix = "\\Q" + negativePrefix + "\\E";
+        positiveSuffix = df.getPositiveSuffix();
+        if (positiveSuffix.length() > 0)
+            positiveSuffix = "\\Q" + positiveSuffix + "\\E";
+        negativeSuffix = df.getNegativeSuffix();
+        if (negativeSuffix.length() > 0)
+            negativeSuffix = "\\Q" + negativeSuffix + "\\E";
+
+        // Force rebuilding and recompilation of locale dependent
+        // primitive patterns
+        integerPattern = null;
+        floatPattern = null;
+
+        return this;
+    }
+
+    /**
+     * Returns this scanner's default radix.
+     *
+     * <p>A scanner's radix affects elements of its default
+     * number matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * @return the default radix of this scanner
+     */
+    public int radix() {
+        return this.defaultRadix;
+    }
+
+    /**
+     * Sets this scanner's default radix to the specified radix.
+     *
+     * <p>A scanner's radix affects elements of its default
+     * number matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * <p>If the radix is less than <code>Character.MIN_RADIX</code>
+     * or greater than <code>Character.MAX_RADIX</code>, then an
+     * <code>IllegalArgumentException</code> is thrown.
+     *
+     * <p>Invoking the {@link #reset} method will set the scanner's radix to
+     * <code>10</code>.
+     *
+     * @param radix The radix to use when scanning numbers
+     * @return this scanner
+     * @throws IllegalArgumentException if radix is out of range
+     */
+    public Scanner useRadix(int radix) {
+        if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX))
+            throw new IllegalArgumentException("radix:"+radix);
+
+        if (this.defaultRadix == radix)
+            return this;
+        this.defaultRadix = radix;
+        // Force rebuilding and recompilation of radix dependent patterns
+        integerPattern = null;
+        return this;
+    }
+
+    // The next operation should occur in the specified radix but
+    // the default is left untouched.
+    private void setRadix(int radix) {
+        // BEGIN Android-added: Complain loudly if a bogus radix is being set.
+        if (radix > Character.MAX_RADIX) {
+            throw new IllegalArgumentException("radix == " + radix);
+        }
+        // END Android-added: Complain loudly if a bogus radix is being set.
+
+        if (this.radix != radix) {
+            // Force rebuilding and recompilation of radix dependent patterns
+            integerPattern = null;
+            this.radix = radix;
+        }
+    }
+
+    /**
+     * Returns the match result of the last scanning operation performed
+     * by this scanner. This method throws <code>IllegalStateException</code>
+     * if no match has been performed, or if the last match was
+     * not successful.
+     *
+     * <p>The various <code>next</code>methods of <code>Scanner</code>
+     * make a match result available if they complete without throwing an
+     * exception. For instance, after an invocation of the {@link #nextInt}
+     * method that returned an int, this method returns a
+     * <code>MatchResult</code> for the search of the
+     * <a href="#Integer-regex"><i>Integer</i></a> regular expression
+     * defined above. Similarly the {@link #findInLine},
+     * {@link #findWithinHorizon}, and {@link #skip} methods will make a
+     * match available if they succeed.
+     *
+     * @return a match result for the last match operation
+     * @throws IllegalStateException  If no match result is available
+     */
+    public MatchResult match() {
+        if (!matchValid)
+            throw new IllegalStateException("No match result available");
+        return matcher.toMatchResult();
+    }
+
+    /**
+     * <p>Returns the string representation of this <code>Scanner</code>. The
+     * string representation of a <code>Scanner</code> contains information
+     * that may be useful for debugging. The exact format is unspecified.
+     *
+     * @return  The string representation of this scanner
+     */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("java.util.Scanner");
+        sb.append("[delimiters=" + delimPattern + "]");
+        sb.append("[position=" + position + "]");
+        sb.append("[match valid=" + matchValid + "]");
+        sb.append("[need input=" + needInput + "]");
+        sb.append("[source closed=" + sourceClosed + "]");
+        sb.append("[skipped=" + skipped + "]");
+        sb.append("[group separator=" + groupSeparator + "]");
+        sb.append("[decimal separator=" + decimalSeparator + "]");
+        sb.append("[positive prefix=" + positivePrefix + "]");
+        sb.append("[negative prefix=" + negativePrefix + "]");
+        sb.append("[positive suffix=" + positiveSuffix + "]");
+        sb.append("[negative suffix=" + negativeSuffix + "]");
+        sb.append("[NaN string=" + nanString + "]");
+        sb.append("[infinity string=" + infinityString + "]");
+        return sb.toString();
+    }
+
+    /**
+     * Returns true if this scanner has another token in its input.
+     * This method may block while waiting for input to scan.
+     * The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner has another token
+     * @throws IllegalStateException if this scanner is closed
+     * @see java.util.Iterator
+     */
+    public boolean hasNext() {
+        ensureOpen();
+        saveState();
+        while (!sourceClosed) {
+            if (hasTokenInBuffer())
+                return revertState(true);
+            readInput();
+        }
+        boolean result = hasTokenInBuffer();
+        return revertState(result);
+    }
+
+    /**
+     * Finds and returns the next complete token from this scanner.
+     * A complete token is preceded and followed by input that matches
+     * the delimiter pattern. This method may block while waiting for input
+     * to scan, even if a previous invocation of {@link #hasNext} returned
+     * <code>true</code>.
+     *
+     * @return the next token
+     * @throws NoSuchElementException if no more tokens are available
+     * @throws IllegalStateException if this scanner is closed
+     * @see java.util.Iterator
+     */
+    public String next() {
+        ensureOpen();
+        clearCaches();
+
+        while (true) {
+            String token = getCompleteTokenInBuffer(null);
+            if (token != null) {
+                matchValid = true;
+                skipped = false;
+                return token;
+            }
+            if (needInput)
+                readInput();
+            else
+                throwFor();
+        }
+    }
+
+    /**
+     * The remove operation is not supported by this implementation of
+     * <code>Iterator</code>.
+     *
+     * @throws UnsupportedOperationException if this method is invoked.
+     * @see java.util.Iterator
+     */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns true if the next token matches the pattern constructed from the
+     * specified string. The scanner does not advance past any input.
+     *
+     * <p> An invocation of this method of the form <tt>hasNext(pattern)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>hasNext(Pattern.compile(pattern))</tt>.
+     *
+     * @param pattern a string specifying the pattern to scan
+     * @return true if and only if this scanner has another token matching
+     *         the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNext(String pattern)  {
+        return hasNext(patternCache.forName(pattern));
+    }
+
+    /**
+     * Returns the next token if it matches the pattern constructed from the
+     * specified string.  If the match is successful, the scanner advances
+     * past the input that matched the pattern.
+     *
+     * <p> An invocation of this method of the form <tt>next(pattern)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>next(Pattern.compile(pattern))</tt>.
+     *
+     * @param pattern a string specifying the pattern to scan
+     * @return the next token
+     * @throws NoSuchElementException if no such tokens are available
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String next(String pattern)  {
+        return next(patternCache.forName(pattern));
+    }
+
+    /**
+     * Returns true if the next complete token matches the specified pattern.
+     * A complete token is prefixed and postfixed by input that matches
+     * the delimiter pattern. This method may block while waiting for input.
+     * The scanner does not advance past any input.
+     *
+     * @param pattern the pattern to scan for
+     * @return true if and only if this scanner has another token matching
+     *         the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNext(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        hasNextPattern = null;
+        saveState();
+
+        while (true) {
+            if (getCompleteTokenInBuffer(pattern) != null) {
+                matchValid = true;
+                cacheResult();
+                return revertState(true);
+            }
+            if (needInput)
+                readInput();
+            else
+                return revertState(false);
+        }
+    }
+
+    /**
+     * Returns the next token if it matches the specified pattern. This
+     * method may block while waiting for input to scan, even if a previous
+     * invocation of {@link #hasNext(Pattern)} returned <code>true</code>.
+     * If the match is successful, the scanner advances past the input that
+     * matched the pattern.
+     *
+     * @param pattern the pattern to scan for
+     * @return the next token
+     * @throws NoSuchElementException if no more tokens are available
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String next(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+
+        // Did we already find this pattern?
+        if (hasNextPattern == pattern)
+            return getCachedResult();
+        clearCaches();
+
+        // Search for the pattern
+        while (true) {
+            String token = getCompleteTokenInBuffer(pattern);
+            if (token != null) {
+                matchValid = true;
+                skipped = false;
+                return token;
+            }
+            if (needInput)
+                readInput();
+            else
+                throwFor();
+        }
+    }
+
+    /**
+     * Returns true if there is another line in the input of this scanner.
+     * This method may block while waiting for input. The scanner does not
+     * advance past any input.
+     *
+     * @return true if and only if this scanner has another line of input
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextLine() {
+        saveState();
+
+        String result = findWithinHorizon(linePattern(), 0);
+        if (result != null) {
+            MatchResult mr = this.match();
+            String lineSep = mr.group(1);
+            if (lineSep != null) {
+                result = result.substring(0, result.length() -
+                                          lineSep.length());
+                cacheResult(result);
+
+            } else {
+                cacheResult();
+            }
+        }
+        revertState();
+        return (result != null);
+    }
+
+    /**
+     * Advances this scanner past the current line and returns the input
+     * that was skipped.
+     *
+     * This method returns the rest of the current line, excluding any line
+     * separator at the end. The position is set to the beginning of the next
+     * line.
+     *
+     * <p>Since this method continues to search through the input looking
+     * for a line separator, it may buffer all of the input searching for
+     * the line to skip if no line separators are present.
+     *
+     * @return the line that was skipped
+     * @throws NoSuchElementException if no line was found
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String nextLine() {
+        if (hasNextPattern == linePattern())
+            return getCachedResult();
+        clearCaches();
+
+        String result = findWithinHorizon(linePattern, 0);
+        if (result == null)
+            throw new NoSuchElementException("No line found");
+        MatchResult mr = this.match();
+        String lineSep = mr.group(1);
+        if (lineSep != null)
+            result = result.substring(0, result.length() - lineSep.length());
+        if (result == null)
+            throw new NoSuchElementException();
+        else
+            return result;
+    }
+
+    // Public methods that ignore delimiters
+
+    /**
+     * Attempts to find the next occurrence of a pattern constructed from the
+     * specified string, ignoring delimiters.
+     *
+     * <p>An invocation of this method of the form <tt>findInLine(pattern)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>findInLine(Pattern.compile(pattern))</tt>.
+     *
+     * @param pattern a string specifying the pattern to search for
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String findInLine(String pattern) {
+        return findInLine(patternCache.forName(pattern));
+    }
+
+    /**
+     * Attempts to find the next occurrence of the specified pattern ignoring
+     * delimiters. If the pattern is found before the next line separator, the
+     * scanner advances past the input that matched and returns the string that
+     * matched the pattern.
+     * If no such pattern is detected in the input up to the next line
+     * separator, then <code>null</code> is returned and the scanner's
+     * position is unchanged. This method may block waiting for input that
+     * matches the pattern.
+     *
+     * <p>Since this method continues to search through the input looking
+     * for the specified pattern, it may buffer all of the input searching for
+     * the desired token if no line separators are present.
+     *
+     * @param pattern the pattern to scan for
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String findInLine(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        clearCaches();
+        // Expand buffer to include the next newline or end of input
+        int endPosition = 0;
+        saveState();
+        while (true) {
+            String token = findPatternInBuffer(separatorPattern(), 0);
+            if (token != null) {
+                endPosition = matcher.start();
+                break; // up to next newline
+            }
+            if (needInput) {
+                readInput();
+            } else {
+                endPosition = buf.limit();
+                break; // up to end of input
+            }
+        }
+        revertState();
+        int horizonForLine = endPosition - position;
+        // If there is nothing between the current pos and the next
+        // newline simply return null, invoking findWithinHorizon
+        // with "horizon=0" will scan beyond the line bound.
+        if (horizonForLine == 0)
+            return null;
+        // Search for the pattern
+        return findWithinHorizon(pattern, horizonForLine);
+    }
+
+    /**
+     * Attempts to find the next occurrence of a pattern constructed from the
+     * specified string, ignoring delimiters.
+     *
+     * <p>An invocation of this method of the form
+     * <tt>findWithinHorizon(pattern)</tt> behaves in exactly the same way as
+     * the invocation
+     * <tt>findWithinHorizon(Pattern.compile(pattern, horizon))</tt>.
+     *
+     * @param pattern a string specifying the pattern to search for
+     * @param horizon the search horizon
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if horizon is negative
+     */
+    public String findWithinHorizon(String pattern, int horizon) {
+        return findWithinHorizon(patternCache.forName(pattern), horizon);
+    }
+
+    /**
+     * Attempts to find the next occurrence of the specified pattern.
+     *
+     * <p>This method searches through the input up to the specified
+     * search horizon, ignoring delimiters. If the pattern is found the
+     * scanner advances past the input that matched and returns the string
+     * that matched the pattern. If no such pattern is detected then the
+     * null is returned and the scanner's position remains unchanged. This
+     * method may block waiting for input that matches the pattern.
+     *
+     * <p>A scanner will never search more than <code>horizon</code> code
+     * points beyond its current position. Note that a match may be clipped
+     * by the horizon; that is, an arbitrary match result may have been
+     * different if the horizon had been larger. The scanner treats the
+     * horizon as a transparent, non-anchoring bound (see {@link
+     * Matcher#useTransparentBounds} and {@link Matcher#useAnchoringBounds}).
+     *
+     * <p>If horizon is <code>0</code>, then the horizon is ignored and
+     * this method continues to search through the input looking for the
+     * specified pattern without bound. In this case it may buffer all of
+     * the input searching for the pattern.
+     *
+     * <p>If horizon is negative, then an IllegalArgumentException is
+     * thrown.
+     *
+     * @param pattern the pattern to scan for
+     * @param horizon the search horizon
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if horizon is negative
+     */
+    public String findWithinHorizon(Pattern pattern, int horizon) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        if (horizon < 0)
+            throw new IllegalArgumentException("horizon < 0");
+        clearCaches();
+
+        // Search for the pattern
+        while (true) {
+            String token = findPatternInBuffer(pattern, horizon);
+            if (token != null) {
+                matchValid = true;
+                return token;
+            }
+            if (needInput)
+                readInput();
+            else
+                break; // up to end of input
+        }
+        return null;
+    }
+
+    /**
+     * Skips input that matches the specified pattern, ignoring delimiters.
+     * This method will skip input if an anchored match of the specified
+     * pattern succeeds.
+     *
+     * <p>If a match to the specified pattern is not found at the
+     * current position, then no input is skipped and a
+     * <tt>NoSuchElementException</tt> is thrown.
+     *
+     * <p>Since this method seeks to match the specified pattern starting at
+     * the scanner's current position, patterns that can match a lot of
+     * input (".*", for example) may cause the scanner to buffer a large
+     * amount of input.
+     *
+     * <p>Note that it is possible to skip something without risking a
+     * <code>NoSuchElementException</code> by using a pattern that can
+     * match nothing, e.g., <code>sc.skip("[ \t]*")</code>.
+     *
+     * @param pattern a string specifying the pattern to skip over
+     * @return this scanner
+     * @throws NoSuchElementException if the specified pattern is not found
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public Scanner skip(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        clearCaches();
+
+        // Search for the pattern
+        while (true) {
+            String token = matchPatternInBuffer(pattern);
+            if (token != null) {
+                matchValid = true;
+                position = matcher.end();
+                return this;
+            }
+            if (needInput)
+                readInput();
+            else
+                throw new NoSuchElementException();
+        }
+    }
+
+    /**
+     * Skips input that matches a pattern constructed from the specified
+     * string.
+     *
+     * <p> An invocation of this method of the form <tt>skip(pattern)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>skip(Pattern.compile(pattern))</tt>.
+     *
+     * @param pattern a string specifying the pattern to skip over
+     * @return this scanner
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public Scanner skip(String pattern) {
+        return skip(patternCache.forName(pattern));
+    }
+
+    // Convenience methods for scanning primitives
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a boolean value using a case insensitive pattern
+     * created from the string "true|false".  The scanner does not
+     * advance past the input that matched.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         boolean value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextBoolean()  {
+        return hasNext(boolPattern());
+    }
+
+    /**
+     * Scans the next token of the input into a boolean value and returns
+     * that value. This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid boolean value.
+     * If the match is successful, the scanner advances past the input that
+     * matched.
+     *
+     * @return the boolean scanned from the input
+     * @throws InputMismatchException if the next token is not a valid boolean
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean nextBoolean()  {
+        clearCaches();
+        return Boolean.parseBoolean(next(boolPattern()));
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a byte value in the default radix using the
+     * {@link #nextByte} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         byte value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextByte() {
+        return hasNextByte(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a byte value in the specified radix using the
+     * {@link #nextByte} method. The scanner does not advance past any input.
+     *
+     * @param radix the radix used to interpret the token as a byte value
+     * @return true if and only if this scanner's next token is a valid
+     *         byte value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextByte(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Byte.parseByte(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>byte</tt>.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>nextByte()</tt> behaves in exactly the same way as the
+     * invocation <tt>nextByte(radix)</tt>, where <code>radix</code>
+     * is the default radix of this scanner.
+     *
+     * @return the <tt>byte</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public byte nextByte() {
+         return nextByte(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>byte</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid byte value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a <tt>byte</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Byte#parseByte(String, int) Byte.parseByte} with the
+     * specified radix.
+     *
+     * @param radix the radix used to interpret the token as a byte value
+     * @return the <tt>byte</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public byte nextByte(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Byte)
+            && this.radix == radix) {
+            byte val = ((Byte)typeCache).byteValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next byte
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Byte.parseByte(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a short value in the default radix using the
+     * {@link #nextShort} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         short value in the default radix
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextShort() {
+        return hasNextShort(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a short value in the specified radix using the
+     * {@link #nextShort} method. The scanner does not advance past any input.
+     *
+     * @param radix the radix used to interpret the token as a short value
+     * @return true if and only if this scanner's next token is a valid
+     *         short value in the specified radix
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextShort(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Short.parseShort(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>short</tt>.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>nextShort()</tt> behaves in exactly the same way as the
+     * invocation <tt>nextShort(radix)</tt>, where <code>radix</code>
+     * is the default radix of this scanner.
+     *
+     * @return the <tt>short</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public short nextShort() {
+        return nextShort(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>short</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid short value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a <tt>short</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Short#parseShort(String, int) Short.parseShort} with the
+     * specified radix.
+     *
+     * @param radix the radix used to interpret the token as a short value
+     * @return the <tt>short</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public short nextShort(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Short)
+            && this.radix == radix) {
+            short val = ((Short)typeCache).shortValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next short
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Short.parseShort(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as an int value in the default radix using the
+     * {@link #nextInt} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         int value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextInt() {
+        return hasNextInt(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as an int value in the specified radix using the
+     * {@link #nextInt} method. The scanner does not advance past any input.
+     *
+     * @param radix the radix used to interpret the token as an int value
+     * @return true if and only if this scanner's next token is a valid
+     *         int value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextInt(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Integer.parseInt(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * The integer token must be stripped of prefixes, group separators,
+     * and suffixes, non ascii digits must be converted into ascii digits
+     * before parse will accept it.
+     */
+    private String processIntegerToken(String token) {
+        String result = token.replaceAll(""+groupSeparator, "");
+        boolean isNegative = false;
+        int preLen = negativePrefix.length();
+        if ((preLen > 0) && result.startsWith(negativePrefix)) {
+            isNegative = true;
+            result = result.substring(preLen);
+        }
+        int sufLen = negativeSuffix.length();
+        if ((sufLen > 0) && result.endsWith(negativeSuffix)) {
+            isNegative = true;
+            result = result.substring(result.length() - sufLen,
+                                      result.length());
+        }
+        if (isNegative)
+            result = "-" + result;
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as an <tt>int</tt>.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>nextInt()</tt> behaves in exactly the same way as the
+     * invocation <tt>nextInt(radix)</tt>, where <code>radix</code>
+     * is the default radix of this scanner.
+     *
+     * @return the <tt>int</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public int nextInt() {
+        return nextInt(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as an <tt>int</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid int value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into an <tt>int</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Integer#parseInt(String, int) Integer.parseInt} with the
+     * specified radix.
+     *
+     * @param radix the radix used to interpret the token as an int value
+     * @return the <tt>int</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public int nextInt(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Integer)
+            && this.radix == radix) {
+            int val = ((Integer)typeCache).intValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next int
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Integer.parseInt(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a long value in the default radix using the
+     * {@link #nextLong} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         long value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextLong() {
+        return hasNextLong(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a long value in the specified radix using the
+     * {@link #nextLong} method. The scanner does not advance past any input.
+     *
+     * @param radix the radix used to interpret the token as a long value
+     * @return true if and only if this scanner's next token is a valid
+     *         long value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextLong(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Long.parseLong(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>long</tt>.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>nextLong()</tt> behaves in exactly the same way as the
+     * invocation <tt>nextLong(radix)</tt>, where <code>radix</code>
+     * is the default radix of this scanner.
+     *
+     * @return the <tt>long</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public long nextLong() {
+        return nextLong(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>long</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid long value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a <tt>long</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Long#parseLong(String, int) Long.parseLong} with the
+     * specified radix.
+     *
+     * @param radix the radix used to interpret the token as an int value
+     * @return the <tt>long</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public long nextLong(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Long)
+            && this.radix == radix) {
+            long val = ((Long)typeCache).longValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Long.parseLong(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * The float token must be stripped of prefixes, group separators,
+     * and suffixes, non ascii digits must be converted into ascii digits
+     * before parseFloat will accept it.
+     *
+     * If there are non-ascii digits in the token these digits must
+     * be processed before the token is passed to parseFloat.
+     */
+    private String processFloatToken(String token) {
+        String result = token.replaceAll(groupSeparator, "");
+        if (!decimalSeparator.equals("\\."))
+            result = result.replaceAll(decimalSeparator, ".");
+        boolean isNegative = false;
+        int preLen = negativePrefix.length();
+        if ((preLen > 0) && result.startsWith(negativePrefix)) {
+            isNegative = true;
+            result = result.substring(preLen);
+        }
+        int sufLen = negativeSuffix.length();
+        if ((sufLen > 0) && result.endsWith(negativeSuffix)) {
+            isNegative = true;
+            result = result.substring(result.length() - sufLen,
+                                      result.length());
+        }
+        if (result.equals(nanString))
+            result = "NaN";
+        if (result.equals(infinityString))
+            result = "Infinity";
+        // BEGIN Android-added: Match the infinity symbol.
+        if (result.equals("\u221E"))
+            result = "Infinity";
+        // END Android-added: Match the infinity symbol.
+        if (isNegative)
+            result = "-" + result;
+
+        // Translate non-ASCII digits
+        Matcher m = NON_ASCII_DIGIT.matcher(result);
+        if (m.find()) {
+            StringBuilder inASCII = new StringBuilder();
+            for (int i=0; i<result.length(); i++) {
+                char nextChar = result.charAt(i);
+                if (Character.isDigit(nextChar)) {
+                    int d = Character.digit(nextChar, 10);
+                    if (d != -1)
+                        inASCII.append(d);
+                    else
+                        inASCII.append(nextChar);
+                } else {
+                    inASCII.append(nextChar);
+                }
+            }
+            result = inASCII.toString();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a float value using the {@link #nextFloat}
+     * method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         float value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextFloat() {
+        setRadix(10);
+        boolean result = hasNext(floatPattern());
+        if (result) { // Cache it
+            try {
+                String s = processFloatToken(hasNextResult);
+                typeCache = Float.valueOf(Float.parseFloat(s));
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>float</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid float value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Float-regex"><i>Float</i></a> regular expression defined above
+     * then the token is converted into a <tt>float</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Float#parseFloat Float.parseFloat}. If the token matches
+     * the localized NaN or infinity strings, then either "Nan" or "Infinity"
+     * is passed to {@link Float#parseFloat(String) Float.parseFloat} as
+     * appropriate.
+     *
+     * @return the <tt>float</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Float</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public float nextFloat() {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Float)) {
+            float val = ((Float)typeCache).floatValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(10);
+        clearCaches();
+        try {
+            return Float.parseFloat(processFloatToken(next(floatPattern())));
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a double value using the {@link #nextDouble}
+     * method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         double value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextDouble() {
+        setRadix(10);
+        boolean result = hasNext(floatPattern());
+        if (result) { // Cache it
+            try {
+                String s = processFloatToken(hasNextResult);
+                typeCache = Double.valueOf(Double.parseDouble(s));
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>double</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid double value.
+     * If the translation is successful, the scanner advances past the input
+     * that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Float-regex"><i>Float</i></a> regular expression defined above
+     * then the token is converted into a <tt>double</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Double#parseDouble Double.parseDouble}. If the token matches
+     * the localized NaN or infinity strings, then either "Nan" or "Infinity"
+     * is passed to {@link Double#parseDouble(String) Double.parseDouble} as
+     * appropriate.
+     *
+     * @return the <tt>double</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Float</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public double nextDouble() {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Double)) {
+            double val = ((Double)typeCache).doubleValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(10);
+        clearCaches();
+        // Search for next float
+        try {
+            return Double.parseDouble(processFloatToken(next(floatPattern())));
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    // Convenience methods for scanning multi precision numbers
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a <code>BigInteger</code> in the default radix using the
+     * {@link #nextBigInteger} method. The scanner does not advance past any
+     * input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         <code>BigInteger</code>
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextBigInteger() {
+        return hasNextBigInteger(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a <code>BigInteger</code> in the specified radix using
+     * the {@link #nextBigInteger} method. The scanner does not advance past
+     * any input.
+     *
+     * @param radix the radix used to interpret the token as an integer
+     * @return true if and only if this scanner's next token is a valid
+     *         <code>BigInteger</code>
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextBigInteger(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = new BigInteger(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a {@link java.math.BigInteger
+     * BigInteger}.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>nextBigInteger()</tt> behaves in exactly the same way as the
+     * invocation <tt>nextBigInteger(radix)</tt>, where <code>radix</code>
+     * is the default radix of this scanner.
+     *
+     * @return the <tt>BigInteger</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public BigInteger nextBigInteger() {
+        return nextBigInteger(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a {@link java.math.BigInteger
+     * BigInteger}.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a <tt>BigInteger</tt> value as if
+     * by removing all group separators, mapping non-ASCII digits into ASCII
+     * digits via the {@link Character#digit Character.digit}, and passing the
+     * resulting string to the {@link
+     * java.math.BigInteger#BigInteger(java.lang.String)
+     * BigInteger(String, int)} constructor with the specified radix.
+     *
+     * @param radix the radix used to interpret the token
+     * @return the <tt>BigInteger</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public BigInteger nextBigInteger(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof BigInteger)
+            && this.radix == radix) {
+            BigInteger val = (BigInteger)typeCache;
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next int
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return new BigInteger(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a <code>BigDecimal</code> using the
+     * {@link #nextBigDecimal} method. The scanner does not advance past any
+     * input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         <code>BigDecimal</code>
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextBigDecimal() {
+        setRadix(10);
+        boolean result = hasNext(decimalPattern());
+        if (result) { // Cache it
+            try {
+                String s = processFloatToken(hasNextResult);
+                typeCache = new BigDecimal(s);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a {@link java.math.BigDecimal
+     * BigDecimal}.
+     *
+     * <p> If the next token matches the <a
+     * href="#Decimal-regex"><i>Decimal</i></a> regular expression defined
+     * above then the token is converted into a <tt>BigDecimal</tt> value as if
+     * by removing all group separators, mapping non-ASCII digits into ASCII
+     * digits via the {@link Character#digit Character.digit}, and passing the
+     * resulting string to the {@link
+     * java.math.BigDecimal#BigDecimal(java.lang.String) BigDecimal(String)}
+     * constructor.
+     *
+     * @return the <tt>BigDecimal</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Decimal</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public BigDecimal nextBigDecimal() {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof BigDecimal)) {
+            BigDecimal val = (BigDecimal)typeCache;
+            useTypeCache();
+            return val;
+        }
+        setRadix(10);
+        clearCaches();
+        // Search for next float
+        try {
+            String s = processFloatToken(next(decimalPattern()));
+            return new BigDecimal(s);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Resets this scanner.
+     *
+     * <p> Resetting a scanner discards all of its explicit state
+     * information which may have been changed by invocations of {@link
+     * #useDelimiter}, {@link #useLocale}, or {@link #useRadix}.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>scanner.reset()</tt> behaves in exactly the same way as the
+     * invocation
+     *
+     * <blockquote><pre>{@code
+     *   scanner.useDelimiter("\\p{javaWhitespace}+")
+     *          .useLocale(Locale.getDefault(Locale.Category.FORMAT))
+     *          .useRadix(10);
+     * }</pre></blockquote>
+     *
+     * @return this scanner
+     *
+     * @since 1.6
+     */
+    public Scanner reset() {
+        delimPattern = WHITESPACE_PATTERN;
+        useLocale(Locale.getDefault(Locale.Category.FORMAT));
+        useRadix(10);
+        clearCaches();
+        return this;
+    }
+}
diff --git a/java/util/ServiceConfigurationError.java b/java/util/ServiceConfigurationError.java
new file mode 100644
index 0000000..e0335f6
--- /dev/null
+++ b/java/util/ServiceConfigurationError.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+
+/**
+ * Error thrown when something goes wrong while loading a service provider.
+ *
+ * <p> This error will be thrown in the following situations:
+ *
+ * <ul>
+ *
+ *   <li> The format of a provider-configuration file violates the <a
+ *   href="ServiceLoader.html#format">specification</a>; </li>
+ *
+ *   <li> An {@link java.io.IOException IOException} occurs while reading a
+ *   provider-configuration file; </li>
+ *
+ *   <li> A concrete provider class named in a provider-configuration file
+ *   cannot be found; </li>
+ *
+ *   <li> A concrete provider class is not a subclass of the service class;
+ *   </li>
+ *
+ *   <li> A concrete provider class cannot be instantiated; or
+ *
+ *   <li> Some other kind of error occurs. </li>
+ *
+ * </ul>
+ *
+ *
+ * @author Mark Reinhold
+ * @since 1.6
+ */
+
+public class ServiceConfigurationError
+    extends Error
+{
+
+    private static final long serialVersionUID = 74132770414881L;
+
+    /**
+     * Constructs a new instance with the specified message.
+     *
+     * @param  msg  The message, or <tt>null</tt> if there is no message
+     *
+     */
+    public ServiceConfigurationError(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance with the specified message and cause.
+     *
+     * @param  msg  The message, or <tt>null</tt> if there is no message
+     *
+     * @param  cause  The cause, or <tt>null</tt> if the cause is nonexistent
+     *                or unknown
+     */
+    public ServiceConfigurationError(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+}
diff --git a/java/util/ServiceLoader.java b/java/util/ServiceLoader.java
new file mode 100644
index 0000000..44582e7
--- /dev/null
+++ b/java/util/ServiceLoader.java
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+
+/**
+ * A simple service-provider loading facility.
+ *
+ * <p> A <i>service</i> is a well-known set of interfaces and (usually
+ * abstract) classes.  A <i>service provider</i> is a specific implementation
+ * of a service.  The classes in a provider typically implement the interfaces
+ * and subclass the classes defined in the service itself.  Service providers
+ * can be installed in an implementation of the Java platform in the form of
+ * extensions, that is, jar files placed into any of the usual extension
+ * directories.  Providers can also be made available by adding them to the
+ * application's class path or by some other platform-specific means.
+ *
+ * <p> For the purpose of loading, a service is represented by a single type,
+ * that is, a single interface or abstract class.  (A concrete class can be
+ * used, but this is not recommended.)  A provider of a given service contains
+ * one or more concrete classes that extend this <i>service type</i> with data
+ * and code specific to the provider.  The <i>provider class</i> is typically
+ * not the entire provider itself but rather a proxy which contains enough
+ * information to decide whether the provider is able to satisfy a particular
+ * request together with code that can create the actual provider on demand.
+ * The details of provider classes tend to be highly service-specific; no
+ * single class or interface could possibly unify them, so no such type is
+ * defined here.  The only requirement enforced by this facility is that
+ * provider classes must have a zero-argument constructor so that they can be
+ * instantiated during loading.
+ *
+ * <p><a name="format"> A service provider is identified by placing a
+ * <i>provider-configuration file</i> in the resource directory
+ * <tt>META-INF/services</tt>.</a>  The file's name is the fully-qualified <a
+ * href="../lang/ClassLoader.html#name">binary name</a> of the service's type.
+ * The file contains a list of fully-qualified binary names of concrete
+ * provider classes, one per line.  Space and tab characters surrounding each
+ * name, as well as blank lines, are ignored.  The comment character is
+ * <tt>'#'</tt> (<tt>'&#92;u0023'</tt>,
+ * <font style="font-size:smaller;">NUMBER SIGN</font>); on
+ * each line all characters following the first comment character are ignored.
+ * The file must be encoded in UTF-8.
+ *
+ * <p> If a particular concrete provider class is named in more than one
+ * configuration file, or is named in the same configuration file more than
+ * once, then the duplicates are ignored.  The configuration file naming a
+ * particular provider need not be in the same jar file or other distribution
+ * unit as the provider itself.  The provider must be accessible from the same
+ * class loader that was initially queried to locate the configuration file;
+ * note that this is not necessarily the class loader from which the file was
+ * actually loaded.
+ *
+ * <p> Providers are located and instantiated lazily, that is, on demand.  A
+ * service loader maintains a cache of the providers that have been loaded so
+ * far.  Each invocation of the {@link #iterator iterator} method returns an
+ * iterator that first yields all of the elements of the cache, in
+ * instantiation order, and then lazily locates and instantiates any remaining
+ * providers, adding each one to the cache in turn.  The cache can be cleared
+ * via the {@link #reload reload} method.
+ *
+ * <p> Service loaders always execute in the security context of the caller.
+ * Trusted system code should typically invoke the methods in this class, and
+ * the methods of the iterators which they return, from within a privileged
+ * security context.
+ *
+ * <p> Instances of this class are not safe for use by multiple concurrent
+ * threads.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method in this class will cause a {@link NullPointerException} to be thrown.
+ *
+ *
+ * <p><span style="font-weight: bold; padding-right: 1em">Example</span>
+ * Suppose we have a service type <tt>com.example.CodecSet</tt> which is
+ * intended to represent sets of encoder/decoder pairs for some protocol.  In
+ * this case it is an abstract class with two abstract methods:
+ *
+ * <blockquote><pre>
+ * public abstract Encoder getEncoder(String encodingName);
+ * public abstract Decoder getDecoder(String encodingName);</pre></blockquote>
+ *
+ * Each method returns an appropriate object or <tt>null</tt> if the provider
+ * does not support the given encoding.  Typical providers support more than
+ * one encoding.
+ *
+ * <p> If <tt>com.example.impl.StandardCodecs</tt> is an implementation of the
+ * <tt>CodecSet</tt> service then its jar file also contains a file named
+ *
+ * <blockquote><pre>
+ * META-INF/services/com.example.CodecSet</pre></blockquote>
+ *
+ * <p> This file contains the single line:
+ *
+ * <blockquote><pre>
+ * com.example.impl.StandardCodecs    # Standard codecs</pre></blockquote>
+ *
+ * <p> The <tt>CodecSet</tt> class creates and saves a single service instance
+ * at initialization:
+ *
+ * <blockquote><pre>
+ * private static ServiceLoader&lt;CodecSet&gt; codecSetLoader
+ *     = ServiceLoader.load(CodecSet.class);</pre></blockquote>
+ *
+ * <p> To locate an encoder for a given encoding name it defines a static
+ * factory method which iterates through the known and available providers,
+ * returning only when it has located a suitable encoder or has run out of
+ * providers.
+ *
+ * <blockquote><pre>
+ * public static Encoder getEncoder(String encodingName) {
+ *     for (CodecSet cp : codecSetLoader) {
+ *         Encoder enc = cp.getEncoder(encodingName);
+ *         if (enc != null)
+ *             return enc;
+ *     }
+ *     return null;
+ * }</pre></blockquote>
+ *
+ * <p> A <tt>getDecoder</tt> method is defined similarly.
+ *
+ *
+ * <p><span style="font-weight: bold; padding-right: 1em">Usage Note</span> If
+ * the class path of a class loader that is used for provider loading includes
+ * remote network URLs then those URLs will be dereferenced in the process of
+ * searching for provider-configuration files.
+ *
+ * <p> This activity is normal, although it may cause puzzling entries to be
+ * created in web-server logs.  If a web server is not configured correctly,
+ * however, then this activity may cause the provider-loading algorithm to fail
+ * spuriously.
+ *
+ * <p> A web server should return an HTTP 404 (Not Found) response when a
+ * requested resource does not exist.  Sometimes, however, web servers are
+ * erroneously configured to return an HTTP 200 (OK) response along with a
+ * helpful HTML error page in such cases.  This will cause a {@link
+ * ServiceConfigurationError} to be thrown when this class attempts to parse
+ * the HTML page as a provider-configuration file.  The best solution to this
+ * problem is to fix the misconfigured web server to return the correct
+ * response code (HTTP 404) along with the HTML error page.
+ *
+ * @param  <S>
+ *         The type of the service to be loaded by this loader
+ *
+ * @author Mark Reinhold
+ * @since 1.6
+ */
+
+public final class ServiceLoader<S>
+    implements Iterable<S>
+{
+
+    private static final String PREFIX = "META-INF/services/";
+
+    // The class or interface representing the service being loaded
+    private final Class<S> service;
+
+    // The class loader used to locate, load, and instantiate providers
+    private final ClassLoader loader;
+
+    // The access control context taken when the ServiceLoader is created
+    // Android-changed: do not use legacy security code.
+    // private final AccessControlContext acc;
+
+    // Cached providers, in instantiation order
+    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
+
+    // The current lazy-lookup iterator
+    private LazyIterator lookupIterator;
+
+    /**
+     * Clear this loader's provider cache so that all providers will be
+     * reloaded.
+     *
+     * <p> After invoking this method, subsequent invocations of the {@link
+     * #iterator() iterator} method will lazily look up and instantiate
+     * providers from scratch, just as is done by a newly-created loader.
+     *
+     * <p> This method is intended for use in situations in which new providers
+     * can be installed into a running Java virtual machine.
+     */
+    public void reload() {
+        providers.clear();
+        lookupIterator = new LazyIterator(service, loader);
+    }
+
+    private ServiceLoader(Class<S> svc, ClassLoader cl) {
+        service = Objects.requireNonNull(svc, "Service interface cannot be null");
+        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
+        // Android-changed: Do not use legacy security code.
+        // On Android, System.getSecurityManager() is always null.
+        // acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
+        reload();
+    }
+
+    private static void fail(Class<?> service, String msg, Throwable cause)
+        throws ServiceConfigurationError
+    {
+        throw new ServiceConfigurationError(service.getName() + ": " + msg,
+                                            cause);
+    }
+
+    private static void fail(Class<?> service, String msg)
+        throws ServiceConfigurationError
+    {
+        throw new ServiceConfigurationError(service.getName() + ": " + msg);
+    }
+
+    private static void fail(Class<?> service, URL u, int line, String msg)
+        throws ServiceConfigurationError
+    {
+        fail(service, u + ":" + line + ": " + msg);
+    }
+
+    // Parse a single line from the given configuration file, adding the name
+    // on the line to the names list.
+    //
+    private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
+                          List<String> names)
+        throws IOException, ServiceConfigurationError
+    {
+        String ln = r.readLine();
+        if (ln == null) {
+            return -1;
+        }
+        int ci = ln.indexOf('#');
+        if (ci >= 0) ln = ln.substring(0, ci);
+        ln = ln.trim();
+        int n = ln.length();
+        if (n != 0) {
+            if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
+                fail(service, u, lc, "Illegal configuration-file syntax");
+            int cp = ln.codePointAt(0);
+            if (!Character.isJavaIdentifierStart(cp))
+                fail(service, u, lc, "Illegal provider-class name: " + ln);
+            for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
+                cp = ln.codePointAt(i);
+                if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
+                    fail(service, u, lc, "Illegal provider-class name: " + ln);
+            }
+            if (!providers.containsKey(ln) && !names.contains(ln))
+                names.add(ln);
+        }
+        return lc + 1;
+    }
+
+    // Parse the content of the given URL as a provider-configuration file.
+    //
+    // @param  service
+    //         The service type for which providers are being sought;
+    //         used to construct error detail strings
+    //
+    // @param  u
+    //         The URL naming the configuration file to be parsed
+    //
+    // @return A (possibly empty) iterator that will yield the provider-class
+    //         names in the given configuration file that are not yet members
+    //         of the returned set
+    //
+    // @throws ServiceConfigurationError
+    //         If an I/O error occurs while reading from the given URL, or
+    //         if a configuration-file format error is detected
+    //
+    private Iterator<String> parse(Class<?> service, URL u)
+        throws ServiceConfigurationError
+    {
+        InputStream in = null;
+        BufferedReader r = null;
+        ArrayList<String> names = new ArrayList<>();
+        try {
+            in = u.openStream();
+            r = new BufferedReader(new InputStreamReader(in, "utf-8"));
+            int lc = 1;
+            while ((lc = parseLine(service, u, r, lc, names)) >= 0);
+        } catch (IOException x) {
+            fail(service, "Error reading configuration file", x);
+        } finally {
+            try {
+                if (r != null) r.close();
+                if (in != null) in.close();
+            } catch (IOException y) {
+                fail(service, "Error closing configuration file", y);
+            }
+        }
+        return names.iterator();
+    }
+
+    // Private inner class implementing fully-lazy provider lookup
+    //
+    private class LazyIterator
+        implements Iterator<S>
+    {
+
+        Class<S> service;
+        ClassLoader loader;
+        Enumeration<URL> configs = null;
+        Iterator<String> pending = null;
+        String nextName = null;
+
+        private LazyIterator(Class<S> service, ClassLoader loader) {
+            this.service = service;
+            this.loader = loader;
+        }
+
+        private boolean hasNextService() {
+            if (nextName != null) {
+                return true;
+            }
+            if (configs == null) {
+                try {
+                    String fullName = PREFIX + service.getName();
+                    if (loader == null)
+                        configs = ClassLoader.getSystemResources(fullName);
+                    else
+                        configs = loader.getResources(fullName);
+                } catch (IOException x) {
+                    fail(service, "Error locating configuration files", x);
+                }
+            }
+            while ((pending == null) || !pending.hasNext()) {
+                if (!configs.hasMoreElements()) {
+                    return false;
+                }
+                pending = parse(service, configs.nextElement());
+            }
+            nextName = pending.next();
+            return true;
+        }
+
+        private S nextService() {
+            if (!hasNextService())
+                throw new NoSuchElementException();
+            String cn = nextName;
+            nextName = null;
+            Class<?> c = null;
+            try {
+                c = Class.forName(cn, false, loader);
+            } catch (ClassNotFoundException x) {
+                fail(service,
+                     // Android-changed: Let the ServiceConfigurationError have a cause.
+                     "Provider " + cn + " not found", x);
+                     // "Provider " + cn + " not found");
+            }
+            if (!service.isAssignableFrom(c)) {
+                // Android-changed: Let the ServiceConfigurationError have a cause.
+                ClassCastException cce = new ClassCastException(
+                        service.getCanonicalName() + " is not assignable from " + c.getCanonicalName());
+                fail(service,
+                     "Provider " + cn  + " not a subtype", cce);
+                // fail(service,
+                //        "Provider " + cn  + " not a subtype");
+            }
+            try {
+                S p = service.cast(c.newInstance());
+                providers.put(cn, p);
+                return p;
+            } catch (Throwable x) {
+                fail(service,
+                     "Provider " + cn + " could not be instantiated",
+                     x);
+            }
+            throw new Error();          // This cannot happen
+        }
+
+        public boolean hasNext() {
+            // Android-changed: do not use legacy security code
+            /* if (acc == null) { */
+                return hasNextService();
+            /*
+            } else {
+                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
+                    public Boolean run() { return hasNextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+            */
+        }
+
+        public S next() {
+            // Android-changed: do not use legacy security code
+            /* if (acc == null) { */
+                return nextService();
+            /*
+            } else {
+                PrivilegedAction<S> action = new PrivilegedAction<S>() {
+                    public S run() { return nextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+            */
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+    /**
+     * Lazily loads the available providers of this loader's service.
+     *
+     * <p> The iterator returned by this method first yields all of the
+     * elements of the provider cache, in instantiation order.  It then lazily
+     * loads and instantiates any remaining providers, adding each one to the
+     * cache in turn.
+     *
+     * <p> To achieve laziness the actual work of parsing the available
+     * provider-configuration files and instantiating providers must be done by
+     * the iterator itself.  Its {@link java.util.Iterator#hasNext hasNext} and
+     * {@link java.util.Iterator#next next} methods can therefore throw a
+     * {@link ServiceConfigurationError} if a provider-configuration file
+     * violates the specified format, or if it names a provider class that
+     * cannot be found and instantiated, or if the result of instantiating the
+     * class is not assignable to the service type, or if any other kind of
+     * exception or error is thrown as the next provider is located and
+     * instantiated.  To write robust code it is only necessary to catch {@link
+     * ServiceConfigurationError} when using a service iterator.
+     *
+     * <p> If such an error is thrown then subsequent invocations of the
+     * iterator will make a best effort to locate and instantiate the next
+     * available provider, but in general such recovery cannot be guaranteed.
+     *
+     * <blockquote style="font-size: smaller; line-height: 1.2"><span
+     * style="padding-right: 1em; font-weight: bold">Design Note</span>
+     * Throwing an error in these cases may seem extreme.  The rationale for
+     * this behavior is that a malformed provider-configuration file, like a
+     * malformed class file, indicates a serious problem with the way the Java
+     * virtual machine is configured or is being used.  As such it is
+     * preferable to throw an error rather than try to recover or, even worse,
+     * fail silently.</blockquote>
+     *
+     * <p> The iterator returned by this method does not support removal.
+     * Invoking its {@link java.util.Iterator#remove() remove} method will
+     * cause an {@link UnsupportedOperationException} to be thrown.
+     *
+     * @implNote When adding providers to the cache, the {@link #iterator
+     * Iterator} processes resources in the order that the {@link
+     * java.lang.ClassLoader#getResources(java.lang.String)
+     * ClassLoader.getResources(String)} method finds the service configuration
+     * files.
+     *
+     * @return  An iterator that lazily loads providers for this loader's
+     *          service
+     */
+    public Iterator<S> iterator() {
+        return new Iterator<S>() {
+
+            Iterator<Map.Entry<String,S>> knownProviders
+                = providers.entrySet().iterator();
+
+            public boolean hasNext() {
+                if (knownProviders.hasNext())
+                    return true;
+                return lookupIterator.hasNext();
+            }
+
+            public S next() {
+                if (knownProviders.hasNext())
+                    return knownProviders.next().getValue();
+                return lookupIterator.next();
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+        };
+    }
+
+    /**
+     * Creates a new service loader for the given service type and class
+     * loader.
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @param  loader
+     *         The class loader to be used to load provider-configuration files
+     *         and provider classes, or <tt>null</tt> if the system class
+     *         loader (or, failing that, the bootstrap class loader) is to be
+     *         used
+     *
+     * @return A new service loader
+     */
+    public static <S> ServiceLoader<S> load(Class<S> service,
+                                            ClassLoader loader)
+    {
+        return new ServiceLoader<>(service, loader);
+    }
+
+    /**
+     * Creates a new service loader for the given service type, using the
+     * current thread's {@linkplain java.lang.Thread#getContextClassLoader
+     * context class loader}.
+     *
+     * <p> An invocation of this convenience method of the form
+     *
+     * <blockquote><pre>
+     * ServiceLoader.load(<i>service</i>)</pre></blockquote>
+     *
+     * is equivalent to
+     *
+     * <blockquote><pre>
+     * ServiceLoader.load(<i>service</i>,
+     *                    Thread.currentThread().getContextClassLoader())</pre></blockquote>
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @return A new service loader
+     */
+    public static <S> ServiceLoader<S> load(Class<S> service) {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        return ServiceLoader.load(service, cl);
+    }
+
+    /**
+     * Creates a new service loader for the given service type, using the
+     * extension class loader.
+     *
+     * <p> This convenience method simply locates the extension class loader,
+     * call it <tt><i>extClassLoader</i></tt>, and then returns
+     *
+     * <blockquote><pre>
+     * ServiceLoader.load(<i>service</i>, <i>extClassLoader</i>)</pre></blockquote>
+     *
+     * <p> If the extension class loader cannot be found then the system class
+     * loader is used; if there is no system class loader then the bootstrap
+     * class loader is used.
+     *
+     * <p> This method is intended for use when only installed providers are
+     * desired.  The resulting service will only find and load providers that
+     * have been installed into the current Java virtual machine; providers on
+     * the application's class path will be ignored.
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @return A new service loader
+     */
+    public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
+        ClassLoader prev = null;
+        while (cl != null) {
+            prev = cl;
+            cl = cl.getParent();
+        }
+        return ServiceLoader.load(service, prev);
+    }
+
+    // BEGIN Android-added: loadFromSystemProperty(), for internal use.
+    // Instantiates a class from a system property (used elsewhere in libcore).
+    /**
+     * Internal API to support built-in SPIs that check a system property first.
+     * Returns an instance specified by a property with the class' binary name, or null if
+     * no such property is set.
+     * @hide
+     */
+    public static <S> S loadFromSystemProperty(final Class<S> service) {
+        try {
+            final String className = System.getProperty(service.getName());
+            if (className != null) {
+                Class<?> c = ClassLoader.getSystemClassLoader().loadClass(className);
+                return (S) c.newInstance();
+            }
+            return null;
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+    // END Android-added: loadFromSystemProperty(), for internal use.
+
+    /**
+     * Returns a string describing this service.
+     *
+     * @return  A descriptive string
+     */
+    public String toString() {
+        return "java.util.ServiceLoader[" + service.getName() + "]";
+    }
+
+}
diff --git a/java/util/Set.annotated.java b/java/util/Set.annotated.java
new file mode 100644
index 0000000..bae8bdd
--- /dev/null
+++ b/java/util/Set.annotated.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Set<E> extends java.util.Collection<E> {
+
+public int size();
+
+public boolean isEmpty();
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o);
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator();
+
+public [email protected] Object @libcore.util.NonNull [] toArray();
+
+// TODO: Make param and return types @Nullable T @NonNull [] once metalava supports TYPE_USE.
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a);
+
+public boolean add(@libcore.util.NullFromTypeParam E e);
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o);
+
+public boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c);
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public void clear();
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o);
+
+public int hashCode();
+
[email protected] public default java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9, @libcore.util.NonNull E e10) { throw new RuntimeException("Stub!"); }
+
[email protected]
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(E @libcore.util.NonNull ... elements) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/Set.java b/java/util/Set.java
new file mode 100644
index 0000000..0499ea3
--- /dev/null
+++ b/java/util/Set.java
@@ -0,0 +1,703 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A collection that contains no duplicate elements.  More formally, sets
+ * contain no pair of elements {@code e1} and {@code e2} such that
+ * {@code e1.equals(e2)}, and at most one null element.  As implied by
+ * its name, this interface models the mathematical <i>set</i> abstraction.
+ *
+ * <p>The {@code Set} interface places additional stipulations, beyond those
+ * inherited from the {@code Collection} interface, on the contracts of all
+ * constructors and on the contracts of the {@code add}, {@code equals} and
+ * {@code hashCode} methods.  Declarations for other inherited methods are
+ * also included here for convenience.  (The specifications accompanying these
+ * declarations have been tailored to the {@code Set} interface, but they do
+ * not contain any additional stipulations.)
+ *
+ * <p>The additional stipulation on constructors is, not surprisingly,
+ * that all constructors must create a set that contains no duplicate elements
+ * (as defined above).
+ *
+ * <p>Note: Great care must be exercised if mutable objects are used as set
+ * elements.  The behavior of a set is not specified if the value of an object
+ * is changed in a manner that affects {@code equals} comparisons while the
+ * object is an element in the set.  A special case of this prohibition is
+ * that it is not permissible for a set to contain itself as an element.
+ *
+ * <p>Some set implementations have restrictions on the elements that
+ * they may contain.  For example, some implementations prohibit null elements,
+ * and some have restrictions on the types of their elements.  Attempting to
+ * add an ineligible element throws an unchecked exception, typically
+ * {@code NullPointerException} or {@code ClassCastException}.  Attempting
+ * to query the presence of an ineligible element may throw an exception,
+ * or it may simply return false; some implementations will exhibit the former
+ * behavior and some will exhibit the latter.  More generally, attempting an
+ * operation on an ineligible element whose completion would not result in
+ * the insertion of an ineligible element into the set may throw an
+ * exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <h2><a id="immutable">Immutable Set Static Factory Methods</a></h2>
+ * <p>The {@link Set#of(Object...) Set.of()} static factory methods
+ * provide a convenient way to create immutable sets. The {@code Set}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Elements cannot be added or
+ * removed. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained elements are themselves mutable, this may cause the
+ * Set to behave inconsistently or its contents to appear to change.
+ * <li>They disallow {@code null} elements. Attempts to create them with
+ * {@code null} elements result in {@code NullPointerException}.
+ * <li>They are serializable if all elements are serializable.
+ * <li>They reject duplicate elements at creation time. Duplicate elements
+ * passed to a static factory method result in {@code IllegalArgumentException}.
+ * <li>The iteration order of set elements is unspecified and is subject to change.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see List
+ * @see SortedSet
+ * @see HashSet
+ * @see TreeSet
+ * @see AbstractSet
+ * @see Collections#singleton(java.lang.Object)
+ * @see Collections#EMPTY_SET
+ * @since 1.2
+ */
+
+public interface Set<E> extends Collection<E> {
+    // Query Operations
+
+    /**
+     * Returns the number of elements in this set (its cardinality).  If this
+     * set contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @return the number of elements in this set (its cardinality)
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this set is to be tested
+     * @return {@code true} if this set contains the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this set
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         set does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns an iterator over the elements in this set.  The elements are
+     * returned in no particular order (unless this set is an instance of some
+     * class that provides a guarantee).
+     *
+     * @return an iterator over the elements in this set
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an array containing all of the elements in this set.
+     * If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the
+     * elements in the same order.
+     *
+     * <p>The returned array will be "safe" in that no references to it
+     * are maintained by this set.  (In other words, this method must
+     * allocate a new array even if this set is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all the elements in this set
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing all of the elements in this set; the
+     * runtime type of the returned array is that of the specified array.
+     * If the set fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this set.
+     *
+     * <p>If this set fits in the specified array with room to spare
+     * (i.e., the array has more elements than this set), the element in
+     * the array immediately following the end of the set is set to
+     * {@code null}.  (This is useful in determining the length of this
+     * set <i>only</i> if the caller knows that this set does not contain
+     * any null elements.)
+     *
+     * <p>If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements
+     * in the same order.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a set known to contain only strings.
+     * The following code can be used to dump the set into a newly allocated
+     * array of {@code String}:
+     *
+     * <pre>
+     *     String[] y = x.toArray(new String[0]);</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of this set are to be
+     *        stored, if it is big enough; otherwise, a new array of the same
+     *        runtime type is allocated for this purpose.
+     * @return an array containing all the elements in this set
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in this
+     *         set
+     * @throws NullPointerException if the specified array is null
+     */
+    <T> T[] toArray(T[] a);
+
+
+    // Modification Operations
+
+    /**
+     * Adds the specified element to this set if it is not already present
+     * (optional operation).  More formally, adds the specified element
+     * {@code e} to this set if the set contains no element {@code e2}
+     * such that
+     * {@code Objects.equals(e, e2)}.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.  In combination with the
+     * restriction on constructors, this ensures that sets never contain
+     * duplicate elements.
+     *
+     * <p>The stipulation above does not imply that sets must accept all
+     * elements; sets may refuse to add any particular element, including
+     * {@code null}, and throw an exception, as described in the
+     * specification for {@link Collection#add Collection.add}.
+     * Individual set implementations should clearly document any
+     * restrictions on the elements that they may contain.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the specified
+     *         element
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this set
+     * @throws NullPointerException if the specified element is null and this
+     *         set does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified element
+     *         prevents it from being added to this set
+     */
+    boolean add(E e);
+
+
+    /**
+     * Removes the specified element from this set if it is present
+     * (optional operation).  More formally, removes an element {@code e}
+     * such that
+     * {@code Objects.equals(o, e)}, if
+     * this set contains such an element.  Returns {@code true} if this set
+     * contained the element (or equivalently, if this set changed as a
+     * result of the call).  (This set will not contain the element once the
+     * call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this set
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         set does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this set
+     */
+    boolean remove(Object o);
+
+
+    // Bulk Operations
+
+    /**
+     * Returns {@code true} if this set contains all of the elements of the
+     * specified collection.  If the specified collection is also a set, this
+     * method returns {@code true} if it is a <i>subset</i> of this set.
+     *
+     * @param  c collection to be checked for containment in this set
+     * @return {@code true} if this set contains all of the elements of the
+     *         specified collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in the specified collection are incompatible with this
+     *         set
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this set does not permit null
+     *         elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see    #contains(Object)
+     */
+    boolean containsAll(Collection<?> c);
+
+    /**
+     * Adds all of the elements in the specified collection to this set if
+     * they're not already present (optional operation).  If the specified
+     * collection is also a set, the {@code addAll} operation effectively
+     * modifies this set so that its value is the <i>union</i> of the two
+     * sets.  The behavior of this operation is undefined if the specified
+     * collection is modified while the operation is in progress.
+     *
+     * @param  c collection containing elements to be added to this set
+     * @return {@code true} if this set changed as a result of the call
+     *
+     * @throws UnsupportedOperationException if the {@code addAll} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of the
+     *         specified collection prevents it from being added to this set
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this set does not permit null
+     *         elements, or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this set
+     * @see #add(Object)
+     */
+    boolean addAll(Collection<? extends E> c);
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection (optional operation).  In other words, removes
+     * from this set all of its elements that are not contained in the
+     * specified collection.  If the specified collection is also a set, this
+     * operation effectively modifies this set so that its value is the
+     * <i>intersection</i> of the two sets.
+     *
+     * @param  c collection containing elements to be retained in this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code retainAll} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    boolean retainAll(Collection<?> c);
+
+    /**
+     * Removes from this set all of its elements that are contained in the
+     * specified collection (optional operation).  If the specified
+     * collection is also a set, this operation effectively modifies this
+     * set so that its value is the <i>asymmetric set difference</i> of
+     * the two sets.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code removeAll} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean removeAll(Collection<?> c);
+
+    /**
+     * Removes all of the elements from this set (optional operation).
+     * The set will be empty after this call returns.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} method
+     *         is not supported by this set
+     */
+    void clear();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * {@code true} if the specified object is also a set, the two sets
+     * have the same size, and every member of the specified set is
+     * contained in this set (or equivalently, every member of this set is
+     * contained in the specified set).  This definition ensures that the
+     * equals method works properly across different implementations of the
+     * set interface.
+     *
+     * @param o object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this set.  The hash code of a set is
+     * defined to be the sum of the hash codes of the elements in the set,
+     * where the hash code of a {@code null} element is defined to be zero.
+     * This ensures that {@code s1.equals(s2)} implies that
+     * {@code s1.hashCode()==s2.hashCode()} for any two sets {@code s1}
+     * and {@code s2}, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * @return the hash code value for this set
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     */
+    int hashCode();
+
+    /**
+     * Creates a {@code Spliterator} over the elements in this set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#DISTINCT}.
+     * Implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the set's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the set's iterator.
+     * <p>
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SIZED}.
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, Spliterator.DISTINCT);
+    }
+
+    /**
+     * Returns an immutable set containing zero elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @return an empty {@code Set}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of() {
+        return ImmutableCollections.Set0.instance();
+    }
+
+    /**
+     * Returns an immutable set containing one element.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the single element
+     * @return a {@code Set} containing the specified element
+     * @throws NullPointerException if the element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1) {
+        return new ImmutableCollections.Set1<>(e1);
+    }
+
+    /**
+     * Returns an immutable set containing two elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if the elements are duplicates
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2) {
+        return new ImmutableCollections.Set2<>(e1, e2);
+    }
+
+    /**
+     * Returns an immutable set containing three elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3);
+    }
+
+    /**
+     * Returns an immutable set containing four elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4);
+    }
+
+    /**
+     * Returns an immutable set containing five elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5);
+    }
+
+    /**
+     * Returns an immutable set containing six elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6);
+    }
+
+    /**
+     * Returns an immutable set containing seven elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7);
+    }
+
+    /**
+     * Returns an immutable set containing eight elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8);
+    }
+
+    /**
+     * Returns an immutable set containing nine elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8, e9);
+    }
+
+    /**
+     * Returns an immutable set containing ten elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @param e10 the tenth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8, e9, e10);
+    }
+
+    /**
+     * Returns an immutable set containing an arbitrary number of elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * This method also accepts a single array as an argument. The element type of
+     * the resulting set will be the component type of the array, and the size of
+     * the set will be equal to the length of the array. To create a set with
+     * a single element that is an array, do the following:
+     *
+     * <pre>{@code
+     *     String[] array = ... ;
+     *     Set<String[]> list = Set.<String[]>of(array);
+     * }</pre>
+     *
+     * This will cause the {@link Set#of(Object) Set.of(E)} method
+     * to be invoked instead.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param elements the elements to be contained in the set
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null} or if the array is {@code null}
+     *
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <E> Set<E> of(E... elements) {
+        switch (elements.length) { // implicit null check of elements
+            case 0:
+                return ImmutableCollections.Set0.instance();
+            case 1:
+                return new ImmutableCollections.Set1<>(elements[0]);
+            case 2:
+                return new ImmutableCollections.Set2<>(elements[0], elements[1]);
+            default:
+                return new ImmutableCollections.SetN<>(elements);
+        }
+    }
+}
diff --git a/java/util/SimpleTimeZone.java b/java/util/SimpleTimeZone.java
new file mode 100644
index 0000000..ef70b96
--- /dev/null
+++ b/java/util/SimpleTimeZone.java
@@ -0,0 +1,1706 @@
+/*
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.Gregorian;
+
+/**
+ * <code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code>
+ * that represents a time zone for use with a Gregorian calendar.
+ * The class holds an offset from GMT, called <em>raw offset</em>, and start
+ * and end rules for a daylight saving time schedule.  Since it only holds
+ * single values for each, it cannot handle historical changes in the offset
+ * from GMT and the daylight saving schedule, except that the {@link
+ * #setStartYear setStartYear} method can specify the year when the daylight
+ * saving time schedule starts in effect.
+ * <p>
+ * To construct a <code>SimpleTimeZone</code> with a daylight saving time
+ * schedule, the schedule can be described with a set of rules,
+ * <em>start-rule</em> and <em>end-rule</em>. A day when daylight saving time
+ * starts or ends is specified by a combination of <em>month</em>,
+ * <em>day-of-month</em>, and <em>day-of-week</em> values. The <em>month</em>
+ * value is represented by a Calendar {@link Calendar#MONTH MONTH} field
+ * value, such as {@link Calendar#MARCH}. The <em>day-of-week</em> value is
+ * represented by a Calendar {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value,
+ * such as {@link Calendar#SUNDAY SUNDAY}. The meanings of value combinations
+ * are as follows.
+ *
+ * <ul>
+ * <li><b>Exact day of month</b><br>
+ * To specify an exact day of month, set the <em>month</em> and
+ * <em>day-of-month</em> to an exact value, and <em>day-of-week</em> to zero. For
+ * example, to specify March 1, set the <em>month</em> to {@link Calendar#MARCH
+ * MARCH}, <em>day-of-month</em> to 1, and <em>day-of-week</em> to 0.</li>
+ *
+ * <li><b>Day of week on or after day of month</b><br>
+ * To specify a day of week on or after an exact day of month, set the
+ * <em>month</em> to an exact month value, <em>day-of-month</em> to the day on
+ * or after which the rule is applied, and <em>day-of-week</em> to a negative {@link
+ * Calendar#DAY_OF_WEEK DAY_OF_WEEK} field value. For example, to specify the
+ * second Sunday of April, set <em>month</em> to {@link Calendar#APRIL APRIL},
+ * <em>day-of-month</em> to 8, and <em>day-of-week</em> to <code>-</code>{@link
+ * Calendar#SUNDAY SUNDAY}.</li>
+ *
+ * <li><b>Day of week on or before day of month</b><br>
+ * To specify a day of the week on or before an exact day of the month, set
+ * <em>day-of-month</em> and <em>day-of-week</em> to a negative value. For
+ * example, to specify the last Wednesday on or before the 21st of March, set
+ * <em>month</em> to {@link Calendar#MARCH MARCH}, <em>day-of-month</em> is -21
+ * and <em>day-of-week</em> is <code>-</code>{@link Calendar#WEDNESDAY WEDNESDAY}. </li>
+ *
+ * <li><b>Last day-of-week of month</b><br>
+ * To specify, the last day-of-week of the month, set <em>day-of-week</em> to a
+ * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value and <em>day-of-month</em> to
+ * -1. For example, to specify the last Sunday of October, set <em>month</em>
+ * to {@link Calendar#OCTOBER OCTOBER}, <em>day-of-week</em> to {@link
+ * Calendar#SUNDAY SUNDAY} and <em>day-of-month</em> to -1.  </li>
+ *
+ * </ul>
+ * The time of the day at which daylight saving time starts or ends is
+ * specified by a millisecond value within the day. There are three kinds of
+ * <em>mode</em>s to specify the time: {@link #WALL_TIME}, {@link
+ * #STANDARD_TIME} and {@link #UTC_TIME}. For example, if daylight
+ * saving time ends
+ * at 2:00 am in the wall clock time, it can be specified by 7200000
+ * milliseconds in the {@link #WALL_TIME} mode. In this case, the wall clock time
+ * for an <em>end-rule</em> means the same thing as the daylight time.
+ * <p>
+ * The following are examples of parameters for constructing time zone objects.
+ * <pre><code>
+ *      // Base GMT offset: -8:00
+ *      // DST starts:      at 2:00am in standard time
+ *      //                  on the first Sunday in April
+ *      // DST ends:        at 2:00am in daylight time
+ *      //                  on the last Sunday in October
+ *      // Save:            1 hour
+ *      SimpleTimeZone(-28800000,
+ *                     "America/Los_Angeles",
+ *                     Calendar.APRIL, 1, -Calendar.SUNDAY,
+ *                     7200000,
+ *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
+ *                     7200000,
+ *                     3600000)
+ *
+ *      // Base GMT offset: +1:00
+ *      // DST starts:      at 1:00am in UTC time
+ *      //                  on the last Sunday in March
+ *      // DST ends:        at 1:00am in UTC time
+ *      //                  on the last Sunday in October
+ *      // Save:            1 hour
+ *      SimpleTimeZone(3600000,
+ *                     "Europe/Paris",
+ *                     Calendar.MARCH, -1, Calendar.SUNDAY,
+ *                     3600000, SimpleTimeZone.UTC_TIME,
+ *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
+ *                     3600000, SimpleTimeZone.UTC_TIME,
+ *                     3600000)
+ * </code></pre>
+ * These parameter rules are also applicable to the set rule methods, such as
+ * <code>setStartRule</code>.
+ *
+ * @since 1.1
+ * @see      Calendar
+ * @see      GregorianCalendar
+ * @see      TimeZone
+ * @author   David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
+ */
+
+public class SimpleTimeZone extends TimeZone {
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from GMT
+     * and time zone ID with no daylight saving time schedule.
+     *
+     * @param rawOffset  The base time zone offset in milliseconds to GMT.
+     * @param ID         The time zone name that is given to this instance.
+     */
+    public SimpleTimeZone(int rawOffset, String ID)
+    {
+        this.rawOffset = rawOffset;
+        setID (ID);
+        dstSavings = millisPerHour; // In case user sets rules later
+    }
+
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from
+     * GMT, time zone ID, and rules for starting and ending the daylight
+     * time.
+     * Both <code>startTime</code> and <code>endTime</code> are specified to be
+     * represented in the wall clock time. The amount of daylight saving is
+     * assumed to be 3600000 milliseconds (i.e., one hour). This constructor is
+     * equivalent to:
+     * <pre><code>
+     *     SimpleTimeZone(rawOffset,
+     *                    ID,
+     *                    startMonth,
+     *                    startDay,
+     *                    startDayOfWeek,
+     *                    startTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    endMonth,
+     *                    endDay,
+     *                    endDayOfWeek,
+     *                    endTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    3600000)
+     * </code></pre>
+     *
+     * @param rawOffset       The given base time zone offset from GMT.
+     * @param ID              The time zone ID which is given to this object.
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field value (0-based. e.g., 0
+     *                        for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time (in milliseconds within the day), which is local
+     *                        standard time in this case.
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
+     * parameters are out of range for the start or end rule
+     */
+    public SimpleTimeZone(int rawOffset, String ID,
+                          int startMonth, int startDay, int startDayOfWeek, int startTime,
+                          int endMonth, int endDay, int endDayOfWeek, int endTime)
+    {
+        this(rawOffset, ID,
+             startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
+             endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
+             millisPerHour);
+    }
+
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from
+     * GMT, time zone ID, and rules for starting and ending the daylight
+     * time.
+     * Both <code>startTime</code> and <code>endTime</code> are assumed to be
+     * represented in the wall clock time. This constructor is equivalent to:
+     * <pre><code>
+     *     SimpleTimeZone(rawOffset,
+     *                    ID,
+     *                    startMonth,
+     *                    startDay,
+     *                    startDayOfWeek,
+     *                    startTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    endMonth,
+     *                    endDay,
+     *                    endDayOfWeek,
+     *                    endTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    dstSavings)
+     * </code></pre>
+     *
+     * @param rawOffset       The given base time zone offset from GMT.
+     * @param ID              The time zone ID which is given to this object.
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        which is local daylight time in this case.
+     * @param dstSavings      The amount of time in milliseconds saved during
+     *                        daylight saving time.
+     * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
+     * parameters are out of range for the start or end rule
+     * @since 1.2
+     */
+    public SimpleTimeZone(int rawOffset, String ID,
+                          int startMonth, int startDay, int startDayOfWeek, int startTime,
+                          int endMonth, int endDay, int endDayOfWeek, int endTime,
+                          int dstSavings)
+    {
+        this(rawOffset, ID,
+             startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
+             endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
+             dstSavings);
+    }
+
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from
+     * GMT, time zone ID, and rules for starting and ending the daylight
+     * time.
+     * This constructor takes the full set of the start and end rules
+     * parameters, including modes of <code>startTime</code> and
+     * <code>endTime</code>. The mode specifies either {@link #WALL_TIME wall
+     * time} or {@link #STANDARD_TIME standard time} or {@link #UTC_TIME UTC
+     * time}.
+     *
+     * @param rawOffset       The given base time zone offset from GMT.
+     * @param ID              The time zone ID which is given to this object.
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in the time mode
+     *                        specified by <code>startTimeMode</code>.
+     * @param startTimeMode   The mode of the start time specified by startTime.
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in time time mode
+     *                        specified by <code>endTimeMode</code>.
+     * @param endTimeMode     The mode of the end time specified by endTime
+     * @param dstSavings      The amount of time in milliseconds saved during
+     *                        daylight saving time.
+     *
+     * @exception IllegalArgumentException if the month, day, dayOfWeek, time more, or
+     * time parameters are out of range for the start or end rule, or if a time mode
+     * value is invalid.
+     *
+     * @see #WALL_TIME
+     * @see #STANDARD_TIME
+     * @see #UTC_TIME
+     *
+     * @since 1.4
+     */
+    public SimpleTimeZone(int rawOffset, String ID,
+                          int startMonth, int startDay, int startDayOfWeek,
+                          int startTime, int startTimeMode,
+                          int endMonth, int endDay, int endDayOfWeek,
+                          int endTime, int endTimeMode,
+                          int dstSavings) {
+
+        setID(ID);
+        this.rawOffset      = rawOffset;
+        this.startMonth     = startMonth;
+        this.startDay       = startDay;
+        this.startDayOfWeek = startDayOfWeek;
+        this.startTime      = startTime;
+        this.startTimeMode  = startTimeMode;
+        this.endMonth       = endMonth;
+        this.endDay         = endDay;
+        this.endDayOfWeek   = endDayOfWeek;
+        this.endTime        = endTime;
+        this.endTimeMode    = endTimeMode;
+        this.dstSavings     = dstSavings;
+
+        // this.useDaylight is set by decodeRules
+        decodeRules();
+        if (dstSavings <= 0) {
+            throw new IllegalArgumentException("Illegal daylight saving value: " + dstSavings);
+        }
+    }
+
+    /**
+     * Sets the daylight saving time starting year.
+     *
+     * @param year  The daylight saving starting year.
+     */
+    public void setStartYear(int year)
+    {
+        startYear = year;
+        invalidateCache();
+    }
+
+    /**
+     * Sets the daylight saving time start rule. For example, if daylight saving
+     * time starts on the first Sunday in April at 2 am in local wall clock
+     * time, you can set the start rule by calling:
+     * <pre><code>setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);</code></pre>
+     *
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
+     * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
+     */
+    public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int startTime)
+    {
+        this.startMonth = startMonth;
+        this.startDay = startDay;
+        this.startDayOfWeek = startDayOfWeek;
+        this.startTime = startTime;
+        startTimeMode = WALL_TIME;
+        decodeStartRule();
+        invalidateCache();
+    }
+
+    /**
+     * Sets the daylight saving time start rule to a fixed date within a month.
+     * This method is equivalent to:
+     * <pre><code>setStartRule(startMonth, startDay, 0, startTime)</code></pre>
+     *
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     *                        See the class description for the special cases of this parameter.
+     * @exception IllegalArgumentException if the <code>startMonth</code>,
+     * <code>startDayOfMonth</code>, or <code>startTime</code> parameters are out of range
+     * @since 1.2
+     */
+    public void setStartRule(int startMonth, int startDay, int startTime) {
+        setStartRule(startMonth, startDay, 0, startTime);
+    }
+
+    /**
+     * Sets the daylight saving time start rule to a weekday before or after the given date within
+     * a month, e.g., the first Monday on or after the 8th.
+     *
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     * @param after           If true, this rule selects the first <code>dayOfWeek</code> on or
+     *                        <em>after</em> <code>dayOfMonth</code>.  If false, this rule
+     *                        selects the last <code>dayOfWeek</code> on or <em>before</em>
+     *                        <code>dayOfMonth</code>.
+     * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
+     * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
+     * @since 1.2
+     */
+    public void setStartRule(int startMonth, int startDay, int startDayOfWeek,
+                             int startTime, boolean after)
+    {
+        // TODO: this method doesn't check the initial values of dayOfMonth or dayOfWeek.
+        if (after) {
+            setStartRule(startMonth, startDay, -startDayOfWeek, startTime);
+        } else {
+            setStartRule(startMonth, -startDay, -startDayOfWeek, startTime);
+        }
+    }
+
+    /**
+     * Sets the daylight saving time end rule. For example, if daylight saving time
+     * ends on the last Sunday in October at 2 am in wall clock time,
+     * you can set the end rule by calling:
+     * <code>setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);</code>
+     *
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @exception IllegalArgumentException if the <code>endMonth</code>, <code>endDay</code>,
+     * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
+     */
+    public void setEndRule(int endMonth, int endDay, int endDayOfWeek,
+                           int endTime)
+    {
+        this.endMonth = endMonth;
+        this.endDay = endDay;
+        this.endDayOfWeek = endDayOfWeek;
+        this.endTime = endTime;
+        this.endTimeMode = WALL_TIME;
+        decodeEndRule();
+        invalidateCache();
+    }
+
+    /**
+     * Sets the daylight saving time end rule to a fixed date within a month.
+     * This method is equivalent to:
+     * <pre><code>setEndRule(endMonth, endDay, 0, endTime)</code></pre>
+     *
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
+     * or <code>endTime</code> parameters are out of range
+     * @since 1.2
+     */
+    public void setEndRule(int endMonth, int endDay, int endTime)
+    {
+        setEndRule(endMonth, endDay, 0, endTime);
+    }
+
+    /**
+     * Sets the daylight saving time end rule to a weekday before or after the given date within
+     * a month, e.g., the first Monday on or after the 8th.
+     *
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @param after           If true, this rule selects the first <code>endDayOfWeek</code> on
+     *                        or <em>after</em> <code>endDay</code>.  If false, this rule
+     *                        selects the last <code>endDayOfWeek</code> on or before
+     *                        <code>endDay</code> of the month.
+     * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
+     * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
+     * @since 1.2
+     */
+    public void setEndRule(int endMonth, int endDay, int endDayOfWeek, int endTime, boolean after)
+    {
+        if (after) {
+            setEndRule(endMonth, endDay, -endDayOfWeek, endTime);
+        } else {
+            setEndRule(endMonth, -endDay, -endDayOfWeek, endTime);
+        }
+    }
+
+    /**
+     * Returns the offset of this time zone from UTC at the given
+     * time. If daylight saving time is in effect at the given time,
+     * the offset value is adjusted with the amount of daylight
+     * saving.
+     *
+     * @param date the time at which the time zone offset is found
+     * @return the amount of time in milliseconds to add to UTC to get
+     * local time.
+     * @since 1.4
+     */
+    public int getOffset(long date) {
+        return getOffsets(date, null);
+    }
+
+    /**
+     * @see TimeZone#getOffsets
+     */
+    int getOffsets(long date, int[] offsets) {
+        int offset = rawOffset;
+
+      computeOffset:
+        if (useDaylight) {
+            synchronized (this) {
+                if (cacheStart != 0) {
+                    if (date >= cacheStart && date < cacheEnd) {
+                        offset += dstSavings;
+                        break computeOffset;
+                    }
+                }
+            }
+            BaseCalendar cal = date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ?
+                gcal : (BaseCalendar) CalendarSystem.forName("julian");
+            BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+            // Get the year in local time
+            cal.getCalendarDate(date + rawOffset, cdate);
+            int year = cdate.getNormalizedYear();
+            if (year >= startYear) {
+                // Clear time elements for the transition calculations
+                cdate.setTimeOfDay(0, 0, 0, 0);
+                offset = getOffset(cal, cdate, year, date);
+            }
+        }
+
+        if (offsets != null) {
+            offsets[0] = rawOffset;
+            offsets[1] = offset - rawOffset;
+        }
+        return offset;
+    }
+
+   /**
+     * Returns the difference in milliseconds between local time and
+     * UTC, taking into account both the raw offset and the effect of
+     * daylight saving, for the specified date and time.  This method
+     * assumes that the start and end month are distinct.  It also
+     * uses a default {@link GregorianCalendar} object as its
+     * underlying calendar, such as for determining leap years.  Do
+     * not use the result of this method with a calendar other than a
+     * default <code>GregorianCalendar</code>.
+     *
+     * <p><em>Note:  In general, clients should use
+     * <code>Calendar.get(ZONE_OFFSET) + Calendar.get(DST_OFFSET)</code>
+     * instead of calling this method.</em>
+     *
+     * @param era       The era of the given date.
+     * @param year      The year in the given date.
+     * @param month     The month in the given date. Month is 0-based. e.g.,
+     *                  0 for January.
+     * @param day       The day-in-month of the given date.
+     * @param dayOfWeek The day-of-week of the given date.
+     * @param millis    The milliseconds in day in <em>standard</em> local time.
+     * @return          The milliseconds to add to UTC to get local time.
+     * @exception       IllegalArgumentException the <code>era</code>,
+     *                  <code>month</code>, <code>day</code>, <code>dayOfWeek</code>,
+     *                  or <code>millis</code> parameters are out of range
+     */
+    public int getOffset(int era, int year, int month, int day, int dayOfWeek,
+                         int millis)
+    {
+        if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) {
+            throw new IllegalArgumentException("Illegal era " + era);
+        }
+
+        int y = year;
+        if (era == GregorianCalendar.BC) {
+            // adjust y with the GregorianCalendar-style year numbering.
+            y = 1 - y;
+        }
+
+        // If the year isn't representable with the 64-bit long
+        // integer in milliseconds, convert the year to an
+        // equivalent year. This is required to pass some JCK test cases
+        // which are actually useless though because the specified years
+        // can't be supported by the Java time system.
+        if (y >= 292278994) {
+            y = 2800 + y % 2800;
+        } else if (y <= -292269054) {
+            // y %= 28 also produces an equivalent year, but positive
+            // year numbers would be convenient to use the UNIX cal
+            // command.
+            y = (int) CalendarUtils.mod((long) y, 28);
+        }
+
+        // convert year to its 1-based month value
+        int m = month + 1;
+
+        // First, calculate time as a Gregorian date.
+        BaseCalendar cal = gcal;
+        BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        cdate.setDate(y, m, day);
+        long time = cal.getTime(cdate); // normalize cdate
+        time += millis - rawOffset; // UTC time
+
+        // If the time value represents a time before the default
+        // Gregorian cutover, recalculate time using the Julian
+        // calendar system. For the Julian calendar system, the
+        // normalized year numbering is ..., -2 (BCE 2), -1 (BCE 1),
+        // 1, 2 ... which is different from the GregorianCalendar
+        // style year numbering (..., -1, 0 (BCE 1), 1, 2, ...).
+        if (time < GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER) {
+            cal = (BaseCalendar) CalendarSystem.forName("julian");
+            cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+            cdate.setNormalizedDate(y, m, day);
+            time = cal.getTime(cdate) + millis - rawOffset;
+        }
+
+        if ((cdate.getNormalizedYear() != y)
+            || (cdate.getMonth() != m)
+            || (cdate.getDayOfMonth() != day)
+            // The validation should be cdate.getDayOfWeek() ==
+            // dayOfWeek. However, we don't check dayOfWeek for
+            // compatibility.
+            || (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
+            || (millis < 0 || millis >= (24*60*60*1000))) {
+            throw new IllegalArgumentException();
+        }
+
+        if (!useDaylight || year < startYear || era != GregorianCalendar.CE) {
+            return rawOffset;
+        }
+
+        return getOffset(cal, cdate, y, time);
+    }
+
+    private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long time) {
+        synchronized (this) {
+            if (cacheStart != 0) {
+                if (time >= cacheStart && time < cacheEnd) {
+                    return rawOffset + dstSavings;
+                }
+                if (year == cacheYear) {
+                    return rawOffset;
+                }
+            }
+        }
+
+        long start = getStart(cal, cdate, year);
+        long end = getEnd(cal, cdate, year);
+        int offset = rawOffset;
+        if (start <= end) {
+            if (time >= start && time < end) {
+                offset += dstSavings;
+            }
+            synchronized (this) {
+                cacheYear = year;
+                cacheStart = start;
+                cacheEnd = end;
+            }
+        } else {
+            if (time < end) {
+                // TODO: support Gregorian cutover. The previous year
+                // may be in the other calendar system.
+                start = getStart(cal, cdate, year - 1);
+                if (time >= start) {
+                    offset += dstSavings;
+                }
+            } else if (time >= start) {
+                // TODO: support Gregorian cutover. The next year
+                // may be in the other calendar system.
+                end = getEnd(cal, cdate, year + 1);
+                if (time < end) {
+                    offset += dstSavings;
+                }
+            }
+            if (start <= end) {
+                synchronized (this) {
+                    // The start and end transitions are in multiple years.
+                    cacheYear = (long) startYear - 1;
+                    cacheStart = start;
+                    cacheEnd = end;
+                }
+            }
+        }
+        return offset;
+    }
+
+    private long getStart(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
+        int time = startTime;
+        if (startTimeMode != UTC_TIME) {
+            time -= rawOffset;
+        }
+        return getTransition(cal, cdate, startMode, year, startMonth, startDay,
+                             startDayOfWeek, time);
+    }
+
+    private long getEnd(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
+        int time = endTime;
+        if (endTimeMode != UTC_TIME) {
+            time -= rawOffset;
+        }
+        if (endTimeMode == WALL_TIME) {
+            time -= dstSavings;
+        }
+        return getTransition(cal, cdate, endMode, year, endMonth, endDay,
+                                        endDayOfWeek, time);
+    }
+
+    private long getTransition(BaseCalendar cal, BaseCalendar.Date cdate,
+                               int mode, int year, int month, int dayOfMonth,
+                               int dayOfWeek, int timeOfDay) {
+        cdate.setNormalizedYear(year);
+        cdate.setMonth(month + 1);
+        switch (mode) {
+        case DOM_MODE:
+            cdate.setDayOfMonth(dayOfMonth);
+            break;
+
+        case DOW_IN_MONTH_MODE:
+            cdate.setDayOfMonth(1);
+            if (dayOfMonth < 0) {
+                cdate.setDayOfMonth(cal.getMonthLength(cdate));
+            }
+            cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(dayOfMonth, dayOfWeek, cdate);
+            break;
+
+        case DOW_GE_DOM_MODE:
+            cdate.setDayOfMonth(dayOfMonth);
+            cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(1, dayOfWeek, cdate);
+            break;
+
+        case DOW_LE_DOM_MODE:
+            cdate.setDayOfMonth(dayOfMonth);
+            cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(-1, dayOfWeek, cdate);
+            break;
+        }
+        return cal.getTime(cdate) + timeOfDay;
+    }
+
+    /**
+     * Gets the GMT offset for this time zone.
+     * @return the GMT offset value in milliseconds
+     * @see #setRawOffset
+     */
+    public int getRawOffset()
+    {
+        // The given date will be taken into account while
+        // we have the historical time zone data in place.
+        return rawOffset;
+    }
+
+    /**
+     * Sets the base time zone offset to GMT.
+     * This is the offset to add to UTC to get local time.
+     * @see #getRawOffset
+     */
+    public void setRawOffset(int offsetMillis)
+    {
+        this.rawOffset = offsetMillis;
+    }
+
+    /**
+     * Sets the amount of time in milliseconds that the clock is advanced
+     * during daylight saving time.
+     * @param millisSavedDuringDST the number of milliseconds the time is
+     * advanced with respect to standard time when the daylight saving time rules
+     * are in effect. A positive number, typically one hour (3600000).
+     * @see #getDSTSavings
+     * @since 1.2
+     */
+    public void setDSTSavings(int millisSavedDuringDST) {
+        if (millisSavedDuringDST <= 0) {
+            throw new IllegalArgumentException("Illegal daylight saving value: "
+                                               + millisSavedDuringDST);
+        }
+        dstSavings = millisSavedDuringDST;
+    }
+
+    /**
+     * Returns the amount of time in milliseconds that the clock is
+     * advanced during daylight saving time.
+     *
+     * @return the number of milliseconds the time is advanced with
+     * respect to standard time when the daylight saving rules are in
+     * effect, or 0 (zero) if this time zone doesn't observe daylight
+     * saving time.
+     *
+     * @see #setDSTSavings
+     * @since 1.2
+     */
+    public int getDSTSavings() {
+        return useDaylight ? dstSavings : 0;
+    }
+
+    /**
+     * Queries if this time zone uses daylight saving time.
+     * @return true if this time zone uses daylight saving time;
+     * false otherwise.
+     */
+    public boolean useDaylightTime()
+    {
+        return useDaylight;
+    }
+
+    /**
+     * Returns {@code true} if this {@code SimpleTimeZone} observes
+     * Daylight Saving Time. This method is equivalent to {@link
+     * #useDaylightTime()}.
+     *
+     * @return {@code true} if this {@code SimpleTimeZone} observes
+     * Daylight Saving Time; {@code false} otherwise.
+     * @since 1.7
+     */
+    @Override
+    public boolean observesDaylightTime() {
+        return useDaylightTime();
+    }
+
+    /**
+     * Queries if the given date is in daylight saving time.
+     * @return true if daylight saving time is in effective at the
+     * given date; false otherwise.
+     */
+    public boolean inDaylightTime(Date date)
+    {
+        return (getOffset(date.getTime()) != rawOffset);
+    }
+
+    /**
+     * Returns a clone of this <code>SimpleTimeZone</code> instance.
+     * @return a clone of this instance.
+     */
+    public Object clone()
+    {
+        return super.clone();
+    }
+
+    /**
+     * Generates the hash code for the SimpleDateFormat object.
+     * @return the hash code for this object
+     */
+    public synchronized int hashCode()
+    {
+        return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^
+            endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset;
+    }
+
+    /**
+     * Compares the equality of two <code>SimpleTimeZone</code> objects.
+     *
+     * @param obj  The <code>SimpleTimeZone</code> object to be compared with.
+     * @return     True if the given <code>obj</code> is the same as this
+     *             <code>SimpleTimeZone</code> object; false otherwise.
+     */
+    public boolean equals(Object obj)
+    {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof SimpleTimeZone)) {
+            return false;
+        }
+
+        SimpleTimeZone that = (SimpleTimeZone) obj;
+
+        return getID().equals(that.getID()) &&
+            hasSameRules(that);
+    }
+
+    /**
+     * Returns <code>true</code> if this zone has the same rules and offset as another zone.
+     * @param other the TimeZone object to be compared with
+     * @return <code>true</code> if the given zone is a SimpleTimeZone and has the
+     * same rules and offset as this one
+     * @since 1.2
+     */
+    public boolean hasSameRules(TimeZone other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof SimpleTimeZone)) {
+            return false;
+        }
+        SimpleTimeZone that = (SimpleTimeZone) other;
+        return rawOffset == that.rawOffset &&
+            useDaylight == that.useDaylight &&
+            (!useDaylight
+             // Only check rules if using DST
+             || (dstSavings == that.dstSavings &&
+                 startMode == that.startMode &&
+                 startMonth == that.startMonth &&
+                 startDay == that.startDay &&
+                 startDayOfWeek == that.startDayOfWeek &&
+                 startTime == that.startTime &&
+                 startTimeMode == that.startTimeMode &&
+                 endMode == that.endMode &&
+                 endMonth == that.endMonth &&
+                 endDay == that.endDay &&
+                 endDayOfWeek == that.endDayOfWeek &&
+                 endTime == that.endTime &&
+                 endTimeMode == that.endTimeMode &&
+                 startYear == that.startYear));
+    }
+
+    /**
+     * Returns a string representation of this time zone.
+     * @return a string representation of this time zone.
+     */
+    public String toString() {
+        return getClass().getName() +
+            "[id=" + getID() +
+            ",offset=" + rawOffset +
+            ",dstSavings=" + dstSavings +
+            ",useDaylight=" + useDaylight +
+            ",startYear=" + startYear +
+            ",startMode=" + startMode +
+            ",startMonth=" + startMonth +
+            ",startDay=" + startDay +
+            ",startDayOfWeek=" + startDayOfWeek +
+            ",startTime=" + startTime +
+            ",startTimeMode=" + startTimeMode +
+            ",endMode=" + endMode +
+            ",endMonth=" + endMonth +
+            ",endDay=" + endDay +
+            ",endDayOfWeek=" + endDayOfWeek +
+            ",endTime=" + endTime +
+            ",endTimeMode=" + endTimeMode + ']';
+    }
+
+    // =======================privates===============================
+
+    /**
+     * The month in which daylight saving time starts.  This value must be
+     * between <code>Calendar.JANUARY</code> and
+     * <code>Calendar.DECEMBER</code> inclusive.  This value must not equal
+     * <code>endMonth</code>.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int startMonth;
+
+    /**
+     * This field has two possible interpretations:
+     * <dl>
+     * <dt><code>startMode == DOW_IN_MONTH</code></dt>
+     * <dd>
+     * <code>startDay</code> indicates the day of the month of
+     * <code>startMonth</code> on which daylight
+     * saving time starts, from 1 to 28, 30, or 31, depending on the
+     * <code>startMonth</code>.
+     * </dd>
+     * <dt><code>startMode != DOW_IN_MONTH</code></dt>
+     * <dd>
+     * <code>startDay</code> indicates which <code>startDayOfWeek</code> in the
+     * month <code>startMonth</code> daylight
+     * saving time starts on.  For example, a value of +1 and a
+     * <code>startDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
+     * first Sunday of <code>startMonth</code>.  Likewise, +2 would indicate the
+     * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
+     * </dd>
+     * </dl>
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int startDay;
+
+    /**
+     * The day of the week on which daylight saving time starts.  This value
+     * must be between <code>Calendar.SUNDAY</code> and
+     * <code>Calendar.SATURDAY</code> inclusive.
+     * <p>If <code>useDaylight</code> is false or
+     * <code>startMode == DAY_OF_MONTH</code>, this value is ignored.
+     * @serial
+     */
+    private int startDayOfWeek;
+
+    /**
+     * The time in milliseconds after midnight at which daylight saving
+     * time starts.  This value is expressed as wall time, standard time,
+     * or UTC time, depending on the setting of <code>startTimeMode</code>.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int startTime;
+
+    /**
+     * The format of startTime, either WALL_TIME, STANDARD_TIME, or UTC_TIME.
+     * @serial
+     * @since 1.3
+     */
+    private int startTimeMode;
+
+    /**
+     * The month in which daylight saving time ends.  This value must be
+     * between <code>Calendar.JANUARY</code> and
+     * <code>Calendar.UNDECIMBER</code>.  This value must not equal
+     * <code>startMonth</code>.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int endMonth;
+
+    /**
+     * This field has two possible interpretations:
+     * <dl>
+     * <dt><code>endMode == DOW_IN_MONTH</code></dt>
+     * <dd>
+     * <code>endDay</code> indicates the day of the month of
+     * <code>endMonth</code> on which daylight
+     * saving time ends, from 1 to 28, 30, or 31, depending on the
+     * <code>endMonth</code>.
+     * </dd>
+     * <dt><code>endMode != DOW_IN_MONTH</code></dt>
+     * <dd>
+     * <code>endDay</code> indicates which <code>endDayOfWeek</code> in th
+     * month <code>endMonth</code> daylight
+     * saving time ends on.  For example, a value of +1 and a
+     * <code>endDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
+     * first Sunday of <code>endMonth</code>.  Likewise, +2 would indicate the
+     * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
+     * </dd>
+     * </dl>
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int endDay;
+
+    /**
+     * The day of the week on which daylight saving time ends.  This value
+     * must be between <code>Calendar.SUNDAY</code> and
+     * <code>Calendar.SATURDAY</code> inclusive.
+     * <p>If <code>useDaylight</code> is false or
+     * <code>endMode == DAY_OF_MONTH</code>, this value is ignored.
+     * @serial
+     */
+    private int endDayOfWeek;
+
+    /**
+     * The time in milliseconds after midnight at which daylight saving
+     * time ends.  This value is expressed as wall time, standard time,
+     * or UTC time, depending on the setting of <code>endTimeMode</code>.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int endTime;
+
+    /**
+     * The format of endTime, either <code>WALL_TIME</code>,
+     * <code>STANDARD_TIME</code>, or <code>UTC_TIME</code>.
+     * @serial
+     * @since 1.3
+     */
+    private int endTimeMode;
+
+    /**
+     * The year in which daylight saving time is first observed.  This is an {@link GregorianCalendar#AD AD}
+     * value.  If this value is less than 1 then daylight saving time is observed
+     * for all <code>AD</code> years.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int startYear;
+
+    /**
+     * The offset in milliseconds between this zone and GMT.  Negative offsets
+     * are to the west of Greenwich.  To obtain local <em>standard</em> time,
+     * add the offset to GMT time.  To obtain local wall time it may also be
+     * necessary to add <code>dstSavings</code>.
+     * @serial
+     */
+    private int rawOffset;
+
+    /**
+     * A boolean value which is true if and only if this zone uses daylight
+     * saving time.  If this value is false, several other fields are ignored.
+     * @serial
+     */
+    private boolean useDaylight=false; // indicate if this time zone uses DST
+
+    private static final int millisPerHour = 60*60*1000;
+    private static final int millisPerDay  = 24*millisPerHour;
+
+    /**
+     * This field was serialized in JDK 1.1, so we have to keep it that way
+     * to maintain serialization compatibility. However, there's no need to
+     * recreate the array each time we create a new time zone.
+     * @serial An array of bytes containing the values {31, 28, 31, 30, 31, 30,
+     * 31, 31, 30, 31, 30, 31}.  This is ignored as of the Java 2 platform v1.2, however, it must
+     * be streamed out for compatibility with JDK 1.1.
+     */
+    private final byte monthLength[] = staticMonthLength;
+    private final static byte staticMonthLength[] = {31,28,31,30,31,30,31,31,30,31,30,31};
+    private final static byte staticLeapMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31};
+
+    /**
+     * Variables specifying the mode of the start rule.  Takes the following
+     * values:
+     * <dl>
+     * <dt><code>DOM_MODE</code></dt>
+     * <dd>
+     * Exact day of week; e.g., March 1.
+     * </dd>
+     * <dt><code>DOW_IN_MONTH_MODE</code></dt>
+     * <dd>
+     * Day of week in month; e.g., last Sunday in March.
+     * </dd>
+     * <dt><code>DOW_GE_DOM_MODE</code></dt>
+     * <dd>
+     * Day of week after day of month; e.g., Sunday on or after March 15.
+     * </dd>
+     * <dt><code>DOW_LE_DOM_MODE</code></dt>
+     * <dd>
+     * Day of week before day of month; e.g., Sunday on or before March 15.
+     * </dd>
+     * </dl>
+     * The setting of this field affects the interpretation of the
+     * <code>startDay</code> field.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     * @since 1.1.4
+     */
+    private int startMode;
+
+    /**
+     * Variables specifying the mode of the end rule.  Takes the following
+     * values:
+     * <dl>
+     * <dt><code>DOM_MODE</code></dt>
+     * <dd>
+     * Exact day of week; e.g., March 1.
+     * </dd>
+     * <dt><code>DOW_IN_MONTH_MODE</code></dt>
+     * <dd>
+     * Day of week in month; e.g., last Sunday in March.
+     * </dd>
+     * <dt><code>DOW_GE_DOM_MODE</code></dt>
+     * <dd>
+     * Day of week after day of month; e.g., Sunday on or after March 15.
+     * </dd>
+     * <dt><code>DOW_LE_DOM_MODE</code></dt>
+     * <dd>
+     * Day of week before day of month; e.g., Sunday on or before March 15.
+     * </dd>
+     * </dl>
+     * The setting of this field affects the interpretation of the
+     * <code>endDay</code> field.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     * @since 1.1.4
+     */
+    private int endMode;
+
+    /**
+     * A positive value indicating the amount of time saved during DST in
+     * milliseconds.
+     * Typically one hour (3600000); sometimes 30 minutes (1800000).
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     * @since 1.1.4
+     */
+    private int dstSavings;
+
+    private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
+
+    /**
+     * Cache values representing a single period of daylight saving
+     * time. When the cache values are valid, cacheStart is the start
+     * time (inclusive) of daylight saving time and cacheEnd is the
+     * end time (exclusive).
+     *
+     * cacheYear has a year value if both cacheStart and cacheEnd are
+     * in the same year. cacheYear is set to startYear - 1 if
+     * cacheStart and cacheEnd are in different years. cacheStart is 0
+     * if the cache values are void. cacheYear is a long to support
+     * Integer.MIN_VALUE - 1 (JCK requirement).
+     */
+    private transient long cacheYear;
+    private transient long cacheStart;
+    private transient long cacheEnd;
+
+    /**
+     * Constants specifying values of startMode and endMode.
+     */
+    private static final int DOM_MODE          = 1; // Exact day of month, "Mar 1"
+    private static final int DOW_IN_MONTH_MODE = 2; // Day of week in month, "lastSun"
+    private static final int DOW_GE_DOM_MODE   = 3; // Day of week after day of month, "Sun>=15"
+    private static final int DOW_LE_DOM_MODE   = 4; // Day of week before day of month, "Sun<=21"
+
+    /**
+     * Constant for a mode of start or end time specified as wall clock
+     * time.  Wall clock time is standard time for the onset rule, and
+     * daylight time for the end rule.
+     * @since 1.4
+     */
+    public static final int WALL_TIME = 0; // Zero for backward compatibility
+
+    /**
+     * Constant for a mode of start or end time specified as standard time.
+     * @since 1.4
+     */
+    public static final int STANDARD_TIME = 1;
+
+    /**
+     * Constant for a mode of start or end time specified as UTC. European
+     * Union rules are specified as UTC time, for example.
+     * @since 1.4
+     */
+    public static final int UTC_TIME = 2;
+
+    // Proclaim compatibility with 1.1
+    static final long serialVersionUID = -403250971215465050L;
+
+    // the internal serial version which says which version was written
+    // - 0 (default) for version up to JDK 1.1.3
+    // - 1 for version from JDK 1.1.4, which includes 3 new fields
+    // - 2 for JDK 1.3, which includes 2 new fields
+    static final int currentSerialVersion = 2;
+
+    /**
+     * The version of the serialized data on the stream.  Possible values:
+     * <dl>
+     * <dt><b>0</b> or not present on stream</dt>
+     * <dd>
+     * JDK 1.1.3 or earlier.
+     * </dd>
+     * <dt><b>1</b></dt>
+     * <dd>
+     * JDK 1.1.4 or later.  Includes three new fields: <code>startMode</code>,
+     * <code>endMode</code>, and <code>dstSavings</code>.
+     * </dd>
+     * <dt><b>2</b></dt>
+     * <dd>
+     * JDK 1.3 or later.  Includes two new fields: <code>startTimeMode</code>
+     * and <code>endTimeMode</code>.
+     * </dd>
+     * </dl>
+     * When streaming out this class, the most recent format
+     * and the highest allowable <code>serialVersionOnStream</code>
+     * is written.
+     * @serial
+     * @since 1.1.4
+     */
+    private int serialVersionOnStream = currentSerialVersion;
+
+    synchronized private void invalidateCache() {
+        cacheYear = startYear - 1;
+        cacheStart = cacheEnd = 0;
+    }
+
+    //----------------------------------------------------------------------
+    // Rule representation
+    //
+    // We represent the following flavors of rules:
+    //       5        the fifth of the month
+    //       lastSun  the last Sunday in the month
+    //       lastMon  the last Monday in the month
+    //       Sun>=8   first Sunday on or after the eighth
+    //       Sun<=25  last Sunday on or before the 25th
+    // This is further complicated by the fact that we need to remain
+    // backward compatible with the 1.1 FCS.  Finally, we need to minimize
+    // API changes.  In order to satisfy these requirements, we support
+    // three representation systems, and we translate between them.
+    //
+    // INTERNAL REPRESENTATION
+    // This is the format SimpleTimeZone objects take after construction or
+    // streaming in is complete.  Rules are represented directly, using an
+    // unencoded format.  We will discuss the start rule only below; the end
+    // rule is analogous.
+    //   startMode      Takes on enumerated values DAY_OF_MONTH,
+    //                  DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
+    //   startDay       The day of the month, or for DOW_IN_MONTH mode, a
+    //                  value indicating which DOW, such as +1 for first,
+    //                  +2 for second, -1 for last, etc.
+    //   startDayOfWeek The day of the week.  Ignored for DAY_OF_MONTH.
+    //
+    // ENCODED REPRESENTATION
+    // This is the format accepted by the constructor and by setStartRule()
+    // and setEndRule().  It uses various combinations of positive, negative,
+    // and zero values to encode the different rules.  This representation
+    // allows us to specify all the different rule flavors without altering
+    // the API.
+    //   MODE              startMonth    startDay    startDayOfWeek
+    //   DOW_IN_MONTH_MODE >=0           !=0         >0
+    //   DOM_MODE          >=0           >0          ==0
+    //   DOW_GE_DOM_MODE   >=0           >0          <0
+    //   DOW_LE_DOM_MODE   >=0           <0          <0
+    //   (no DST)          don't care    ==0         don't care
+    //
+    // STREAMED REPRESENTATION
+    // We must retain binary compatibility with the 1.1 FCS.  The 1.1 code only
+    // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
+    // flag useDaylight.  When we stream an object out, we translate into an
+    // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
+    // and used by 1.1 code.  Following that, we write out the full
+    // representation separately so that contemporary code can recognize and
+    // parse it.  The full representation is written in a "packed" format,
+    // consisting of a version number, a length, and an array of bytes.  Future
+    // versions of this class may specify different versions.  If they wish to
+    // include additional data, they should do so by storing them after the
+    // packed representation below.
+    //----------------------------------------------------------------------
+
+    /**
+     * Given a set of encoded rules in startDay and startDayOfMonth, decode
+     * them and set the startMode appropriately.  Do the same for endDay and
+     * endDayOfMonth.  Upon entry, the day of week variables may be zero or
+     * negative, in order to indicate special modes.  The day of month
+     * variables may also be negative.  Upon exit, the mode variables will be
+     * set, and the day of week and day of month variables will be positive.
+     * This method also recognizes a startDay or endDay of zero as indicating
+     * no DST.
+     */
+    private void decodeRules()
+    {
+        decodeStartRule();
+        decodeEndRule();
+    }
+
+    /**
+     * Decode the start rule and validate the parameters.  The parameters are
+     * expected to be in encoded form, which represents the various rule modes
+     * by negating or zeroing certain values.  Representation formats are:
+     * <p>
+     * <pre>
+     *            DOW_IN_MONTH  DOM    DOW>=DOM  DOW<=DOM  no DST
+     *            ------------  -----  --------  --------  ----------
+     * month       0..11        same    same      same     don't care
+     * day        -5..5         1..31   1..31    -1..-31   0
+     * dayOfWeek   1..7         0      -1..-7    -1..-7    don't care
+     * time        0..ONEDAY    same    same      same     don't care
+     * </pre>
+     * The range for month does not include UNDECIMBER since this class is
+     * really specific to GregorianCalendar, which does not use that month.
+     * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
+     * end rule is an exclusive limit point.  That is, the range of times that
+     * are in DST include those >= the start and < the end.  For this reason,
+     * it should be possible to specify an end of ONEDAY in order to include the
+     * entire day.  Although this is equivalent to time 0 of the following day,
+     * it's not always possible to specify that, for example, on December 31.
+     * While arguably the start range should still be 0..ONEDAY-1, we keep
+     * the start and end ranges the same for consistency.
+     */
+    private void decodeStartRule() {
+        useDaylight = (startDay != 0) && (endDay != 0);
+        if (startDay != 0) {
+            if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {
+                throw new IllegalArgumentException(
+                        "Illegal start month " + startMonth);
+            }
+            if (startTime < 0 || startTime > millisPerDay) {
+                throw new IllegalArgumentException(
+                        "Illegal start time " + startTime);
+            }
+            if (startDayOfWeek == 0) {
+                startMode = DOM_MODE;
+            } else {
+                if (startDayOfWeek > 0) {
+                    startMode = DOW_IN_MONTH_MODE;
+                } else {
+                    startDayOfWeek = -startDayOfWeek;
+                    if (startDay > 0) {
+                        startMode = DOW_GE_DOM_MODE;
+                    } else {
+                        startDay = -startDay;
+                        startMode = DOW_LE_DOM_MODE;
+                    }
+                }
+                if (startDayOfWeek > Calendar.SATURDAY) {
+                    throw new IllegalArgumentException(
+                           "Illegal start day of week " + startDayOfWeek);
+                }
+            }
+            if (startMode == DOW_IN_MONTH_MODE) {
+                if (startDay < -5 || startDay > 5) {
+                    throw new IllegalArgumentException(
+                            "Illegal start day of week in month " + startDay);
+                }
+            } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) {
+                throw new IllegalArgumentException(
+                        "Illegal start day " + startDay);
+            }
+        }
+    }
+
+    /**
+     * Decode the end rule and validate the parameters.  This method is exactly
+     * analogous to decodeStartRule().
+     * @see decodeStartRule
+     */
+    private void decodeEndRule() {
+        useDaylight = (startDay != 0) && (endDay != 0);
+        if (endDay != 0) {
+            if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {
+                throw new IllegalArgumentException(
+                        "Illegal end month " + endMonth);
+            }
+            if (endTime < 0 || endTime > millisPerDay) {
+                throw new IllegalArgumentException(
+                        "Illegal end time " + endTime);
+            }
+            if (endDayOfWeek == 0) {
+                endMode = DOM_MODE;
+            } else {
+                if (endDayOfWeek > 0) {
+                    endMode = DOW_IN_MONTH_MODE;
+                } else {
+                    endDayOfWeek = -endDayOfWeek;
+                    if (endDay > 0) {
+                        endMode = DOW_GE_DOM_MODE;
+                    } else {
+                        endDay = -endDay;
+                        endMode = DOW_LE_DOM_MODE;
+                    }
+                }
+                if (endDayOfWeek > Calendar.SATURDAY) {
+                    throw new IllegalArgumentException(
+                           "Illegal end day of week " + endDayOfWeek);
+                }
+            }
+            if (endMode == DOW_IN_MONTH_MODE) {
+                if (endDay < -5 || endDay > 5) {
+                    throw new IllegalArgumentException(
+                            "Illegal end day of week in month " + endDay);
+                }
+            } else if (endDay < 1 || endDay > staticMonthLength[endMonth]) {
+                throw new IllegalArgumentException(
+                        "Illegal end day " + endDay);
+            }
+        }
+    }
+
+    /**
+     * Make rules compatible to 1.1 FCS code.  Since 1.1 FCS code only understands
+     * day-of-week-in-month rules, we must modify other modes of rules to their
+     * approximate equivalent in 1.1 FCS terms.  This method is used when streaming
+     * out objects of this class.  After it is called, the rules will be modified,
+     * with a possible loss of information.  startMode and endMode will NOT be
+     * altered, even though semantically they should be set to DOW_IN_MONTH_MODE,
+     * since the rule modification is only intended to be temporary.
+     */
+    private void makeRulesCompatible()
+    {
+        switch (startMode) {
+        case DOM_MODE:
+            startDay = 1 + (startDay / 7);
+            startDayOfWeek = Calendar.SUNDAY;
+            break;
+
+        case DOW_GE_DOM_MODE:
+            // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
+            // that is, Sun>=1 == firstSun.
+            if (startDay != 1) {
+                startDay = 1 + (startDay / 7);
+            }
+            break;
+
+        case DOW_LE_DOM_MODE:
+            if (startDay >= 30) {
+                startDay = -1;
+            } else {
+                startDay = 1 + (startDay / 7);
+            }
+            break;
+        }
+
+        switch (endMode) {
+        case DOM_MODE:
+            endDay = 1 + (endDay / 7);
+            endDayOfWeek = Calendar.SUNDAY;
+            break;
+
+        case DOW_GE_DOM_MODE:
+            // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
+            // that is, Sun>=1 == firstSun.
+            if (endDay != 1) {
+                endDay = 1 + (endDay / 7);
+            }
+            break;
+
+        case DOW_LE_DOM_MODE:
+            if (endDay >= 30) {
+                endDay = -1;
+            } else {
+                endDay = 1 + (endDay / 7);
+            }
+            break;
+        }
+
+        /*
+         * Adjust the start and end times to wall time.  This works perfectly
+         * well unless it pushes into the next or previous day.  If that
+         * happens, we attempt to adjust the day rule somewhat crudely.  The day
+         * rules have been forced into DOW_IN_MONTH mode already, so we change
+         * the day of week to move forward or back by a day.  It's possible to
+         * make a more refined adjustment of the original rules first, but in
+         * most cases this extra effort will go to waste once we adjust the day
+         * rules anyway.
+         */
+        switch (startTimeMode) {
+        case UTC_TIME:
+            startTime += rawOffset;
+            break;
+        }
+        while (startTime < 0) {
+            startTime += millisPerDay;
+            startDayOfWeek = 1 + ((startDayOfWeek+5) % 7); // Back 1 day
+        }
+        while (startTime >= millisPerDay) {
+            startTime -= millisPerDay;
+            startDayOfWeek = 1 + (startDayOfWeek % 7); // Forward 1 day
+        }
+
+        switch (endTimeMode) {
+        case UTC_TIME:
+            endTime += rawOffset + dstSavings;
+            break;
+        case STANDARD_TIME:
+            endTime += dstSavings;
+        }
+        while (endTime < 0) {
+            endTime += millisPerDay;
+            endDayOfWeek = 1 + ((endDayOfWeek+5) % 7); // Back 1 day
+        }
+        while (endTime >= millisPerDay) {
+            endTime -= millisPerDay;
+            endDayOfWeek = 1 + (endDayOfWeek % 7); // Forward 1 day
+        }
+    }
+
+    /**
+     * Pack the start and end rules into an array of bytes.  Only pack
+     * data which is not preserved by makeRulesCompatible.
+     */
+    private byte[] packRules()
+    {
+        byte[] rules = new byte[6];
+        rules[0] = (byte)startDay;
+        rules[1] = (byte)startDayOfWeek;
+        rules[2] = (byte)endDay;
+        rules[3] = (byte)endDayOfWeek;
+
+        // As of serial version 2, include time modes
+        rules[4] = (byte)startTimeMode;
+        rules[5] = (byte)endTimeMode;
+
+        return rules;
+    }
+
+    /**
+     * Given an array of bytes produced by packRules, interpret them
+     * as the start and end rules.
+     */
+    private void unpackRules(byte[] rules)
+    {
+        startDay       = rules[0];
+        startDayOfWeek = rules[1];
+        endDay         = rules[2];
+        endDayOfWeek   = rules[3];
+
+        // As of serial version 2, include time modes
+        if (rules.length >= 6) {
+            startTimeMode = rules[4];
+            endTimeMode   = rules[5];
+        }
+    }
+
+    /**
+     * Pack the start and end times into an array of bytes.  This is required
+     * as of serial version 2.
+     */
+    private int[] packTimes() {
+        int[] times = new int[2];
+        times[0] = startTime;
+        times[1] = endTime;
+        return times;
+    }
+
+    /**
+     * Unpack the start and end times from an array of bytes.  This is required
+     * as of serial version 2.
+     */
+    private void unpackTimes(int[] times) {
+        startTime = times[0];
+        endTime = times[1];
+    }
+
+    /**
+     * Save the state of this object to a stream (i.e., serialize it).
+     *
+     * @serialData We write out two formats, a JDK 1.1 compatible format, using
+     * <code>DOW_IN_MONTH_MODE</code> rules, in the required section, followed
+     * by the full rules, in packed format, in the optional section.  The
+     * optional section will be ignored by JDK 1.1 code upon stream in.
+     * <p> Contents of the optional section: The length of a byte array is
+     * emitted (int); this is 4 as of this release. The byte array of the given
+     * length is emitted. The contents of the byte array are the true values of
+     * the fields <code>startDay</code>, <code>startDayOfWeek</code>,
+     * <code>endDay</code>, and <code>endDayOfWeek</code>.  The values of these
+     * fields in the required section are approximate values suited to the rule
+     * mode <code>DOW_IN_MONTH_MODE</code>, which is the only mode recognized by
+     * JDK 1.1.
+     */
+    private void writeObject(ObjectOutputStream stream)
+         throws IOException
+    {
+        // Construct a binary rule
+        byte[] rules = packRules();
+        int[] times = packTimes();
+
+        // Convert to 1.1 FCS rules.  This step may cause us to lose information.
+        makeRulesCompatible();
+
+        // Write out the 1.1 FCS rules
+        stream.defaultWriteObject();
+
+        // Write out the binary rules in the optional data area of the stream.
+        stream.writeInt(rules.length);
+        stream.write(rules);
+        stream.writeObject(times);
+
+        // Recover the original rules.  This recovers the information lost
+        // by makeRulesCompatible.
+        unpackRules(rules);
+        unpackTimes(times);
+    }
+
+    /**
+     * Reconstitute this object from a stream (i.e., deserialize it).
+     *
+     * We handle both JDK 1.1
+     * binary formats and full formats with a packed byte array.
+     */
+    private void readObject(ObjectInputStream stream)
+         throws IOException, ClassNotFoundException
+    {
+        stream.defaultReadObject();
+
+        if (serialVersionOnStream < 1) {
+            // Fix a bug in the 1.1 SimpleTimeZone code -- namely,
+            // startDayOfWeek and endDayOfWeek were usually uninitialized.  We can't do
+            // too much, so we assume SUNDAY, which actually works most of the time.
+            if (startDayOfWeek == 0) {
+                startDayOfWeek = Calendar.SUNDAY;
+            }
+            if (endDayOfWeek == 0) {
+                endDayOfWeek = Calendar.SUNDAY;
+            }
+
+            // The variables dstSavings, startMode, and endMode are post-1.1, so they
+            // won't be present if we're reading from a 1.1 stream.  Fix them up.
+            startMode = endMode = DOW_IN_MONTH_MODE;
+            dstSavings = millisPerHour;
+        } else {
+            // For 1.1.4, in addition to the 3 new instance variables, we also
+            // store the actual rules (which have not be made compatible with 1.1)
+            // in the optional area.  Read them in here and parse them.
+            int length = stream.readInt();
+            byte[] rules = new byte[length];
+            stream.readFully(rules);
+            unpackRules(rules);
+        }
+
+        if (serialVersionOnStream >= 2) {
+            int[] times = (int[]) stream.readObject();
+            unpackTimes(times);
+        }
+
+        serialVersionOnStream = currentSerialVersion;
+    }
+}
diff --git a/java/util/SortedMap.annotated.java b/java/util/SortedMap.annotated.java
new file mode 100644
index 0000000..9d68839
--- /dev/null
+++ b/java/util/SortedMap.annotated.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface SortedMap<K, V> extends java.util.Map<K,V> {
+
[email protected] public java.util.Comparator<? super @libcore.util.NullFromTypeParam K> comparator();
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> subMap(@libcore.util.NullFromTypeParam K fromKey, @libcore.util.NullFromTypeParam K toKey);
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> headMap(@libcore.util.NullFromTypeParam K toKey);
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> tailMap(@libcore.util.NullFromTypeParam K fromKey);
+
[email protected] public K firstKey();
+
[email protected] public K lastKey();
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet();
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values();
+
[email protected] public java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet();
+}
diff --git a/java/util/SortedMap.java b/java/util/SortedMap.java
new file mode 100644
index 0000000..7f98152
--- /dev/null
+++ b/java/util/SortedMap.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A {@link Map} that further provides a <em>total ordering</em> on its keys.
+ * The map is ordered according to the {@linkplain Comparable natural
+ * ordering} of its keys, or by a {@link Comparator} typically
+ * provided at sorted map creation time.  This order is reflected when
+ * iterating over the sorted map's collection views (returned by the
+ * {@code entrySet}, {@code keySet} and {@code values} methods).
+ * Several additional operations are provided to take advantage of the
+ * ordering.  (This interface is the map analogue of {@link SortedSet}.)
+ *
+ * <p>All keys inserted into a sorted map must implement the {@code Comparable}
+ * interface (or be accepted by the specified comparator).  Furthermore, all
+ * such keys must be <em>mutually comparable</em>: {@code k1.compareTo(k2)} (or
+ * {@code comparator.compare(k1, k2)}) must not throw a
+ * {@code ClassCastException} for any keys {@code k1} and {@code k2} in
+ * the sorted map.  Attempts to violate this restriction will cause the
+ * offending method or constructor invocation to throw a
+ * {@code ClassCastException}.
+ *
+ * <p>Note that the ordering maintained by a sorted map (whether or not an
+ * explicit comparator is provided) must be <em>consistent with equals</em> if
+ * the sorted map is to correctly implement the {@code Map} interface.  (See
+ * the {@code Comparable} interface or {@code Comparator} interface for a
+ * precise definition of <em>consistent with equals</em>.)  This is so because
+ * the {@code Map} interface is defined in terms of the {@code equals}
+ * operation, but a sorted map performs all key comparisons using its
+ * {@code compareTo} (or {@code compare}) method, so two keys that are
+ * deemed equal by this method are, from the standpoint of the sorted map,
+ * equal.  The behavior of a tree map <em>is</em> well-defined even if its
+ * ordering is inconsistent with equals; it just fails to obey the general
+ * contract of the {@code Map} interface.
+ *
+ * <p>All general-purpose sorted map implementation classes should provide four
+ * "standard" constructors. It is not possible to enforce this recommendation
+ * though as required constructors cannot be specified by interfaces. The
+ * expected "standard" constructors for all sorted map implementations are:
+ * <ol>
+ *   <li>A void (no arguments) constructor, which creates an empty sorted map
+ *   sorted according to the natural ordering of its keys.</li>
+ *   <li>A constructor with a single argument of type {@code Comparator}, which
+ *   creates an empty sorted map sorted according to the specified comparator.</li>
+ *   <li>A constructor with a single argument of type {@code Map}, which creates
+ *   a new map with the same key-value mappings as its argument, sorted
+ *   according to the keys' natural ordering.</li>
+ *   <li>A constructor with a single argument of type {@code SortedMap}, which
+ *   creates a new sorted map with the same key-value mappings and the same
+ *   ordering as the input sorted map.</li>
+ * </ol>
+ *
+ * <p><strong>Note</strong>: several methods return submaps with restricted key
+ * ranges. Such ranges are <em>half-open</em>, that is, they include their low
+ * endpoint but not their high endpoint (where applicable).  If you need a
+ * <em>closed range</em> (which includes both endpoints), and the key type
+ * allows for calculation of the successor of a given key, merely request
+ * the subrange from {@code lowEndpoint} to
+ * {@code successor(highEndpoint)}.  For example, suppose that {@code m}
+ * is a map whose keys are strings.  The following idiom obtains a view
+ * containing all of the key-value mappings in {@code m} whose keys are
+ * between {@code low} and {@code high}, inclusive:<pre>
+ *   SortedMap&lt;String, V&gt; sub = m.subMap(low, high+"\0");</pre>
+ *
+ * A similar technique can be used to generate an <em>open range</em>
+ * (which contains neither endpoint).  The following idiom obtains a
+ * view containing all of the key-value mappings in {@code m} whose keys
+ * are between {@code low} and {@code high}, exclusive:<pre>
+ *   SortedMap&lt;String, V&gt; sub = m.subMap(low+"\0", high);</pre>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @see Map
+ * @see TreeMap
+ * @see SortedSet
+ * @see Comparator
+ * @see Comparable
+ * @see Collection
+ * @see ClassCastException
+ * @since 1.2
+ */
+
+public interface SortedMap<K,V> extends Map<K,V> {
+    /**
+     * Returns the comparator used to order the keys in this map, or
+     * {@code null} if this map uses the {@linkplain Comparable
+     * natural ordering} of its keys.
+     *
+     * @return the comparator used to order the keys in this map,
+     *         or {@code null} if this map uses the natural ordering
+     *         of its keys
+     */
+    Comparator<? super K> comparator();
+
+    /**
+     * Returns a view of the portion of this map whose keys range from
+     * {@code fromKey}, inclusive, to {@code toKey}, exclusive.  (If
+     * {@code fromKey} and {@code toKey} are equal, the returned map
+     * is empty.)  The returned map is backed by this map, so changes
+     * in the returned map are reflected in this map, and vice-versa.
+     * The returned map supports all optional map operations that this
+     * map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param fromKey low endpoint (inclusive) of the keys in the returned map
+     * @param toKey high endpoint (exclusive) of the keys in the returned map
+     * @return a view of the portion of this map whose keys range from
+     *         {@code fromKey}, inclusive, to {@code toKey}, exclusive
+     * @throws ClassCastException if {@code fromKey} and {@code toKey}
+     *         cannot be compared to one another using this map's comparator
+     *         (or, if the map has no comparator, using natural ordering).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} or {@code toKey}
+     *         cannot be compared to keys currently in the map.
+     * @throws NullPointerException if {@code fromKey} or {@code toKey}
+     *         is null and this map does not permit null keys
+     * @throws IllegalArgumentException if {@code fromKey} is greater than
+     *         {@code toKey}; or if this map itself has a restricted
+     *         range, and {@code fromKey} or {@code toKey} lies
+     *         outside the bounds of the range
+     */
+    SortedMap<K,V> subMap(K fromKey, K toKey);
+
+    /**
+     * Returns a view of the portion of this map whose keys are
+     * strictly less than {@code toKey}.  The returned map is backed
+     * by this map, so changes in the returned map are reflected in
+     * this map, and vice-versa.  The returned map supports all
+     * optional map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param toKey high endpoint (exclusive) of the keys in the returned map
+     * @return a view of the portion of this map whose keys are strictly
+     *         less than {@code toKey}
+     * @throws ClassCastException if {@code toKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code toKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code toKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code toKey} is null and
+     *         this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code toKey} lies outside the
+     *         bounds of the range
+     */
+    SortedMap<K,V> headMap(K toKey);
+
+    /**
+     * Returns a view of the portion of this map whose keys are
+     * greater than or equal to {@code fromKey}.  The returned map is
+     * backed by this map, so changes in the returned map are
+     * reflected in this map, and vice-versa.  The returned map
+     * supports all optional map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param fromKey low endpoint (inclusive) of the keys in the returned map
+     * @return a view of the portion of this map whose keys are greater
+     *         than or equal to {@code fromKey}
+     * @throws ClassCastException if {@code fromKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code fromKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code fromKey} is null and
+     *         this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code fromKey} lies outside the
+     *         bounds of the range
+     */
+    SortedMap<K,V> tailMap(K fromKey);
+
+    /**
+     * Returns the first (lowest) key currently in this map.
+     *
+     * @return the first (lowest) key currently in this map
+     * @throws NoSuchElementException if this map is empty
+     */
+    K firstKey();
+
+    /**
+     * Returns the last (highest) key currently in this map.
+     *
+     * @return the last (highest) key currently in this map
+     * @throws NoSuchElementException if this map is empty
+     */
+    K lastKey();
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * @return a set view of the keys contained in this map, sorted in
+     *         ascending order
+     */
+    Set<K> keySet();
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection's iterator returns the values in ascending order
+     * of the corresponding keys.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * @return a collection view of the values contained in this map,
+     *         sorted in ascending key order
+     */
+    Collection<V> values();
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set's iterator returns the entries in ascending key order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     *
+     * @return a set view of the mappings contained in this map,
+     *         sorted in ascending key order
+     */
+    Set<Map.Entry<K, V>> entrySet();
+}
diff --git a/java/util/SortedSet.java b/java/util/SortedSet.java
new file mode 100644
index 0000000..3ea9329
--- /dev/null
+++ b/java/util/SortedSet.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A {@link Set} that further provides a <i>total ordering</i> on its elements.
+ * The elements are ordered using their {@linkplain Comparable natural
+ * ordering}, or by a {@link Comparator} typically provided at sorted
+ * set creation time.  The set's iterator will traverse the set in
+ * ascending element order. Several additional operations are provided
+ * to take advantage of the ordering.  (This interface is the set
+ * analogue of {@link SortedMap}.)
+ *
+ * <p>All elements inserted into a sorted set must implement the <tt>Comparable</tt>
+ * interface (or be accepted by the specified comparator).  Furthermore, all
+ * such elements must be <i>mutually comparable</i>: <tt>e1.compareTo(e2)</tt>
+ * (or <tt>comparator.compare(e1, e2)</tt>) must not throw a
+ * <tt>ClassCastException</tt> for any elements <tt>e1</tt> and <tt>e2</tt> in
+ * the sorted set.  Attempts to violate this restriction will cause the
+ * offending method or constructor invocation to throw a
+ * <tt>ClassCastException</tt>.
+ *
+ * <p>Note that the ordering maintained by a sorted set (whether or not an
+ * explicit comparator is provided) must be <i>consistent with equals</i> if
+ * the sorted set is to correctly implement the <tt>Set</tt> interface.  (See
+ * the <tt>Comparable</tt> interface or <tt>Comparator</tt> interface for a
+ * precise definition of <i>consistent with equals</i>.)  This is so because
+ * the <tt>Set</tt> interface is defined in terms of the <tt>equals</tt>
+ * operation, but a sorted set performs all element comparisons using its
+ * <tt>compareTo</tt> (or <tt>compare</tt>) method, so two elements that are
+ * deemed equal by this method are, from the standpoint of the sorted set,
+ * equal.  The behavior of a sorted set <i>is</i> well-defined even if its
+ * ordering is inconsistent with equals; it just fails to obey the general
+ * contract of the <tt>Set</tt> interface.
+ *
+ * <p>All general-purpose sorted set implementation classes should
+ * provide four "standard" constructors: 1) A void (no arguments)
+ * constructor, which creates an empty sorted set sorted according to
+ * the natural ordering of its elements.  2) A constructor with a
+ * single argument of type <tt>Comparator</tt>, which creates an empty
+ * sorted set sorted according to the specified comparator.  3) A
+ * constructor with a single argument of type <tt>Collection</tt>,
+ * which creates a new sorted set with the same elements as its
+ * argument, sorted according to the natural ordering of the elements.
+ * 4) A constructor with a single argument of type <tt>SortedSet</tt>,
+ * which creates a new sorted set with the same elements and the same
+ * ordering as the input sorted set.  There is no way to enforce this
+ * recommendation, as interfaces cannot contain constructors.
+ *
+ * <p>Note: several methods return subsets with restricted ranges.
+ * Such ranges are <i>half-open</i>, that is, they include their low
+ * endpoint but not their high endpoint (where applicable).
+ * If you need a <i>closed range</i> (which includes both endpoints), and
+ * the element type allows for calculation of the successor of a given
+ * value, merely request the subrange from <tt>lowEndpoint</tt> to
+ * <tt>successor(highEndpoint)</tt>.  For example, suppose that <tt>s</tt>
+ * is a sorted set of strings.  The following idiom obtains a view
+ * containing all of the strings in <tt>s</tt> from <tt>low</tt> to
+ * <tt>high</tt>, inclusive:<pre>
+ *   SortedSet&lt;String&gt; sub = s.subSet(low, high+"\0");</pre>
+ *
+ * A similar technique can be used to generate an <i>open range</i> (which
+ * contains neither endpoint).  The following idiom obtains a view
+ * containing all of the Strings in <tt>s</tt> from <tt>low</tt> to
+ * <tt>high</tt>, exclusive:<pre>
+ *   SortedSet&lt;String&gt; sub = s.subSet(low+"\0", high);</pre>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @see Set
+ * @see TreeSet
+ * @see SortedMap
+ * @see Collection
+ * @see Comparable
+ * @see Comparator
+ * @see ClassCastException
+ * @since 1.2
+ */
+
+public interface SortedSet<E> extends Set<E> {
+    /**
+     * Returns the comparator used to order the elements in this set,
+     * or <tt>null</tt> if this set uses the {@linkplain Comparable
+     * natural ordering} of its elements.
+     *
+     * @return the comparator used to order the elements in this set,
+     *         or <tt>null</tt> if this set uses the natural ordering
+     *         of its elements
+     */
+    Comparator<? super E> comparator();
+
+    /**
+     * Returns a view of the portion of this set whose elements range
+     * from <tt>fromElement</tt>, inclusive, to <tt>toElement</tt>,
+     * exclusive.  (If <tt>fromElement</tt> and <tt>toElement</tt> are
+     * equal, the returned set is empty.)  The returned set is backed
+     * by this set, so changes in the returned set are reflected in
+     * this set, and vice-versa.  The returned set supports all
+     * optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an <tt>IllegalArgumentException</tt>
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint (inclusive) of the returned set
+     * @param toElement high endpoint (exclusive) of the returned set
+     * @return a view of the portion of this set whose elements range from
+     *         <tt>fromElement</tt>, inclusive, to <tt>toElement</tt>, exclusive
+     * @throws ClassCastException if <tt>fromElement</tt> and
+     *         <tt>toElement</tt> cannot be compared to one another using this
+     *         set's comparator (or, if the set has no comparator, using
+     *         natural ordering).  Implementations may, but are not required
+     *         to, throw this exception if <tt>fromElement</tt> or
+     *         <tt>toElement</tt> cannot be compared to elements currently in
+     *         the set.
+     * @throws NullPointerException if <tt>fromElement</tt> or
+     *         <tt>toElement</tt> is null and this set does not permit null
+     *         elements
+     * @throws IllegalArgumentException if <tt>fromElement</tt> is
+     *         greater than <tt>toElement</tt>; or if this set itself
+     *         has a restricted range, and <tt>fromElement</tt> or
+     *         <tt>toElement</tt> lies outside the bounds of the range
+     */
+    SortedSet<E> subSet(E fromElement, E toElement);
+
+    /**
+     * Returns a view of the portion of this set whose elements are
+     * strictly less than <tt>toElement</tt>.  The returned set is
+     * backed by this set, so changes in the returned set are
+     * reflected in this set, and vice-versa.  The returned set
+     * supports all optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an <tt>IllegalArgumentException</tt>
+     * on an attempt to insert an element outside its range.
+     *
+     * @param toElement high endpoint (exclusive) of the returned set
+     * @return a view of the portion of this set whose elements are strictly
+     *         less than <tt>toElement</tt>
+     * @throws ClassCastException if <tt>toElement</tt> is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if <tt>toElement</tt> does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if <tt>toElement</tt> cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if <tt>toElement</tt> is null and
+     *         this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and <tt>toElement</tt> lies outside the
+     *         bounds of the range
+     */
+    SortedSet<E> headSet(E toElement);
+
+    /**
+     * Returns a view of the portion of this set whose elements are
+     * greater than or equal to <tt>fromElement</tt>.  The returned
+     * set is backed by this set, so changes in the returned set are
+     * reflected in this set, and vice-versa.  The returned set
+     * supports all optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an <tt>IllegalArgumentException</tt>
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint (inclusive) of the returned set
+     * @return a view of the portion of this set whose elements are greater
+     *         than or equal to <tt>fromElement</tt>
+     * @throws ClassCastException if <tt>fromElement</tt> is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if <tt>fromElement</tt> does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if <tt>fromElement</tt> cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if <tt>fromElement</tt> is null
+     *         and this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and <tt>fromElement</tt> lies outside the
+     *         bounds of the range
+     */
+    SortedSet<E> tailSet(E fromElement);
+
+    /**
+     * Returns the first (lowest) element currently in this set.
+     *
+     * @return the first (lowest) element currently in this set
+     * @throws NoSuchElementException if this set is empty
+     */
+    E first();
+
+    /**
+     * Returns the last (highest) element currently in this set.
+     *
+     * @return the last (highest) element currently in this set
+     * @throws NoSuchElementException if this set is empty
+     */
+    E last();
+
+    /**
+     * Creates a {@code Spliterator} over the elements in this sorted set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#DISTINCT},
+     * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}.
+     * Implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * <p>The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) must be {@code null} if
+     * the sorted set's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator must be the same as or impose the
+     * same total ordering as the sorted set's comparator.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the sorted set's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the set's iterator.  The
+     * spliterator's comparator is the same as the sorted set's comparator.
+     * <p>
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SIZED}.
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this sorted set
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        return new Spliterators.IteratorSpliterator<E>(
+                this, Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED) {
+            @Override
+            public Comparator<? super E> getComparator() {
+                return SortedSet.this.comparator();
+            }
+        };
+    }
+}
diff --git a/java/util/Spliterator.java b/java/util/Spliterator.java
new file mode 100644
index 0000000..35322b3
--- /dev/null
+++ b/java/util/Spliterator.java
@@ -0,0 +1,832 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * An object for traversing and partitioning elements of a source.  The source
+ * of elements covered by a Spliterator could be, for example, an array, a
+ * {@link Collection}, an IO channel, or a generator function.
+ *
+ * <p>A Spliterator may traverse elements individually ({@link
+ * #tryAdvance tryAdvance()}) or sequentially in bulk
+ * ({@link #forEachRemaining forEachRemaining()}).
+ *
+ * <p>A Spliterator may also partition off some of its elements (using
+ * {@link #trySplit}) as another Spliterator, to be used in
+ * possibly-parallel operations.  Operations using a Spliterator that
+ * cannot split, or does so in a highly imbalanced or inefficient
+ * manner, are unlikely to benefit from parallelism.  Traversal
+ * and splitting exhaust elements; each Spliterator is useful for only a single
+ * bulk computation.
+ *
+ * <p>A Spliterator also reports a set of {@link #characteristics()} of its
+ * structure, source, and elements from among {@link #ORDERED},
+ * {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED}, {@link #NONNULL},
+ * {@link #IMMUTABLE}, {@link #CONCURRENT}, and {@link #SUBSIZED}. These may
+ * be employed by Spliterator clients to control, specialize or simplify
+ * computation.  For example, a Spliterator for a {@link Collection} would
+ * report {@code SIZED}, a Spliterator for a {@link Set} would report
+ * {@code DISTINCT}, and a Spliterator for a {@link SortedSet} would also
+ * report {@code SORTED}.  Characteristics are reported as a simple unioned bit
+ * set.
+ *
+ * Some characteristics additionally constrain method behavior; for example if
+ * {@code ORDERED}, traversal methods must conform to their documented ordering.
+ * New characteristics may be defined in the future, so implementors should not
+ * assign meanings to unlisted values.
+ *
+ * <p><a name="binding">A Spliterator that does not report {@code IMMUTABLE} or
+ * {@code CONCURRENT} is expected to have a documented policy concerning:
+ * when the spliterator <em>binds</em> to the element source; and detection of
+ * structural interference of the element source detected after binding.</a>  A
+ * <em>late-binding</em> Spliterator binds to the source of elements at the
+ * point of first traversal, first split, or first query for estimated size,
+ * rather than at the time the Spliterator is created.  A Spliterator that is
+ * not <em>late-binding</em> binds to the source of elements at the point of
+ * construction or first invocation of any method.  Modifications made to the
+ * source prior to binding are reflected when the Spliterator is traversed.
+ * After binding a Spliterator should, on a best-effort basis, throw
+ * {@link ConcurrentModificationException} if structural interference is
+ * detected.  Spliterators that do this are called <em>fail-fast</em>.  The
+ * bulk traversal method ({@link #forEachRemaining forEachRemaining()}) of a
+ * Spliterator may optimize traversal and check for structural interference
+ * after all elements have been traversed, rather than checking per-element and
+ * failing immediately.
+ *
+ * <p>Spliterators can provide an estimate of the number of remaining elements
+ * via the {@link #estimateSize} method.  Ideally, as reflected in characteristic
+ * {@link #SIZED}, this value corresponds exactly to the number of elements
+ * that would be encountered in a successful traversal.  However, even when not
+ * exactly known, an estimated value value may still be useful to operations
+ * being performed on the source, such as helping to determine whether it is
+ * preferable to split further or traverse the remaining elements sequentially.
+ *
+ * <p>Despite their obvious utility in parallel algorithms, spliterators are not
+ * expected to be thread-safe; instead, implementations of parallel algorithms
+ * using spliterators should ensure that the spliterator is only used by one
+ * thread at a time.  This is generally easy to attain via <em>serial
+ * thread-confinement</em>, which often is a natural consequence of typical
+ * parallel algorithms that work by recursive decomposition.  A thread calling
+ * {@link #trySplit()} may hand over the returned Spliterator to another thread,
+ * which in turn may traverse or further split that Spliterator.  The behaviour
+ * of splitting and traversal is undefined if two or more threads operate
+ * concurrently on the same spliterator.  If the original thread hands a
+ * spliterator off to another thread for processing, it is best if that handoff
+ * occurs before any elements are consumed with {@link #tryAdvance(Consumer)
+ * tryAdvance()}, as certain guarantees (such as the accuracy of
+ * {@link #estimateSize()} for {@code SIZED} spliterators) are only valid before
+ * traversal has begun.
+ *
+ * <p>Primitive subtype specializations of {@code Spliterator} are provided for
+ * {@link OfInt int}, {@link OfLong long}, and {@link OfDouble double} values.
+ * The subtype default implementations of
+ * {@link Spliterator#tryAdvance(java.util.function.Consumer)}
+ * and {@link Spliterator#forEachRemaining(java.util.function.Consumer)} box
+ * primitive values to instances of their corresponding wrapper class.  Such
+ * boxing may undermine any performance advantages gained by using the primitive
+ * specializations.  To avoid boxing, the corresponding primitive-based methods
+ * should be used.  For example,
+ * {@link Spliterator.OfInt#tryAdvance(java.util.function.IntConsumer)}
+ * and {@link Spliterator.OfInt#forEachRemaining(java.util.function.IntConsumer)}
+ * should be used in preference to
+ * {@link Spliterator.OfInt#tryAdvance(java.util.function.Consumer)} and
+ * {@link Spliterator.OfInt#forEachRemaining(java.util.function.Consumer)}.
+ * Traversal of primitive values using boxing-based methods
+ * {@link #tryAdvance tryAdvance()} and
+ * {@link #forEachRemaining(java.util.function.Consumer) forEachRemaining()}
+ * does not affect the order in which the values, transformed to boxed values,
+ * are encountered.
+ *
+ * @apiNote
+ * <p>Spliterators, like {@code Iterator}s, are for traversing the elements of
+ * a source.  The {@code Spliterator} API was designed to support efficient
+ * parallel traversal in addition to sequential traversal, by supporting
+ * decomposition as well as single-element iteration.  In addition, the
+ * protocol for accessing elements via a Spliterator is designed to impose
+ * smaller per-element overhead than {@code Iterator}, and to avoid the inherent
+ * race involved in having separate methods for {@code hasNext()} and
+ * {@code next()}.
+ *
+ * <p>For mutable sources, arbitrary and non-deterministic behavior may occur if
+ * the source is structurally interfered with (elements added, replaced, or
+ * removed) between the time that the Spliterator binds to its data source and
+ * the end of traversal.  For example, such interference will produce arbitrary,
+ * non-deterministic results when using the {@code java.util.stream} framework.
+ *
+ * <p>Structural interference of a source can be managed in the following ways
+ * (in approximate order of decreasing desirability):
+ * <ul>
+ * <li>The source cannot be structurally interfered with.
+ * <br>For example, an instance of
+ * {@link java.util.concurrent.CopyOnWriteArrayList} is an immutable source.
+ * A Spliterator created from the source reports a characteristic of
+ * {@code IMMUTABLE}.</li>
+ * <li>The source manages concurrent modifications.
+ * <br>For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap}
+ * is a concurrent source.  A Spliterator created from the source reports a
+ * characteristic of {@code CONCURRENT}.</li>
+ * <li>The mutable source provides a late-binding and fail-fast Spliterator.
+ * <br>Late binding narrows the window during which interference can affect
+ * the calculation; fail-fast detects, on a best-effort basis, that structural
+ * interference has occurred after traversal has commenced and throws
+ * {@link ConcurrentModificationException}.  For example, {@link ArrayList},
+ * and many other non-concurrent {@code Collection} classes in the JDK, provide
+ * a late-binding, fail-fast spliterator.</li>
+ * <li>The mutable source provides a non-late-binding but fail-fast Spliterator.
+ * <br>The source increases the likelihood of throwing
+ * {@code ConcurrentModificationException} since the window of potential
+ * interference is larger.</li>
+ * <li>The mutable source provides a late-binding and non-fail-fast Spliterator.
+ * <br>The source risks arbitrary, non-deterministic behavior after traversal
+ * has commenced since interference is not detected.
+ * </li>
+ * <li>The mutable source provides a non-late-binding and non-fail-fast
+ * Spliterator.
+ * <br>The source increases the risk of arbitrary, non-deterministic behavior
+ * since non-detected interference may occur after construction.
+ * </li>
+ * </ul>
+ *
+ * <p><b>Example.</b> Here is a class (not a very useful one, except
+ * for illustration) that maintains an array in which the actual data
+ * are held in even locations, and unrelated tag data are held in odd
+ * locations. Its Spliterator ignores the tags.
+ *
+ * <pre> {@code
+ * class TaggedArray<T> {
+ *   private final Object[] elements; // immutable after construction
+ *   TaggedArray(T[] data, Object[] tags) {
+ *     int size = data.length;
+ *     if (tags.length != size) throw new IllegalArgumentException();
+ *     this.elements = new Object[2 * size];
+ *     for (int i = 0, j = 0; i < size; ++i) {
+ *       elements[j++] = data[i];
+ *       elements[j++] = tags[i];
+ *     }
+ *   }
+ *
+ *   public Spliterator<T> spliterator() {
+ *     return new TaggedArraySpliterator<>(elements, 0, elements.length);
+ *   }
+ *
+ *   static class TaggedArraySpliterator<T> implements Spliterator<T> {
+ *     private final Object[] array;
+ *     private int origin; // current index, advanced on split or traversal
+ *     private final int fence; // one past the greatest index
+ *
+ *     TaggedArraySpliterator(Object[] array, int origin, int fence) {
+ *       this.array = array; this.origin = origin; this.fence = fence;
+ *     }
+ *
+ *     public void forEachRemaining(Consumer<? super T> action) {
+ *       for (; origin < fence; origin += 2)
+ *         action.accept((T) array[origin]);
+ *     }
+ *
+ *     public boolean tryAdvance(Consumer<? super T> action) {
+ *       if (origin < fence) {
+ *         action.accept((T) array[origin]);
+ *         origin += 2;
+ *         return true;
+ *       }
+ *       else // cannot advance
+ *         return false;
+ *     }
+ *
+ *     public Spliterator<T> trySplit() {
+ *       int lo = origin; // divide range in half
+ *       int mid = ((lo + fence) >>> 1) & ~1; // force midpoint to be even
+ *       if (lo < mid) { // split out left half
+ *         origin = mid; // reset this Spliterator's origin
+ *         return new TaggedArraySpliterator<>(array, lo, mid);
+ *       }
+ *       else       // too small to split
+ *         return null;
+ *     }
+ *
+ *     public long estimateSize() {
+ *       return (long)((fence - origin) / 2);
+ *     }
+ *
+ *     public int characteristics() {
+ *       return ORDERED | SIZED | IMMUTABLE | SUBSIZED;
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>As an example how a parallel computation framework, such as the
+ * {@code java.util.stream} package, would use Spliterator in a parallel
+ * computation, here is one way to implement an associated parallel forEach,
+ * that illustrates the primary usage idiom of splitting off subtasks until
+ * the estimated amount of work is small enough to perform
+ * sequentially. Here we assume that the order of processing across
+ * subtasks doesn't matter; different (forked) tasks may further split
+ * and process elements concurrently in undetermined order.  This
+ * example uses a {@link java.util.concurrent.CountedCompleter};
+ * similar usages apply to other parallel task constructions.
+ *
+ * <pre>{@code
+ * static <T> void parEach(TaggedArray<T> a, Consumer<T> action) {
+ *   Spliterator<T> s = a.spliterator();
+ *   long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8);
+ *   new ParEach(null, s, action, targetBatchSize).invoke();
+ * }
+ *
+ * static class ParEach<T> extends CountedCompleter<Void> {
+ *   final Spliterator<T> spliterator;
+ *   final Consumer<T> action;
+ *   final long targetBatchSize;
+ *
+ *   ParEach(ParEach<T> parent, Spliterator<T> spliterator,
+ *           Consumer<T> action, long targetBatchSize) {
+ *     super(parent);
+ *     this.spliterator = spliterator; this.action = action;
+ *     this.targetBatchSize = targetBatchSize;
+ *   }
+ *
+ *   public void compute() {
+ *     Spliterator<T> sub;
+ *     while (spliterator.estimateSize() > targetBatchSize &&
+ *            (sub = spliterator.trySplit()) != null) {
+ *       addToPendingCount(1);
+ *       new ParEach<>(this, sub, action, targetBatchSize).fork();
+ *     }
+ *     spliterator.forEachRemaining(action);
+ *     propagateCompletion();
+ *   }
+ * }}</pre>
+ *
+ * @implNote
+ * If the boolean system property {@code org.openjdk.java.util.stream.tripwire}
+ * is set to {@code true} then diagnostic warnings are reported if boxing of
+ * primitive values occur when operating on primitive subtype specializations.
+ *
+ * @param <T> the type of elements returned by this Spliterator
+ *
+ * @see Collection
+ * @since 1.8
+ */
+public interface Spliterator<T> {
+    /**
+     * If a remaining element exists, performs the given action on it,
+     * returning {@code true}; else returns {@code false}.  If this
+     * Spliterator is {@link #ORDERED} the action is performed on the
+     * next element in encounter order.  Exceptions thrown by the
+     * action are relayed to the caller.
+     *
+     * @param action The action
+     * @return {@code false} if no remaining elements existed
+     * upon entry to this method, else {@code true}.
+     * @throws NullPointerException if the specified action is null
+     */
+    boolean tryAdvance(Consumer<? super T> action);
+
+    /**
+     * Performs the given action for each remaining element, sequentially in
+     * the current thread, until all elements have been processed or the action
+     * throws an exception.  If this Spliterator is {@link #ORDERED}, actions
+     * are performed in encounter order.  Exceptions thrown by the action
+     * are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation repeatedly invokes {@link #tryAdvance} until
+     * it returns {@code false}.  It should be overridden whenever possible.
+     *
+     * @param action The action
+     * @throws NullPointerException if the specified action is null
+     */
+    default void forEachRemaining(Consumer<? super T> action) {
+        do { } while (tryAdvance(action));
+    }
+
+    /**
+     * If this spliterator can be partitioned, returns a Spliterator
+     * covering elements, that will, upon return from this method, not
+     * be covered by this Spliterator.
+     *
+     * <p>If this Spliterator is {@link #ORDERED}, the returned Spliterator
+     * must cover a strict prefix of the elements.
+     *
+     * <p>Unless this Spliterator covers an infinite number of elements,
+     * repeated calls to {@code trySplit()} must eventually return {@code null}.
+     * Upon non-null return:
+     * <ul>
+     * <li>the value reported for {@code estimateSize()} before splitting,
+     * must, after splitting, be greater than or equal to {@code estimateSize()}
+     * for this and the returned Spliterator; and</li>
+     * <li>if this Spliterator is {@code SUBSIZED}, then {@code estimateSize()}
+     * for this spliterator before splitting must be equal to the sum of
+     * {@code estimateSize()} for this and the returned Spliterator after
+     * splitting.</li>
+     * </ul>
+     *
+     * <p>This method may return {@code null} for any reason,
+     * including emptiness, inability to split after traversal has
+     * commenced, data structure constraints, and efficiency
+     * considerations.
+     *
+     * @apiNote
+     * An ideal {@code trySplit} method efficiently (without
+     * traversal) divides its elements exactly in half, allowing
+     * balanced parallel computation.  Many departures from this ideal
+     * remain highly effective; for example, only approximately
+     * splitting an approximately balanced tree, or for a tree in
+     * which leaf nodes may contain either one or two elements,
+     * failing to further split these nodes.  However, large
+     * deviations in balance and/or overly inefficient {@code
+     * trySplit} mechanics typically result in poor parallel
+     * performance.
+     *
+     * @return a {@code Spliterator} covering some portion of the
+     * elements, or {@code null} if this spliterator cannot be split
+     */
+    Spliterator<T> trySplit();
+
+    /**
+     * Returns an estimate of the number of elements that would be
+     * encountered by a {@link #forEachRemaining} traversal, or returns {@link
+     * Long#MAX_VALUE} if infinite, unknown, or too expensive to compute.
+     *
+     * <p>If this Spliterator is {@link #SIZED} and has not yet been partially
+     * traversed or split, or this Spliterator is {@link #SUBSIZED} and has
+     * not yet been partially traversed, this estimate must be an accurate
+     * count of elements that would be encountered by a complete traversal.
+     * Otherwise, this estimate may be arbitrarily inaccurate, but must decrease
+     * as specified across invocations of {@link #trySplit}.
+     *
+     * @apiNote
+     * Even an inexact estimate is often useful and inexpensive to compute.
+     * For example, a sub-spliterator of an approximately balanced binary tree
+     * may return a value that estimates the number of elements to be half of
+     * that of its parent; if the root Spliterator does not maintain an
+     * accurate count, it could estimate size to be the power of two
+     * corresponding to its maximum depth.
+     *
+     * @return the estimated size, or {@code Long.MAX_VALUE} if infinite,
+     *         unknown, or too expensive to compute.
+     */
+    long estimateSize();
+
+    /**
+     * Convenience method that returns {@link #estimateSize()} if this
+     * Spliterator is {@link #SIZED}, else {@code -1}.
+     * @implSpec
+     * The default implementation returns the result of {@code estimateSize()}
+     * if the Spliterator reports a characteristic of {@code SIZED}, and
+     * {@code -1} otherwise.
+     *
+     * @return the exact size, if known, else {@code -1}.
+     */
+    default long getExactSizeIfKnown() {
+        return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
+    }
+
+    /**
+     * Returns a set of characteristics of this Spliterator and its
+     * elements. The result is represented as ORed values from {@link
+     * #ORDERED}, {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED},
+     * {@link #NONNULL}, {@link #IMMUTABLE}, {@link #CONCURRENT},
+     * {@link #SUBSIZED}.  Repeated calls to {@code characteristics()} on
+     * a given spliterator, prior to or in-between calls to {@code trySplit},
+     * should always return the same result.
+     *
+     * <p>If a Spliterator reports an inconsistent set of
+     * characteristics (either those returned from a single invocation
+     * or across multiple invocations), no guarantees can be made
+     * about any computation using this Spliterator.
+     *
+     * @apiNote The characteristics of a given spliterator before splitting
+     * may differ from the characteristics after splitting.  For specific
+     * examples see the characteristic values {@link #SIZED}, {@link #SUBSIZED}
+     * and {@link #CONCURRENT}.
+     *
+     * @return a representation of characteristics
+     */
+    int characteristics();
+
+    /**
+     * Returns {@code true} if this Spliterator's {@link
+     * #characteristics} contain all of the given characteristics.
+     *
+     * @implSpec
+     * The default implementation returns true if the corresponding bits
+     * of the given characteristics are set.
+     *
+     * @param characteristics the characteristics to check for
+     * @return {@code true} if all the specified characteristics are present,
+     * else {@code false}
+     */
+    default boolean hasCharacteristics(int characteristics) {
+        return (characteristics() & characteristics) == characteristics;
+    }
+
+    /**
+     * If this Spliterator's source is {@link #SORTED} by a {@link Comparator},
+     * returns that {@code Comparator}. If the source is {@code SORTED} in
+     * {@linkplain Comparable natural order}, returns {@code null}.  Otherwise,
+     * if the source is not {@code SORTED}, throws {@link IllegalStateException}.
+     *
+     * @implSpec
+     * The default implementation always throws {@link IllegalStateException}.
+     *
+     * @return a Comparator, or {@code null} if the elements are sorted in the
+     * natural order.
+     * @throws IllegalStateException if the spliterator does not report
+     *         a characteristic of {@code SORTED}.
+     */
+    default Comparator<? super T> getComparator() {
+        throw new IllegalStateException();
+    }
+
+    /**
+     * Characteristic value signifying that an encounter order is defined for
+     * elements. If so, this Spliterator guarantees that method
+     * {@link #trySplit} splits a strict prefix of elements, that method
+     * {@link #tryAdvance} steps by one element in prefix order, and that
+     * {@link #forEachRemaining} performs actions in encounter order.
+     *
+     * <p>A {@link Collection} has an encounter order if the corresponding
+     * {@link Collection#iterator} documents an order. If so, the encounter
+     * order is the same as the documented order. Otherwise, a collection does
+     * not have an encounter order.
+     *
+     * @apiNote Encounter order is guaranteed to be ascending index order for
+     * any {@link List}. But no order is guaranteed for hash-based collections
+     * such as {@link HashSet}. Clients of a Spliterator that reports
+     * {@code ORDERED} are expected to preserve ordering constraints in
+     * non-commutative parallel computations.
+     */
+    public static final int ORDERED    = 0x00000010;
+
+    /**
+     * Characteristic value signifying that, for each pair of
+     * encountered elements {@code x, y}, {@code !x.equals(y)}. This
+     * applies for example, to a Spliterator based on a {@link Set}.
+     */
+    public static final int DISTINCT   = 0x00000001;
+
+    /**
+     * Characteristic value signifying that encounter order follows a defined
+     * sort order. If so, method {@link #getComparator()} returns the associated
+     * Comparator, or {@code null} if all elements are {@link Comparable} and
+     * are sorted by their natural ordering.
+     *
+     * <p>A Spliterator that reports {@code SORTED} must also report
+     * {@code ORDERED}.
+     *
+     * @apiNote The spliterators for {@code Collection} classes in the JDK that
+     * implement {@link NavigableSet} or {@link SortedSet} report {@code SORTED}.
+     */
+    public static final int SORTED     = 0x00000004;
+
+    /**
+     * Characteristic value signifying that the value returned from
+     * {@code estimateSize()} prior to traversal or splitting represents a
+     * finite size that, in the absence of structural source modification,
+     * represents an exact count of the number of elements that would be
+     * encountered by a complete traversal.
+     *
+     * @apiNote Most Spliterators for Collections, that cover all elements of a
+     * {@code Collection} report this characteristic. Sub-spliterators, such as
+     * those for {@link HashSet}, that cover a sub-set of elements and
+     * approximate their reported size do not.
+     */
+    public static final int SIZED      = 0x00000040;
+
+    /**
+     * Characteristic value signifying that the source guarantees that
+     * encountered elements will not be {@code null}. (This applies,
+     * for example, to most concurrent collections, queues, and maps.)
+     */
+    public static final int NONNULL    = 0x00000100;
+
+    /**
+     * Characteristic value signifying that the element source cannot be
+     * structurally modified; that is, elements cannot be added, replaced, or
+     * removed, so such changes cannot occur during traversal. A Spliterator
+     * that does not report {@code IMMUTABLE} or {@code CONCURRENT} is expected
+     * to have a documented policy (for example throwing
+     * {@link ConcurrentModificationException}) concerning structural
+     * interference detected during traversal.
+     */
+    public static final int IMMUTABLE  = 0x00000400;
+
+    /**
+     * Characteristic value signifying that the element source may be safely
+     * concurrently modified (allowing additions, replacements, and/or removals)
+     * by multiple threads without external synchronization. If so, the
+     * Spliterator is expected to have a documented policy concerning the impact
+     * of modifications during traversal.
+     *
+     * <p>A top-level Spliterator should not report both {@code CONCURRENT} and
+     * {@code SIZED}, since the finite size, if known, may change if the source
+     * is concurrently modified during traversal. Such a Spliterator is
+     * inconsistent and no guarantees can be made about any computation using
+     * that Spliterator. Sub-spliterators may report {@code SIZED} if the
+     * sub-split size is known and additions or removals to the source are not
+     * reflected when traversing.
+     *
+     * @apiNote Most concurrent collections maintain a consistency policy
+     * guaranteeing accuracy with respect to elements present at the point of
+     * Spliterator construction, but possibly not reflecting subsequent
+     * additions or removals.
+     */
+    public static final int CONCURRENT = 0x00001000;
+
+    /**
+     * Characteristic value signifying that all Spliterators resulting from
+     * {@code trySplit()} will be both {@link #SIZED} and {@link #SUBSIZED}.
+     * (This means that all child Spliterators, whether direct or indirect, will
+     * be {@code SIZED}.)
+     *
+     * <p>A Spliterator that does not report {@code SIZED} as required by
+     * {@code SUBSIZED} is inconsistent and no guarantees can be made about any
+     * computation using that Spliterator.
+     *
+     * @apiNote Some spliterators, such as the top-level spliterator for an
+     * approximately balanced binary tree, will report {@code SIZED} but not
+     * {@code SUBSIZED}, since it is common to know the size of the entire tree
+     * but not the exact sizes of subtrees.
+     */
+    public static final int SUBSIZED = 0x00004000;
+
+    /**
+     * A Spliterator specialized for primitive values.
+     *
+     * @param <T> the type of elements returned by this Spliterator.  The
+     * type must be a wrapper type for a primitive type, such as {@code Integer}
+     * for the primitive {@code int} type.
+     * @param <T_CONS> the type of primitive consumer.  The type must be a
+     * primitive specialization of {@link java.util.function.Consumer} for
+     * {@code T}, such as {@link java.util.function.IntConsumer} for
+     * {@code Integer}.
+     * @param <T_SPLITR> the type of primitive Spliterator.  The type must be
+     * a primitive specialization of Spliterator for {@code T}, such as
+     * {@link Spliterator.OfInt} for {@code Integer}.
+     *
+     * @see Spliterator.OfInt
+     * @see Spliterator.OfLong
+     * @see Spliterator.OfDouble
+     * @since 1.8
+     */
+    public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+            extends Spliterator<T> {
+        @Override
+        T_SPLITR trySplit();
+
+        /**
+         * If a remaining element exists, performs the given action on it,
+         * returning {@code true}; else returns {@code false}.  If this
+         * Spliterator is {@link #ORDERED} the action is performed on the
+         * next element in encounter order.  Exceptions thrown by the
+         * action are relayed to the caller.
+         *
+         * @param action The action
+         * @return {@code false} if no remaining elements existed
+         * upon entry to this method, else {@code true}.
+         * @throws NullPointerException if the specified action is null
+         */
+        @SuppressWarnings("overloads")
+        boolean tryAdvance(T_CONS action);
+
+        /**
+         * Performs the given action for each remaining element, sequentially in
+         * the current thread, until all elements have been processed or the
+         * action throws an exception.  If this Spliterator is {@link #ORDERED},
+         * actions are performed in encounter order.  Exceptions thrown by the
+         * action are relayed to the caller.
+         *
+         * @implSpec
+         * The default implementation repeatedly invokes {@link #tryAdvance}
+         * until it returns {@code false}.  It should be overridden whenever
+         * possible.
+         *
+         * @param action The action
+         * @throws NullPointerException if the specified action is null
+         */
+        @SuppressWarnings("overloads")
+        default void forEachRemaining(T_CONS action) {
+            do { } while (tryAdvance(action));
+        }
+    }
+
+    /**
+     * A Spliterator specialized for {@code int} values.
+     * @since 1.8
+     */
+    public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> {
+
+        @Override
+        OfInt trySplit();
+
+        @Override
+        boolean tryAdvance(IntConsumer action);
+
+        @Override
+        default void forEachRemaining(IntConsumer action) {
+            do { } while (tryAdvance(action));
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code IntConsumer} then it is cast
+         * to {@code IntConsumer} and passed to
+         * {@link #tryAdvance(java.util.function.IntConsumer)}; otherwise
+         * the action is adapted to an instance of {@code IntConsumer}, by
+         * boxing the argument of {@code IntConsumer}, and then passed to
+         * {@link #tryAdvance(java.util.function.IntConsumer)}.
+         */
+        @Override
+        default boolean tryAdvance(Consumer<? super Integer> action) {
+            if (action instanceof IntConsumer) {
+                return tryAdvance((IntConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
+                return tryAdvance((IntConsumer) action::accept);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code IntConsumer} then it is cast
+         * to {@code IntConsumer} and passed to
+         * {@link #forEachRemaining(java.util.function.IntConsumer)}; otherwise
+         * the action is adapted to an instance of {@code IntConsumer}, by
+         * boxing the argument of {@code IntConsumer}, and then passed to
+         * {@link #forEachRemaining(java.util.function.IntConsumer)}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Integer> action) {
+            if (action instanceof IntConsumer) {
+                forEachRemaining((IntConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfInt.forEachRemaining((IntConsumer) action::accept)");
+                forEachRemaining((IntConsumer) action::accept);
+            }
+        }
+    }
+
+    /**
+     * A Spliterator specialized for {@code long} values.
+     * @since 1.8
+     */
+    public interface OfLong extends OfPrimitive<Long, LongConsumer, OfLong> {
+
+        @Override
+        OfLong trySplit();
+
+        @Override
+        boolean tryAdvance(LongConsumer action);
+
+        @Override
+        default void forEachRemaining(LongConsumer action) {
+            do { } while (tryAdvance(action));
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code LongConsumer} then it is cast
+         * to {@code LongConsumer} and passed to
+         * {@link #tryAdvance(java.util.function.LongConsumer)}; otherwise
+         * the action is adapted to an instance of {@code LongConsumer}, by
+         * boxing the argument of {@code LongConsumer}, and then passed to
+         * {@link #tryAdvance(java.util.function.LongConsumer)}.
+         */
+        @Override
+        default boolean tryAdvance(Consumer<? super Long> action) {
+            if (action instanceof LongConsumer) {
+                return tryAdvance((LongConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfLong.tryAdvance((LongConsumer) action::accept)");
+                return tryAdvance((LongConsumer) action::accept);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code LongConsumer} then it is cast
+         * to {@code LongConsumer} and passed to
+         * {@link #forEachRemaining(java.util.function.LongConsumer)}; otherwise
+         * the action is adapted to an instance of {@code LongConsumer}, by
+         * boxing the argument of {@code LongConsumer}, and then passed to
+         * {@link #forEachRemaining(java.util.function.LongConsumer)}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Long> action) {
+            if (action instanceof LongConsumer) {
+                forEachRemaining((LongConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfLong.forEachRemaining((LongConsumer) action::accept)");
+                forEachRemaining((LongConsumer) action::accept);
+            }
+        }
+    }
+
+    /**
+     * A Spliterator specialized for {@code double} values.
+     * @since 1.8
+     */
+    public interface OfDouble extends OfPrimitive<Double, DoubleConsumer, OfDouble> {
+
+        @Override
+        OfDouble trySplit();
+
+        @Override
+        boolean tryAdvance(DoubleConsumer action);
+
+        @Override
+        default void forEachRemaining(DoubleConsumer action) {
+            do { } while (tryAdvance(action));
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code DoubleConsumer} then it is
+         * cast to {@code DoubleConsumer} and passed to
+         * {@link #tryAdvance(java.util.function.DoubleConsumer)}; otherwise
+         * the action is adapted to an instance of {@code DoubleConsumer}, by
+         * boxing the argument of {@code DoubleConsumer}, and then passed to
+         * {@link #tryAdvance(java.util.function.DoubleConsumer)}.
+         */
+        @Override
+        default boolean tryAdvance(Consumer<? super Double> action) {
+            if (action instanceof DoubleConsumer) {
+                return tryAdvance((DoubleConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfDouble.tryAdvance((DoubleConsumer) action::accept)");
+                return tryAdvance((DoubleConsumer) action::accept);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code DoubleConsumer} then it is
+         * cast to {@code DoubleConsumer} and passed to
+         * {@link #forEachRemaining(java.util.function.DoubleConsumer)};
+         * otherwise the action is adapted to an instance of
+         * {@code DoubleConsumer}, by boxing the argument of
+         * {@code DoubleConsumer}, and then passed to
+         * {@link #forEachRemaining(java.util.function.DoubleConsumer)}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Double> action) {
+            if (action instanceof DoubleConsumer) {
+                forEachRemaining((DoubleConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfDouble.forEachRemaining((DoubleConsumer) action::accept)");
+                forEachRemaining((DoubleConsumer) action::accept);
+            }
+        }
+    }
+}
diff --git a/java/util/Spliterators.java b/java/util/Spliterators.java
new file mode 100644
index 0000000..79c0ef3
--- /dev/null
+++ b/java/util/Spliterators.java
@@ -0,0 +1,2124 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * Static classes and methods for operating on or creating instances of
+ * {@link Spliterator} and its primitive specializations
+ * {@link Spliterator.OfInt}, {@link Spliterator.OfLong}, and
+ * {@link Spliterator.OfDouble}.
+ *
+ * @see Spliterator
+ * @since 1.8
+ */
+public final class Spliterators {
+
+    // Suppresses default constructor, ensuring non-instantiability.
+    private Spliterators() {}
+
+    // Empty spliterators
+
+    /**
+     * Creates an empty {@code Spliterator}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @param <T> Type of elements
+     * @return An empty spliterator
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Spliterator<T> emptySpliterator() {
+        return (Spliterator<T>) EMPTY_SPLITERATOR;
+    }
+
+    private static final Spliterator<Object> EMPTY_SPLITERATOR =
+            new EmptySpliterator.OfRef<>();
+
+    /**
+     * Creates an empty {@code Spliterator.OfInt}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return An empty spliterator
+     */
+    public static Spliterator.OfInt emptyIntSpliterator() {
+        return EMPTY_INT_SPLITERATOR;
+    }
+
+    private static final Spliterator.OfInt EMPTY_INT_SPLITERATOR =
+            new EmptySpliterator.OfInt();
+
+    /**
+     * Creates an empty {@code Spliterator.OfLong}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return An empty spliterator
+     */
+    public static Spliterator.OfLong emptyLongSpliterator() {
+        return EMPTY_LONG_SPLITERATOR;
+    }
+
+    private static final Spliterator.OfLong EMPTY_LONG_SPLITERATOR =
+            new EmptySpliterator.OfLong();
+
+    /**
+     * Creates an empty {@code Spliterator.OfDouble}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return An empty spliterator
+     */
+    public static Spliterator.OfDouble emptyDoubleSpliterator() {
+        return EMPTY_DOUBLE_SPLITERATOR;
+    }
+
+    private static final Spliterator.OfDouble EMPTY_DOUBLE_SPLITERATOR =
+            new EmptySpliterator.OfDouble();
+
+    // Array-based spliterators
+
+    /**
+     * Creates a {@code Spliterator} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(Object[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param <T> Type of elements
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(Object[])
+     */
+    public static <T> Spliterator<T> spliterator(Object[] array,
+                                                 int additionalCharacteristics) {
+        return new ArraySpliterator<>(Objects.requireNonNull(array),
+                                      additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator} covering a range of elements of a given
+     * array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(Object[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param <T> Type of elements
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(Object[], int, int)
+     */
+    public static <T> Spliterator<T> spliterator(Object[] array, int fromIndex, int toIndex,
+                                                 int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new ArraySpliterator<>(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(int[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(int[])
+     */
+    public static Spliterator.OfInt spliterator(int[] array,
+                                                int additionalCharacteristics) {
+        return new IntArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} covering a range of elements of a
+     * given array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(int[], int, int)}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(int[], int, int)
+     */
+    public static Spliterator.OfInt spliterator(int[] array, int fromIndex, int toIndex,
+                                                int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new IntArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(long[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(long[])
+     */
+    public static Spliterator.OfLong spliterator(long[] array,
+                                                 int additionalCharacteristics) {
+        return new LongArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} covering a range of elements of a
+     * given array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(long[], int, int)}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report.  (For example, if it is
+     * known the array will not be further modified, specify {@code IMMUTABLE};
+     * if the array data is considered to have an an encounter order, specify
+     * {@code ORDERED}).  The method {@link Arrays#spliterator(long[], int, int)} can
+     * often be used instead, which returns a spliterator that reports
+     * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(long[], int, int)
+     */
+    public static Spliterator.OfLong spliterator(long[] array, int fromIndex, int toIndex,
+                                                 int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new LongArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(double[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(double[])
+     */
+    public static Spliterator.OfDouble spliterator(double[] array,
+                                                   int additionalCharacteristics) {
+        return new DoubleArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} covering a range of elements of a
+     * given array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(double[], int, int)}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report.  (For example, if it is
+     * known the array will not be further modified, specify {@code IMMUTABLE};
+     * if the array data is considered to have an an encounter order, specify
+     * {@code ORDERED}).  The method {@link Arrays#spliterator(long[], int, int)} can
+     * often be used instead, which returns a spliterator that reports
+     * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(double[], int, int)
+     */
+    public static Spliterator.OfDouble spliterator(double[] array, int fromIndex, int toIndex,
+                                                   int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new DoubleArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Validate inclusive start index and exclusive end index against the length
+     * of an array.
+     * @param arrayLength The length of the array
+     * @param origin The inclusive start index
+     * @param fence The exclusive end index
+     * @throws ArrayIndexOutOfBoundsException if the start index is greater than
+     * the end index, if the start index is negative, or the end index is
+     * greater than the array length
+     */
+    private static void checkFromToBounds(int arrayLength, int origin, int fence) {
+        if (origin > fence) {
+            throw new ArrayIndexOutOfBoundsException(
+                    "origin(" + origin + ") > fence(" + fence + ")");
+        }
+        if (origin < 0) {
+            throw new ArrayIndexOutOfBoundsException(origin);
+        }
+        if (fence > arrayLength) {
+            throw new ArrayIndexOutOfBoundsException(fence);
+        }
+    }
+
+    // Iterator-based spliterators
+
+    /**
+     * Creates a {@code Spliterator} using the given collection's
+     * {@link java.util.Collection#iterator()} as the source of elements, and
+     * reporting its {@link java.util.Collection#size()} as its initial size.
+     *
+     * <p>The spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the collection's iterator, and
+     * implements {@code trySplit} to permit limited parallelism.
+     *
+     * @param <T> Type of elements
+     * @param c The collection
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given collection is {@code null}
+     */
+    public static <T> Spliterator<T> spliterator(Collection<? extends T> c,
+                                                 int characteristics) {
+        return new IteratorSpliterator<>(Objects.requireNonNull(c),
+                                         characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator} using a given {@code Iterator}
+     * as the source of elements, and with a given initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param <T> Type of elements
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static <T> Spliterator<T> spliterator(Iterator<? extends T> iterator,
+                                                 long size,
+                                                 int characteristics) {
+        return new IteratorSpliterator<>(Objects.requireNonNull(iterator), size,
+                                         characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator} using a given {@code Iterator}
+     * as the source of elements, with no initial size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param <T> Type of elements
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static <T> Spliterator<T> spliteratorUnknownSize(Iterator<? extends T> iterator,
+                                                            int characteristics) {
+        return new IteratorSpliterator<>(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} using a given
+     * {@code IntStream.IntIterator} as the source of elements, and with a given
+     * initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}.
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfInt spliterator(PrimitiveIterator.OfInt iterator,
+                                                long size,
+                                                int characteristics) {
+        return new IntIteratorSpliterator(Objects.requireNonNull(iterator),
+                                          size, characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} using a given
+     * {@code IntStream.IntIterator} as the source of elements, with no initial
+     * size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfInt spliteratorUnknownSize(PrimitiveIterator.OfInt iterator,
+                                                           int characteristics) {
+        return new IntIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} using a given
+     * {@code LongStream.LongIterator} as the source of elements, and with a
+     * given initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}.
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfLong spliterator(PrimitiveIterator.OfLong iterator,
+                                                 long size,
+                                                 int characteristics) {
+        return new LongIteratorSpliterator(Objects.requireNonNull(iterator),
+                                           size, characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} using a given
+     * {@code LongStream.LongIterator} as the source of elements, with no
+     * initial size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfLong spliteratorUnknownSize(PrimitiveIterator.OfLong iterator,
+                                                            int characteristics) {
+        return new LongIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} using a given
+     * {@code DoubleStream.DoubleIterator} as the source of elements, and with a
+     * given initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfDouble spliterator(PrimitiveIterator.OfDouble iterator,
+                                                   long size,
+                                                   int characteristics) {
+        return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator),
+                                             size, characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} using a given
+     * {@code DoubleStream.DoubleIterator} as the source of elements, with no
+     * initial size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfDouble spliteratorUnknownSize(PrimitiveIterator.OfDouble iterator,
+                                                              int characteristics) {
+        return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    // Iterators from Spliterators
+
+    /**
+     * Creates an {@code Iterator} from a {@code Spliterator}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param <T> Type of elements
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static<T> Iterator<T> iterator(Spliterator<? extends T> spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements Iterator<T>, Consumer<T> {
+            boolean valueReady = false;
+            T nextElement;
+
+            @Override
+            public void accept(T t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public T next() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    return nextElement;
+                }
+            }
+        }
+
+        return new Adapter();
+    }
+
+    /**
+     * Creates an {@code PrimitiveIterator.OfInt} from a
+     * {@code Spliterator.OfInt}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static PrimitiveIterator.OfInt iterator(Spliterator.OfInt spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements PrimitiveIterator.OfInt, IntConsumer {
+            boolean valueReady = false;
+            int nextElement;
+
+            @Override
+            public void accept(int t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public int nextInt() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    return nextElement;
+                }
+            }
+        }
+
+        return new Adapter();
+    }
+
+    /**
+     * Creates an {@code PrimitiveIterator.OfLong} from a
+     * {@code Spliterator.OfLong}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static PrimitiveIterator.OfLong iterator(Spliterator.OfLong spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements PrimitiveIterator.OfLong, LongConsumer {
+            boolean valueReady = false;
+            long nextElement;
+
+            @Override
+            public void accept(long t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public long nextLong() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    return nextElement;
+                }
+            }
+        }
+
+        return new Adapter();
+    }
+
+    /**
+     * Creates an {@code PrimitiveIterator.OfDouble} from a
+     * {@code Spliterator.OfDouble}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static PrimitiveIterator.OfDouble iterator(Spliterator.OfDouble spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements PrimitiveIterator.OfDouble, DoubleConsumer {
+            boolean valueReady = false;
+            double nextElement;
+
+            @Override
+            public void accept(double t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public double nextDouble() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    return nextElement;
+                }
+            }
+        }
+
+        return new Adapter();
+    }
+
+    // Implementations
+
+    private static abstract class EmptySpliterator<T, S extends Spliterator<T>, C> {
+
+        EmptySpliterator() { }
+
+        public S trySplit() {
+            return null;
+        }
+
+        public boolean tryAdvance(C consumer) {
+            Objects.requireNonNull(consumer);
+            return false;
+        }
+
+        public void forEachRemaining(C consumer) {
+            Objects.requireNonNull(consumer);
+        }
+
+        public long estimateSize() {
+            return 0;
+        }
+
+        public int characteristics() {
+            return Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        private static final class OfRef<T>
+                extends EmptySpliterator<T, Spliterator<T>, Consumer<? super T>>
+                implements Spliterator<T> {
+            OfRef() { }
+        }
+
+        private static final class OfInt
+                extends EmptySpliterator<Integer, Spliterator.OfInt, IntConsumer>
+                implements Spliterator.OfInt {
+            OfInt() { }
+        }
+
+        private static final class OfLong
+                extends EmptySpliterator<Long, Spliterator.OfLong, LongConsumer>
+                implements Spliterator.OfLong {
+            OfLong() { }
+        }
+
+        private static final class OfDouble
+                extends EmptySpliterator<Double, Spliterator.OfDouble, DoubleConsumer>
+                implements Spliterator.OfDouble {
+            OfDouble() { }
+        }
+    }
+
+    // Array-based spliterators
+
+    /**
+     * A Spliterator designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code Object[]} array.
+     */
+    static final class ArraySpliterator<T> implements Spliterator<T> {
+        /**
+         * The array, explicitly typed as Object[]. Unlike in some other
+         * classes (see for example CR 6260652), we do not need to
+         * screen arguments to ensure they are exactly of type Object[]
+         * so long as no methods write into the array or serialize it,
+         * which we ensure here by defining this class as final.
+         */
+        private final Object[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         * of this spliterator's source or elements beyond {@code SIZED} and
+         * {@code SUBSIZED} which are are always reported
+         */
+        public ArraySpliterator(Object[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         * of this spliterator's source or elements beyond {@code SIZED} and
+         * {@code SUBSIZED} which are are always reported
+         */
+        public ArraySpliterator(Object[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public Spliterator<T> trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new ArraySpliterator<>(array, lo, index = mid, characteristics);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            Object[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept((T)a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                @SuppressWarnings("unchecked") T e = (T) array[index++];
+                action.accept(e);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfInt designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code int[]} array.
+     */
+    static final class IntArraySpliterator implements Spliterator.OfInt {
+        private final int[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public IntArraySpliterator(int[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public IntArraySpliterator(int[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public OfInt trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new IntArraySpliterator(array, lo, index = mid, characteristics);
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            int[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept(a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                action.accept(array[index++]);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super Integer> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfLong designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code int[]} array.
+     */
+    static final class LongArraySpliterator implements Spliterator.OfLong {
+        private final long[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public LongArraySpliterator(long[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public LongArraySpliterator(long[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public OfLong trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new LongArraySpliterator(array, lo, index = mid, characteristics);
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer action) {
+            long[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept(a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                action.accept(array[index++]);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super Long> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfDouble designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code int[]} array.
+     */
+    static final class DoubleArraySpliterator implements Spliterator.OfDouble {
+        private final double[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public DoubleArraySpliterator(double[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public DoubleArraySpliterator(double[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public OfDouble trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new DoubleArraySpliterator(array, lo, index = mid, characteristics);
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer action) {
+            double[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept(a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                action.accept(array[index++]);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super Double> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    //
+
+    /**
+     * An abstract {@code Spliterator} that implements {@code trySplit} to
+     * permit limited parallelism.
+     *
+     * <p>An extending class need only
+     * implement {@link #tryAdvance(java.util.function.Consumer) tryAdvance}.
+     * The extending class should override
+     * {@link #forEachRemaining(java.util.function.Consumer) forEach} if it can
+     * provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(Iterator, long, int)}.  Depending on the
+     * circumstances using an iterator may be easier or more convenient than
+     * extending this class, such as when there is already an iterator
+     * available to use.
+     *
+     * @see #spliterator(Iterator, long, int)
+     * @since 1.8
+     */
+    public static abstract class AbstractSpliterator<T> implements Spliterator<T> {
+        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * additionalCharacteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingConsumer<T> implements Consumer<T> {
+            Object value;
+
+            @Override
+            public void accept(T value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator<T> trySplit() {
+            /*
+             * Split into arrays of arithmetically increasing batch
+             * sizes.  This will only improve parallel performance if
+             * per-element Consumer actions are more costly than
+             * transferring them into an array.  The use of an
+             * arithmetic progression in split sizes provides overhead
+             * vs parallelism bounds that do not particularly favor or
+             * penalize cases of lightweight vs heavyweight element
+             * operations, across combinations of #elements vs #cores,
+             * whether or not either are known.  We generate
+             * O(sqrt(#elements)) splits, allowing O(sqrt(#cores))
+             * potential speedup.
+             */
+            HoldingConsumer<T> holder = new HoldingConsumer<>();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                Object[] a = new Object[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new ArraySpliterator<>(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * An abstract {@code Spliterator.OfInt} that implements {@code trySplit} to
+     * permit limited parallelism.
+     *
+     * <p>To implement a spliterator an extending class need only
+     * implement {@link #tryAdvance(java.util.function.IntConsumer)}
+     * tryAdvance}.  The extending class should override
+     * {@link #forEachRemaining(java.util.function.IntConsumer)} forEach} if it
+     * can provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(java.util.PrimitiveIterator.OfInt, long, int)}.
+     * Depending on the circumstances using an iterator may be easier or more
+     * convenient than extending this class. For example, if there is already an
+     * iterator available to use then there is no need to extend this class.
+     *
+     * @see #spliterator(java.util.PrimitiveIterator.OfInt, long, int)
+     * @since 1.8
+     */
+    public static abstract class AbstractIntSpliterator implements Spliterator.OfInt {
+        static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
+        static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * characteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractIntSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingIntConsumer implements IntConsumer {
+            int value;
+
+            @Override
+            public void accept(int value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator.OfInt trySplit() {
+            HoldingIntConsumer holder = new HoldingIntConsumer();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                int[] a = new int[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new IntArraySpliterator(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * An abstract {@code Spliterator.OfLong} that implements {@code trySplit}
+     * to permit limited parallelism.
+     *
+     * <p>To implement a spliterator an extending class need only
+     * implement {@link #tryAdvance(java.util.function.LongConsumer)}
+     * tryAdvance}.  The extending class should override
+     * {@link #forEachRemaining(java.util.function.LongConsumer)} forEach} if it
+     * can provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(java.util.PrimitiveIterator.OfLong, long, int)}.
+     * Depending on the circumstances using an iterator may be easier or more
+     * convenient than extending this class. For example, if there is already an
+     * iterator available to use then there is no need to extend this class.
+     *
+     * @see #spliterator(java.util.PrimitiveIterator.OfLong, long, int)
+     * @since 1.8
+     */
+    public static abstract class AbstractLongSpliterator implements Spliterator.OfLong {
+        static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
+        static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * characteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractLongSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingLongConsumer implements LongConsumer {
+            long value;
+
+            @Override
+            public void accept(long value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator.OfLong trySplit() {
+            HoldingLongConsumer holder = new HoldingLongConsumer();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                long[] a = new long[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new LongArraySpliterator(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * An abstract {@code Spliterator.OfDouble} that implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>To implement a spliterator an extending class need only
+     * implement {@link #tryAdvance(java.util.function.DoubleConsumer)}
+     * tryAdvance}.  The extending class should override
+     * {@link #forEachRemaining(java.util.function.DoubleConsumer)} forEach} if
+     * it can provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(java.util.PrimitiveIterator.OfDouble, long, int)}.
+     * Depending on the circumstances using an iterator may be easier or more
+     * convenient than extending this class. For example, if there is already an
+     * iterator available to use then there is no need to extend this class.
+     *
+     * @see #spliterator(java.util.PrimitiveIterator.OfDouble, long, int)
+     * @since 1.8
+     */
+    public static abstract class AbstractDoubleSpliterator implements Spliterator.OfDouble {
+        static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
+        static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * characteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractDoubleSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingDoubleConsumer implements DoubleConsumer {
+            double value;
+
+            @Override
+            public void accept(double value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator.OfDouble trySplit() {
+            HoldingDoubleConsumer holder = new HoldingDoubleConsumer();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                double[] a = new double[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new DoubleArraySpliterator(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    // Iterator-based Spliterators
+
+    /**
+     * A Spliterator using a given Iterator for element
+     * operations. The spliterator implements {@code trySplit} to
+     * permit limited parallelism.
+     */
+    static class IteratorSpliterator<T> implements Spliterator<T> {
+        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        private final Collection<? extends T> collection; // null OK
+        private Iterator<? extends T> it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given given
+         * collection's {@link java.util.Collection#iterator()) for traversal,
+         * and reporting its {@link java.util.Collection#size()) as its initial
+         * size.
+         *
+         * @param c the collection
+         * @param characteristics properties of this spliterator's
+         *        source or elements.
+         */
+        public IteratorSpliterator(Collection<? extends T> collection, int characteristics) {
+            this.collection = collection;
+            this.it = null;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IteratorSpliterator(Iterator<? extends T> iterator, long size, int characteristics) {
+            this.collection = null;
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IteratorSpliterator(Iterator<? extends T> iterator, int characteristics) {
+            this.collection = null;
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public Spliterator<T> trySplit() {
+            /*
+             * Split into arrays of arithmetically increasing batch
+             * sizes.  This will only improve parallel performance if
+             * per-element Consumer actions are more costly than
+             * transferring them into an array.  The use of an
+             * arithmetic progression in split sizes provides overhead
+             * vs parallelism bounds that do not particularly favor or
+             * penalize cases of lightweight vs heavyweight element
+             * operations, across combinations of #elements vs #cores,
+             * whether or not either are known.  We generate
+             * O(sqrt(#elements)) splits, allowing O(sqrt(#cores))
+             * potential speedup.
+             */
+            Iterator<? extends T> i;
+            long s;
+            if ((i = it) == null) {
+                i = it = collection.iterator();
+                s = est = (long) collection.size();
+            }
+            else
+                s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                Object[] a = new Object[n];
+                int j = 0;
+                do { a[j] = i.next(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new ArraySpliterator<>(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            if (action == null) throw new NullPointerException();
+            Iterator<? extends T> i;
+            if ((i = it) == null) {
+                i = it = collection.iterator();
+                est = (long)collection.size();
+            }
+            i.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            if (action == null) throw new NullPointerException();
+            if (it == null) {
+                it = collection.iterator();
+                est = (long) collection.size();
+            }
+            if (it.hasNext()) {
+                action.accept(it.next());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            if (it == null) {
+                it = collection.iterator();
+                return est = (long)collection.size();
+            }
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfInt using a given IntStream.IntIterator for element
+     * operations. The spliterator implements {@code trySplit} to
+     * permit limited parallelism.
+     */
+    static final class IntIteratorSpliterator implements Spliterator.OfInt {
+        static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
+        static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
+        private PrimitiveIterator.OfInt it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IntIteratorSpliterator(PrimitiveIterator.OfInt iterator, long size, int characteristics) {
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator for a
+         * source of unknown size, reporting the given
+         * characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IntIteratorSpliterator(PrimitiveIterator.OfInt iterator, int characteristics) {
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public OfInt trySplit() {
+            PrimitiveIterator.OfInt i = it;
+            long s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                int[] a = new int[n];
+                int j = 0;
+                do { a[j] = i.nextInt(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new IntArraySpliterator(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            if (action == null) throw new NullPointerException();
+            it.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            if (action == null) throw new NullPointerException();
+            if (it.hasNext()) {
+                action.accept(it.nextInt());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super Integer> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    static final class LongIteratorSpliterator implements Spliterator.OfLong {
+        static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
+        static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
+        private PrimitiveIterator.OfLong it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public LongIteratorSpliterator(PrimitiveIterator.OfLong iterator, long size, int characteristics) {
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator for a
+         * source of unknown size, reporting the given
+         * characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public LongIteratorSpliterator(PrimitiveIterator.OfLong iterator, int characteristics) {
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public OfLong trySplit() {
+            PrimitiveIterator.OfLong i = it;
+            long s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                long[] a = new long[n];
+                int j = 0;
+                do { a[j] = i.nextLong(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new LongArraySpliterator(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer action) {
+            if (action == null) throw new NullPointerException();
+            it.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer action) {
+            if (action == null) throw new NullPointerException();
+            if (it.hasNext()) {
+                action.accept(it.nextLong());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super Long> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    static final class DoubleIteratorSpliterator implements Spliterator.OfDouble {
+        static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
+        static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
+        private PrimitiveIterator.OfDouble it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public DoubleIteratorSpliterator(PrimitiveIterator.OfDouble iterator, long size, int characteristics) {
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator for a
+         * source of unknown size, reporting the given
+         * characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public DoubleIteratorSpliterator(PrimitiveIterator.OfDouble iterator, int characteristics) {
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public OfDouble trySplit() {
+            PrimitiveIterator.OfDouble i = it;
+            long s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                double[] a = new double[n];
+                int j = 0;
+                do { a[j] = i.nextDouble(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new DoubleArraySpliterator(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer action) {
+            if (action == null) throw new NullPointerException();
+            it.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer action) {
+            if (action == null) throw new NullPointerException();
+            if (it.hasNext()) {
+                action.accept(it.nextDouble());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super Double> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+}
diff --git a/java/util/SplittableRandom.java b/java/util/SplittableRandom.java
new file mode 100644
index 0000000..579102a
--- /dev/null
+++ b/java/util/SplittableRandom.java
@@ -0,0 +1,996 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.StreamSupport;
+
+/**
+ * A generator of uniform pseudorandom values applicable for use in
+ * (among other contexts) isolated parallel computations that may
+ * generate subtasks. Class {@code SplittableRandom} supports methods for
+ * producing pseudorandom numbers of type {@code int}, {@code long},
+ * and {@code double} with similar usages as for class
+ * {@link java.util.Random} but differs in the following ways:
+ *
+ * <ul>
+ *
+ * <li>Series of generated values pass the DieHarder suite testing
+ * independence and uniformity properties of random number generators.
+ * (Most recently validated with <a
+ * href="http://www.phy.duke.edu/~rgb/General/dieharder.php"> version
+ * 3.31.1</a>.) These tests validate only the methods for certain
+ * types and ranges, but similar properties are expected to hold, at
+ * least approximately, for others as well. The <em>period</em>
+ * (length of any series of generated values before it repeats) is at
+ * least 2<sup>64</sup>.
+ *
+ * <li>Method {@link #split} constructs and returns a new
+ * SplittableRandom instance that shares no mutable state with the
+ * current instance. However, with very high probability, the
+ * values collectively generated by the two objects have the same
+ * statistical properties as if the same quantity of values were
+ * generated by a single thread using a single {@code
+ * SplittableRandom} object.
+ *
+ * <li>Instances of SplittableRandom are <em>not</em> thread-safe.
+ * They are designed to be split, not shared, across threads. For
+ * example, a {@link java.util.concurrent.ForkJoinTask
+ * fork/join-style} computation using random numbers might include a
+ * construction of the form {@code new
+ * Subtask(aSplittableRandom.split()).fork()}.
+ *
+ * <li>This class provides additional methods for generating random
+ * streams, that employ the above techniques when used in {@code
+ * stream.parallel()} mode.
+ *
+ * </ul>
+ *
+ * <p>Instances of {@code SplittableRandom} are not cryptographically
+ * secure.  Consider instead using {@link java.security.SecureRandom}
+ * in security-sensitive applications. Additionally,
+ * default-constructed instances do not use a cryptographically random
+ * seed unless the {@linkplain System#getProperty system property}
+ * {@code java.util.secureRandomSeed} is set to {@code true}.
+ *
+ * @author  Guy Steele
+ * @author  Doug Lea
+ * @since   1.8
+ */
+public final class SplittableRandom {
+
+    /*
+     * Implementation Overview.
+     *
+     * This algorithm was inspired by the "DotMix" algorithm by
+     * Leiserson, Schardl, and Sukha "Deterministic Parallel
+     * Random-Number Generation for Dynamic-Multithreading Platforms",
+     * PPoPP 2012, as well as those in "Parallel random numbers: as
+     * easy as 1, 2, 3" by Salmon, Morae, Dror, and Shaw, SC 2011.  It
+     * differs mainly in simplifying and cheapening operations.
+     *
+     * The primary update step (method nextSeed()) is to add a
+     * constant ("gamma") to the current (64 bit) seed, forming a
+     * simple sequence.  The seed and the gamma values for any two
+     * SplittableRandom instances are highly likely to be different.
+     *
+     * Methods nextLong, nextInt, and derivatives do not return the
+     * sequence (seed) values, but instead a hash-like bit-mix of
+     * their bits, producing more independently distributed sequences.
+     * For nextLong, the mix64 function is based on David Stafford's
+     * (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
+     * "Mix13" variant of the "64-bit finalizer" function in Austin
+     * Appleby's MurmurHash3 algorithm (see
+     * http://code.google.com/p/smhasher/wiki/MurmurHash3). The mix32
+     * function is based on Stafford's Mix04 mix function, but returns
+     * the upper 32 bits cast as int.
+     *
+     * The split operation uses the current generator to form the seed
+     * and gamma for another SplittableRandom.  To conservatively
+     * avoid potential correlations between seed and value generation,
+     * gamma selection (method mixGamma) uses different
+     * (Murmurhash3's) mix constants.  To avoid potential weaknesses
+     * in bit-mixing transformations, we restrict gammas to odd values
+     * with at least 24 0-1 or 1-0 bit transitions.  Rather than
+     * rejecting candidates with too few or too many bits set, method
+     * mixGamma flips some bits (which has the effect of mapping at
+     * most 4 to any given gamma value).  This reduces the effective
+     * set of 64bit odd gamma values by about 2%, and serves as an
+     * automated screening for sequence constant selection that is
+     * left as an empirical decision in some other hashing and crypto
+     * algorithms.
+     *
+     * The resulting generator thus transforms a sequence in which
+     * (typically) many bits change on each step, with an inexpensive
+     * mixer with good (but less than cryptographically secure)
+     * avalanching.
+     *
+     * The default (no-argument) constructor, in essence, invokes
+     * split() for a common "defaultGen" SplittableRandom.  Unlike
+     * other cases, this split must be performed in a thread-safe
+     * manner, so we use an AtomicLong to represent the seed rather
+     * than use an explicit SplittableRandom. To bootstrap the
+     * defaultGen, we start off using a seed based on current time
+     * unless the java.util.secureRandomSeed property is set. This
+     * serves as a slimmed-down (and insecure) variant of SecureRandom
+     * that also avoids stalls that may occur when using /dev/random.
+     *
+     * It is a relatively simple matter to apply the basic design here
+     * to use 128 bit seeds. However, emulating 128bit arithmetic and
+     * carrying around twice the state add more overhead than appears
+     * warranted for current usages.
+     *
+     * File organization: First the non-public methods that constitute
+     * the main algorithm, then the main public methods, followed by
+     * some custom spliterator classes needed for stream methods.
+     */
+
+    /**
+     * The golden ratio scaled to 64bits, used as the initial gamma
+     * value for (unsplit) SplittableRandoms.
+     */
+    private static final long GOLDEN_GAMMA = 0x9e3779b97f4a7c15L;
+
+    /**
+     * The least non-zero value returned by nextDouble(). This value
+     * is scaled by a random value of 53 bits to produce a result.
+     */
+    private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53);
+
+    /**
+     * The seed. Updated only via method nextSeed.
+     */
+    private long seed;
+
+    /**
+     * The step value.
+     */
+    private final long gamma;
+
+    /**
+     * Internal constructor used by all others except default constructor.
+     */
+    private SplittableRandom(long seed, long gamma) {
+        this.seed = seed;
+        this.gamma = gamma;
+    }
+
+    /**
+     * Computes Stafford variant 13 of 64bit mix function.
+     */
+    private static long mix64(long z) {
+        z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L;
+        z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
+        return z ^ (z >>> 31);
+    }
+
+    /**
+     * Returns the 32 high bits of Stafford variant 4 mix64 function as int.
+     */
+    private static int mix32(long z) {
+        z = (z ^ (z >>> 33)) * 0x62a9d9ed799705f5L;
+        return (int)(((z ^ (z >>> 28)) * 0xcb24d0a5c88c35b3L) >>> 32);
+    }
+
+    /**
+     * Returns the gamma value to use for a new split instance.
+     */
+    private static long mixGamma(long z) {
+        z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; // MurmurHash3 mix constants
+        z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
+        z = (z ^ (z >>> 33)) | 1L;                  // force to be odd
+        int n = Long.bitCount(z ^ (z >>> 1));       // ensure enough transitions
+        return (n < 24) ? z ^ 0xaaaaaaaaaaaaaaaaL : z;
+    }
+
+    /**
+     * Adds gamma to seed.
+     */
+    private long nextSeed() {
+        return seed += gamma;
+    }
+
+    // IllegalArgumentException messages
+    static final String BAD_BOUND = "bound must be positive";
+    static final String BAD_RANGE = "bound must be greater than origin";
+    static final String BAD_SIZE  = "size must be non-negative";
+
+    /**
+     * The seed generator for default constructors.
+     */
+    private static final AtomicLong defaultGen
+        = new AtomicLong(mix64(System.currentTimeMillis()) ^
+                         mix64(System.nanoTime()));
+
+    // at end of <clinit> to survive static initialization circularity
+    static {
+        if (java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return Boolean.getBoolean("java.util.secureRandomSeed");
+                }})) {
+            byte[] seedBytes = java.security.SecureRandom.getSeed(8);
+            long s = (long)seedBytes[0] & 0xffL;
+            for (int i = 1; i < 8; ++i)
+                s = (s << 8) | ((long)seedBytes[i] & 0xffL);
+            defaultGen.set(s);
+        }
+    }
+
+    /*
+     * Internal versions of nextX methods used by streams, as well as
+     * the public nextX(origin, bound) methods.  These exist mainly to
+     * avoid the need for multiple versions of stream spliterators
+     * across the different exported forms of streams.
+     */
+
+    /**
+     * The form of nextLong used by LongStream Spliterators.  If
+     * origin is greater than bound, acts as unbounded form of
+     * nextLong, else as bounded form.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final long internalNextLong(long origin, long bound) {
+        /*
+         * Four Cases:
+         *
+         * 1. If the arguments indicate unbounded form, act as
+         * nextLong().
+         *
+         * 2. If the range is an exact power of two, apply the
+         * associated bit mask.
+         *
+         * 3. If the range is positive, loop to avoid potential bias
+         * when the implicit nextLong() bound (2<sup>64</sup>) is not
+         * evenly divisible by the range. The loop rejects candidates
+         * computed from otherwise over-represented values.  The
+         * expected number of iterations under an ideal generator
+         * varies from 1 to 2, depending on the bound. The loop itself
+         * takes an unlovable form. Because the first candidate is
+         * already available, we need a break-in-the-middle
+         * construction, which is concisely but cryptically performed
+         * within the while-condition of a body-less for loop.
+         *
+         * 4. Otherwise, the range cannot be represented as a positive
+         * long.  The loop repeatedly generates unbounded longs until
+         * obtaining a candidate meeting constraints (with an expected
+         * number of iterations of less than two).
+         */
+
+        long r = mix64(nextSeed());
+        if (origin < bound) {
+            long n = bound - origin, m = n - 1;
+            if ((n & m) == 0L)  // power of two
+                r = (r & m) + origin;
+            else if (n > 0L) {  // reject over-represented candidates
+                for (long u = r >>> 1;            // ensure nonnegative
+                     u + m - (r = u % n) < 0L;    // rejection check
+                     u = mix64(nextSeed()) >>> 1) // retry
+                    ;
+                r += origin;
+            }
+            else {              // range not representable as long
+                while (r < origin || r >= bound)
+                    r = mix64(nextSeed());
+            }
+        }
+        return r;
+    }
+
+    /**
+     * The form of nextInt used by IntStream Spliterators.
+     * Exactly the same as long version, except for types.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final int internalNextInt(int origin, int bound) {
+        int r = mix32(nextSeed());
+        if (origin < bound) {
+            int n = bound - origin, m = n - 1;
+            if ((n & m) == 0)
+                r = (r & m) + origin;
+            else if (n > 0) {
+                for (int u = r >>> 1;
+                     u + m - (r = u % n) < 0;
+                     u = mix32(nextSeed()) >>> 1)
+                    ;
+                r += origin;
+            }
+            else {
+                while (r < origin || r >= bound)
+                    r = mix32(nextSeed());
+            }
+        }
+        return r;
+    }
+
+    /**
+     * The form of nextDouble used by DoubleStream Spliterators.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final double internalNextDouble(double origin, double bound) {
+        double r = (nextLong() >>> 11) * DOUBLE_UNIT;
+        if (origin < bound) {
+            r = r * (bound - origin) + origin;
+            if (r >= bound) // correct for rounding
+                r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+        }
+        return r;
+    }
+
+    /* ---------------- public methods ---------------- */
+
+    /**
+     * Creates a new SplittableRandom instance using the specified
+     * initial seed. SplittableRandom instances created with the same
+     * seed in the same program generate identical sequences of values.
+     *
+     * @param seed the initial seed
+     */
+    public SplittableRandom(long seed) {
+        this(seed, GOLDEN_GAMMA);
+    }
+
+    /**
+     * Creates a new SplittableRandom instance that is likely to
+     * generate sequences of values that are statistically independent
+     * of those of any other instances in the current program; and
+     * may, and typically does, vary across program invocations.
+     */
+    public SplittableRandom() { // emulate defaultGen.split()
+        long s = defaultGen.getAndAdd(2 * GOLDEN_GAMMA);
+        this.seed = mix64(s);
+        this.gamma = mixGamma(s + GOLDEN_GAMMA);
+    }
+
+    /**
+     * Constructs and returns a new SplittableRandom instance that
+     * shares no mutable state with this instance. However, with very
+     * high probability, the set of values collectively generated by
+     * the two objects has the same statistical properties as if the
+     * same quantity of values were generated by a single thread using
+     * a single SplittableRandom object.  Either or both of the two
+     * objects may be further split using the {@code split()} method,
+     * and the same expected statistical properties apply to the
+     * entire set of generators constructed by such recursive
+     * splitting.
+     *
+     * @return the new SplittableRandom instance
+     */
+    public SplittableRandom split() {
+        return new SplittableRandom(nextLong(), mixGamma(nextSeed()));
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value.
+     *
+     * @return a pseudorandom {@code int} value
+     */
+    public int nextInt() {
+        return mix32(nextSeed());
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value between zero (inclusive)
+     * and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code int} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public int nextInt(int bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BAD_BOUND);
+        // Specialize internalNextInt for origin 0
+        int r = mix32(nextSeed());
+        int m = bound - 1;
+        if ((bound & m) == 0) // power of two
+            r &= m;
+        else { // reject over-represented candidates
+            for (int u = r >>> 1;
+                 u + m - (r = u % bound) < 0;
+                 u = mix32(nextSeed()) >>> 1)
+                ;
+        }
+        return r;
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code int} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public int nextInt(int origin, int bound) {
+        if (origin >= bound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextInt(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value.
+     *
+     * @return a pseudorandom {@code long} value
+     */
+    public long nextLong() {
+        return mix64(nextSeed());
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value between zero (inclusive)
+     * and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code long} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public long nextLong(long bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BAD_BOUND);
+        // Specialize internalNextLong for origin 0
+        long r = mix64(nextSeed());
+        long m = bound - 1;
+        if ((bound & m) == 0L) // power of two
+            r &= m;
+        else { // reject over-represented candidates
+            for (long u = r >>> 1;
+                 u + m - (r = u % bound) < 0L;
+                 u = mix64(nextSeed()) >>> 1)
+                ;
+        }
+        return r;
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code long} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public long nextLong(long origin, long bound) {
+        if (origin >= bound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextLong(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @return a pseudorandom {@code double} value between zero
+     *         (inclusive) and one (exclusive)
+     */
+    public double nextDouble() {
+        return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT;
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between 0.0
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code double} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public double nextDouble(double bound) {
+        if (!(bound > 0.0))
+            throw new IllegalArgumentException(BAD_BOUND);
+        double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
+        return (result < bound) ?  result : // correct for rounding
+            Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between the specified
+     * origin (inclusive) and bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code double} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public double nextDouble(double origin, double bound) {
+        if (!(origin < bound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextDouble(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code boolean} value.
+     *
+     * @return a pseudorandom {@code boolean} value
+     */
+    public boolean nextBoolean() {
+        return mix32(nextSeed()) < 0;
+    }
+
+    // stream methods, coded in a way intended to better isolate for
+    // maintenance purposes the small differences across forms.
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values from this generator and/or
+     * one split from it.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code int} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    public IntStream ints(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (this, 0L, streamSize, Integer.MAX_VALUE, 0),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code int}
+     * values from this generator and/or one split from it.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code int} values
+     */
+    public IntStream ints() {
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values from this generator and/or one split
+     * from it; each value conforms to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public IntStream ints(long streamSize, int randomNumberOrigin,
+                          int randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * int} values from this generator and/or one split from it; each value
+     * conforms to the given origin (inclusive) and bound (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code long} values from this generator and/or
+     * one split from it.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code long} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    public LongStream longs(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (this, 0L, streamSize, Long.MAX_VALUE, 0L),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values from this generator and/or one split from it.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code long} values
+     */
+    public LongStream longs() {
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long} values from this generator and/or one split
+     * from it; each value conforms to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public LongStream longs(long streamSize, long randomNumberOrigin,
+                            long randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values from this generator and/or one split from it; each value
+     * conforms to the given origin (inclusive) and bound (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values from this generator and/or one split
+     * from it; each value is between zero (inclusive) and one (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of {@code double} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    public DoubleStream doubles(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (this, 0L, streamSize, Double.MAX_VALUE, 0.0),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values from this generator and/or one split from it; each value
+     * is between zero (inclusive) and one (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code double} values
+     */
+    public DoubleStream doubles() {
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values from this generator and/or one split
+     * from it; each value conforms to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public DoubleStream doubles(long streamSize, double randomNumberOrigin,
+                                double randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values from this generator and/or one split from it; each value
+     * conforms to the given origin (inclusive) and bound (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Spliterator for int streams.  We multiplex the four int
+     * versions into one class by treating a bound less than origin as
+     * unbounded, and also by treating "infinite" as equivalent to
+     * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
+     * approach. The long and double versions of this class are
+     * identical except for types.
+     */
+    private static final class RandomIntsSpliterator
+            implements Spliterator.OfInt {
+        final SplittableRandom rng;
+        long index;
+        final long fence;
+        final int origin;
+        final int bound;
+        RandomIntsSpliterator(SplittableRandom rng, long index, long fence,
+                              int origin, int bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomIntsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomIntsSpliterator(rng.split(), i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextInt(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                SplittableRandom r = rng;
+                int o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextInt(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+    /**
+     * Spliterator for long streams.
+     */
+    private static final class RandomLongsSpliterator
+            implements Spliterator.OfLong {
+        final SplittableRandom rng;
+        long index;
+        final long fence;
+        final long origin;
+        final long bound;
+        RandomLongsSpliterator(SplittableRandom rng, long index, long fence,
+                               long origin, long bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomLongsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomLongsSpliterator(rng.split(), i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextLong(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                SplittableRandom r = rng;
+                long o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextLong(o, b));
+                } while (++i < f);
+            }
+        }
+
+    }
+
+    /**
+     * Spliterator for double streams.
+     */
+    private static final class RandomDoublesSpliterator
+            implements Spliterator.OfDouble {
+        final SplittableRandom rng;
+        long index;
+        final long fence;
+        final double origin;
+        final double bound;
+        RandomDoublesSpliterator(SplittableRandom rng, long index, long fence,
+                                 double origin, double bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomDoublesSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomDoublesSpliterator(rng.split(), i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextDouble(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                SplittableRandom r = rng;
+                double o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextDouble(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+}
diff --git a/java/util/Stack.java b/java/util/Stack.java
new file mode 100644
index 0000000..ebea11e
--- /dev/null
+++ b/java/util/Stack.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * The <code>Stack</code> class represents a last-in-first-out
+ * (LIFO) stack of objects. It extends class <tt>Vector</tt> with five
+ * operations that allow a vector to be treated as a stack. The usual
+ * <tt>push</tt> and <tt>pop</tt> operations are provided, as well as a
+ * method to <tt>peek</tt> at the top item on the stack, a method to test
+ * for whether the stack is <tt>empty</tt>, and a method to <tt>search</tt>
+ * the stack for an item and discover how far it is from the top.
+ * <p>
+ * When a stack is first created, it contains no items.
+ *
+ * <p>A more complete and consistent set of LIFO stack operations is
+ * provided by the {@link Deque} interface and its implementations, which
+ * should be used in preference to this class.  For example:
+ * <pre>   {@code
+ *   Deque<Integer> stack = new ArrayDeque<Integer>();}</pre>
+ *
+ * @author  Jonathan Payne
+ * @since   JDK1.0
+ */
+public
+class Stack<E> extends Vector<E> {
+    /**
+     * Creates an empty Stack.
+     */
+    public Stack() {
+    }
+
+    /**
+     * Pushes an item onto the top of this stack. This has exactly
+     * the same effect as:
+     * <blockquote><pre>
+     * addElement(item)</pre></blockquote>
+     *
+     * @param   item   the item to be pushed onto this stack.
+     * @return  the <code>item</code> argument.
+     * @see     java.util.Vector#addElement
+     */
+    public E push(E item) {
+        addElement(item);
+
+        return item;
+    }
+
+    /**
+     * Removes the object at the top of this stack and returns that
+     * object as the value of this function.
+     *
+     * @return  The object at the top of this stack (the last item
+     *          of the <tt>Vector</tt> object).
+     * @throws  EmptyStackException  if this stack is empty.
+     */
+    public synchronized E pop() {
+        E       obj;
+        int     len = size();
+
+        obj = peek();
+        removeElementAt(len - 1);
+
+        return obj;
+    }
+
+    /**
+     * Looks at the object at the top of this stack without removing it
+     * from the stack.
+     *
+     * @return  the object at the top of this stack (the last item
+     *          of the <tt>Vector</tt> object).
+     * @throws  EmptyStackException  if this stack is empty.
+     */
+    public synchronized E peek() {
+        int     len = size();
+
+        if (len == 0)
+            throw new EmptyStackException();
+        return elementAt(len - 1);
+    }
+
+    /**
+     * Tests if this stack is empty.
+     *
+     * @return  <code>true</code> if and only if this stack contains
+     *          no items; <code>false</code> otherwise.
+     */
+    public boolean empty() {
+        return size() == 0;
+    }
+
+    /**
+     * Returns the 1-based position where an object is on this stack.
+     * If the object <tt>o</tt> occurs as an item in this stack, this
+     * method returns the distance from the top of the stack of the
+     * occurrence nearest the top of the stack; the topmost item on the
+     * stack is considered to be at distance <tt>1</tt>. The <tt>equals</tt>
+     * method is used to compare <tt>o</tt> to the
+     * items in this stack.
+     *
+     * @param   o   the desired object.
+     * @return  the 1-based position from the top of the stack where
+     *          the object is located; the return value <code>-1</code>
+     *          indicates that the object is not on the stack.
+     */
+    public synchronized int search(Object o) {
+        int i = lastIndexOf(o);
+
+        if (i >= 0) {
+            return size() - i;
+        }
+        return -1;
+    }
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = 1224463164541339165L;
+}
diff --git a/java/util/StringJoiner.java b/java/util/StringJoiner.java
new file mode 100644
index 0000000..b6ba84c
--- /dev/null
+++ b/java/util/StringJoiner.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+/**
+ * {@code StringJoiner} is used to construct a sequence of characters separated
+ * by a delimiter and optionally starting with a supplied prefix
+ * and ending with a supplied suffix.
+ * <p>
+ * Prior to adding something to the {@code StringJoiner}, its
+ * {@code sj.toString()} method will, by default, return {@code prefix + suffix}.
+ * However, if the {@code setEmptyValue} method is called, the {@code emptyValue}
+ * supplied will be returned instead. This can be used, for example, when
+ * creating a string using set notation to indicate an empty set, i.e.
+ * <code>"{}"</code>, where the {@code prefix} is <code>"{"</code>, the
+ * {@code suffix} is <code>"}"</code> and nothing has been added to the
+ * {@code StringJoiner}.
+ *
+ * @apiNote
+ * <p>The String {@code "[George:Sally:Fred]"} may be constructed as follows:
+ *
+ * <pre> {@code
+ * StringJoiner sj = new StringJoiner(":", "[", "]");
+ * sj.add("George").add("Sally").add("Fred");
+ * String desiredString = sj.toString();
+ * }</pre>
+ * <p>
+ * A {@code StringJoiner} may be employed to create formatted output from a
+ * {@link java.util.stream.Stream} using
+ * {@link java.util.stream.Collectors#joining(CharSequence)}. For example:
+ *
+ * <pre> {@code
+ * List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
+ * String commaSeparatedNumbers = numbers.stream()
+ *     .map(i -> i.toString())
+ *     .collect(Collectors.joining(", "));
+ * }</pre>
+ *
+ * @see java.util.stream.Collectors#joining(CharSequence)
+ * @see java.util.stream.Collectors#joining(CharSequence, CharSequence, CharSequence)
+ * @since  1.8
+*/
+public final class StringJoiner {
+    private final String prefix;
+    private final String delimiter;
+    private final String suffix;
+
+    /*
+     * StringBuilder value -- at any time, the characters constructed from the
+     * prefix, the added element separated by the delimiter, but without the
+     * suffix, so that we can more easily add elements without having to jigger
+     * the suffix each time.
+     */
+    private StringBuilder value;
+
+    /*
+     * By default, the string consisting of prefix+suffix, returned by
+     * toString(), or properties of value, when no elements have yet been added,
+     * i.e. when it is empty.  This may be overridden by the user to be some
+     * other value including the empty String.
+     */
+    private String emptyValue;
+
+    /**
+     * Constructs a {@code StringJoiner} with no characters in it, with no
+     * {@code prefix} or {@code suffix}, and a copy of the supplied
+     * {@code delimiter}.
+     * If no characters are added to the {@code StringJoiner} and methods
+     * accessing the value of it are invoked, it will not return a
+     * {@code prefix} or {@code suffix} (or properties thereof) in the result,
+     * unless {@code setEmptyValue} has first been called.
+     *
+     * @param  delimiter the sequence of characters to be used between each
+     *         element added to the {@code StringJoiner} value
+     * @throws NullPointerException if {@code delimiter} is {@code null}
+     */
+    public StringJoiner(CharSequence delimiter) {
+        this(delimiter, "", "");
+    }
+
+    /**
+     * Constructs a {@code StringJoiner} with no characters in it using copies
+     * of the supplied {@code prefix}, {@code delimiter} and {@code suffix}.
+     * If no characters are added to the {@code StringJoiner} and methods
+     * accessing the string value of it are invoked, it will return the
+     * {@code prefix + suffix} (or properties thereof) in the result, unless
+     * {@code setEmptyValue} has first been called.
+     *
+     * @param  delimiter the sequence of characters to be used between each
+     *         element added to the {@code StringJoiner}
+     * @param  prefix the sequence of characters to be used at the beginning
+     * @param  suffix the sequence of characters to be used at the end
+     * @throws NullPointerException if {@code prefix}, {@code delimiter}, or
+     *         {@code suffix} is {@code null}
+     */
+    public StringJoiner(CharSequence delimiter,
+                        CharSequence prefix,
+                        CharSequence suffix) {
+        Objects.requireNonNull(prefix, "The prefix must not be null");
+        Objects.requireNonNull(delimiter, "The delimiter must not be null");
+        Objects.requireNonNull(suffix, "The suffix must not be null");
+        // make defensive copies of arguments
+        this.prefix = prefix.toString();
+        this.delimiter = delimiter.toString();
+        this.suffix = suffix.toString();
+        this.emptyValue = this.prefix + this.suffix;
+    }
+
+    /**
+     * Sets the sequence of characters to be used when determining the string
+     * representation of this {@code StringJoiner} and no elements have been
+     * added yet, that is, when it is empty.  A copy of the {@code emptyValue}
+     * parameter is made for this purpose. Note that once an add method has been
+     * called, the {@code StringJoiner} is no longer considered empty, even if
+     * the element(s) added correspond to the empty {@code String}.
+     *
+     * @param  emptyValue the characters to return as the value of an empty
+     *         {@code StringJoiner}
+     * @return this {@code StringJoiner} itself so the calls may be chained
+     * @throws NullPointerException when the {@code emptyValue} parameter is
+     *         {@code null}
+     */
+    public StringJoiner setEmptyValue(CharSequence emptyValue) {
+        this.emptyValue = Objects.requireNonNull(emptyValue,
+            "The empty value must not be null").toString();
+        return this;
+    }
+
+    /**
+     * Returns the current value, consisting of the {@code prefix}, the values
+     * added so far separated by the {@code delimiter}, and the {@code suffix},
+     * unless no elements have been added in which case, the
+     * {@code prefix + suffix} or the {@code emptyValue} characters are returned
+     *
+     * @return the string representation of this {@code StringJoiner}
+     */
+    @Override
+    public String toString() {
+        if (value == null) {
+            return emptyValue;
+        } else {
+            if (suffix.equals("")) {
+                return value.toString();
+            } else {
+                int initialLength = value.length();
+                String result = value.append(suffix).toString();
+                // reset value to pre-append initialLength
+                value.setLength(initialLength);
+                return result;
+            }
+        }
+    }
+
+    /**
+     * Adds a copy of the given {@code CharSequence} value as the next
+     * element of the {@code StringJoiner} value. If {@code newElement} is
+     * {@code null}, then {@code "null"} is added.
+     *
+     * @param  newElement The element to add
+     * @return a reference to this {@code StringJoiner}
+     */
+    public StringJoiner add(CharSequence newElement) {
+        prepareBuilder().append(newElement);
+        return this;
+    }
+
+    /**
+     * Adds the contents of the given {@code StringJoiner} without prefix and
+     * suffix as the next element if it is non-empty. If the given {@code
+     * StringJoiner} is empty, the call has no effect.
+     *
+     * <p>A {@code StringJoiner} is empty if {@link #add(CharSequence) add()}
+     * has never been called, and if {@code merge()} has never been called
+     * with a non-empty {@code StringJoiner} argument.
+     *
+     * <p>If the other {@code StringJoiner} is using a different delimiter,
+     * then elements from the other {@code StringJoiner} are concatenated with
+     * that delimiter and the result is appended to this {@code StringJoiner}
+     * as a single element.
+     *
+     * @param other The {@code StringJoiner} whose contents should be merged
+     *              into this one
+     * @throws NullPointerException if the other {@code StringJoiner} is null
+     * @return This {@code StringJoiner}
+     */
+    public StringJoiner merge(StringJoiner other) {
+        Objects.requireNonNull(other);
+        if (other.value != null) {
+            final int length = other.value.length();
+            // lock the length so that we can seize the data to be appended
+            // before initiate copying to avoid interference, especially when
+            // merge 'this'
+            StringBuilder builder = prepareBuilder();
+            builder.append(other.value, other.prefix.length(), length);
+        }
+        return this;
+    }
+
+    private StringBuilder prepareBuilder() {
+        if (value != null) {
+            value.append(delimiter);
+        } else {
+            value = new StringBuilder().append(prefix);
+        }
+        return value;
+    }
+
+    /**
+     * Returns the length of the {@code String} representation
+     * of this {@code StringJoiner}. Note that if
+     * no add methods have been called, then the length of the {@code String}
+     * representation (either {@code prefix + suffix} or {@code emptyValue})
+     * will be returned. The value should be equivalent to
+     * {@code toString().length()}.
+     *
+     * @return the length of the current value of {@code StringJoiner}
+     */
+    public int length() {
+        // Remember that we never actually append the suffix unless we return
+        // the full (present) value or some sub-string or length of it, so that
+        // we can add on more if we need to.
+        return (value != null ? value.length() + suffix.length() :
+                emptyValue.length());
+    }
+}
diff --git a/java/util/StringTokenizer.java b/java/util/StringTokenizer.java
new file mode 100644
index 0000000..1540c1a
--- /dev/null
+++ b/java/util/StringTokenizer.java
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.lang.*;
+
+/**
+ * The string tokenizer class allows an application to break a
+ * string into tokens. The tokenization method is much simpler than
+ * the one used by the <code>StreamTokenizer</code> class. The
+ * <code>StringTokenizer</code> methods do not distinguish among
+ * identifiers, numbers, and quoted strings, nor do they recognize
+ * and skip comments.
+ * <p>
+ * The set of delimiters (the characters that separate tokens) may
+ * be specified either at creation time or on a per-token basis.
+ * <p>
+ * An instance of <code>StringTokenizer</code> behaves in one of two
+ * ways, depending on whether it was created with the
+ * <code>returnDelims</code> flag having the value <code>true</code>
+ * or <code>false</code>:
+ * <ul>
+ * <li>If the flag is <code>false</code>, delimiter characters serve to
+ *     separate tokens. A token is a maximal sequence of consecutive
+ *     characters that are not delimiters.
+ * <li>If the flag is <code>true</code>, delimiter characters are themselves
+ *     considered to be tokens. A token is thus either one delimiter
+ *     character, or a maximal sequence of consecutive characters that are
+ *     not delimiters.
+ * </ul><p>
+ * A <tt>StringTokenizer</tt> object internally maintains a current
+ * position within the string to be tokenized. Some operations advance this
+ * current position past the characters processed.<p>
+ * A token is returned by taking a substring of the string that was used to
+ * create the <tt>StringTokenizer</tt> object.
+ * <p>
+ * The following is one example of the use of the tokenizer. The code:
+ * <blockquote><pre>
+ *     StringTokenizer st = new StringTokenizer("this is a test");
+ *     while (st.hasMoreTokens()) {
+ *         System.out.println(st.nextToken());
+ *     }
+ * </pre></blockquote>
+ * <p>
+ * prints the following output:
+ * <blockquote><pre>
+ *     this
+ *     is
+ *     a
+ *     test
+ * </pre></blockquote>
+ *
+ * <p>
+ * <tt>StringTokenizer</tt> is a legacy class that is retained for
+ * compatibility reasons although its use is discouraged in new code. It is
+ * recommended that anyone seeking this functionality use the <tt>split</tt>
+ * method of <tt>String</tt> or the java.util.regex package instead.
+ * <p>
+ * The following example illustrates how the <tt>String.split</tt>
+ * method can be used to break up a string into its basic tokens:
+ * <blockquote><pre>
+ *     String[] result = "this is a test".split("\\s");
+ *     for (int x=0; x&lt;result.length; x++)
+ *         System.out.println(result[x]);
+ * </pre></blockquote>
+ * <p>
+ * prints the following output:
+ * <blockquote><pre>
+ *     this
+ *     is
+ *     a
+ *     test
+ * </pre></blockquote>
+ *
+ * @author  unascribed
+ * @see     java.io.StreamTokenizer
+ * @since   JDK1.0
+ */
+public
+class StringTokenizer implements Enumeration<Object> {
+    private int currentPosition;
+    private int newPosition;
+    private int maxPosition;
+    private String str;
+    private String delimiters;
+    private boolean retDelims;
+    private boolean delimsChanged;
+
+    /**
+     * maxDelimCodePoint stores the value of the delimiter character with the
+     * highest value. It is used to optimize the detection of delimiter
+     * characters.
+     *
+     * It is unlikely to provide any optimization benefit in the
+     * hasSurrogates case because most string characters will be
+     * smaller than the limit, but we keep it so that the two code
+     * paths remain similar.
+     */
+    private int maxDelimCodePoint;
+
+    /**
+     * If delimiters include any surrogates (including surrogate
+     * pairs), hasSurrogates is true and the tokenizer uses the
+     * different code path. This is because String.indexOf(int)
+     * doesn't handle unpaired surrogates as a single character.
+     */
+    private boolean hasSurrogates = false;
+
+    /**
+     * When hasSurrogates is true, delimiters are converted to code
+     * points and isDelimiter(int) is used to determine if the given
+     * codepoint is a delimiter.
+     */
+    private int[] delimiterCodePoints;
+
+    /**
+     * Set maxDelimCodePoint to the highest char in the delimiter set.
+     */
+    private void setMaxDelimCodePoint() {
+        if (delimiters == null) {
+            maxDelimCodePoint = 0;
+            return;
+        }
+
+        int m = 0;
+        int c;
+        int count = 0;
+        for (int i = 0; i < delimiters.length(); i += Character.charCount(c)) {
+            c = delimiters.charAt(i);
+            if (c >= Character.MIN_HIGH_SURROGATE && c <= Character.MAX_LOW_SURROGATE) {
+                c = delimiters.codePointAt(i);
+                hasSurrogates = true;
+            }
+            if (m < c)
+                m = c;
+            count++;
+        }
+        maxDelimCodePoint = m;
+
+        if (hasSurrogates) {
+            delimiterCodePoints = new int[count];
+            for (int i = 0, j = 0; i < count; i++, j += Character.charCount(c)) {
+                c = delimiters.codePointAt(j);
+                delimiterCodePoints[i] = c;
+            }
+        }
+    }
+
+    /**
+     * Constructs a string tokenizer for the specified string. All
+     * characters in the <code>delim</code> argument are the delimiters
+     * for separating tokens.
+     * <p>
+     * If the <code>returnDelims</code> flag is <code>true</code>, then
+     * the delimiter characters are also returned as tokens. Each
+     * delimiter is returned as a string of length one. If the flag is
+     * <code>false</code>, the delimiter characters are skipped and only
+     * serve as separators between tokens.
+     * <p>
+     * Note that if <tt>delim</tt> is <tt>null</tt>, this constructor does
+     * not throw an exception. However, trying to invoke other methods on the
+     * resulting <tt>StringTokenizer</tt> may result in a
+     * <tt>NullPointerException</tt>.
+     *
+     * @param   str            a string to be parsed.
+     * @param   delim          the delimiters.
+     * @param   returnDelims   flag indicating whether to return the delimiters
+     *                         as tokens.
+     * @exception NullPointerException if str is <CODE>null</CODE>
+     */
+    public StringTokenizer(String str, String delim, boolean returnDelims) {
+        currentPosition = 0;
+        newPosition = -1;
+        delimsChanged = false;
+        this.str = str;
+        maxPosition = str.length();
+        delimiters = delim;
+        retDelims = returnDelims;
+        setMaxDelimCodePoint();
+    }
+
+    /**
+     * Constructs a string tokenizer for the specified string. The
+     * characters in the <code>delim</code> argument are the delimiters
+     * for separating tokens. Delimiter characters themselves will not
+     * be treated as tokens.
+     * <p>
+     * Note that if <tt>delim</tt> is <tt>null</tt>, this constructor does
+     * not throw an exception. However, trying to invoke other methods on the
+     * resulting <tt>StringTokenizer</tt> may result in a
+     * <tt>NullPointerException</tt>.
+     *
+     * @param   str     a string to be parsed.
+     * @param   delim   the delimiters.
+     * @exception NullPointerException if str is <CODE>null</CODE>
+     */
+    public StringTokenizer(String str, String delim) {
+        this(str, delim, false);
+    }
+
+    /**
+     * Constructs a string tokenizer for the specified string. The
+     * tokenizer uses the default delimiter set, which is
+     * <code>"&nbsp;&#92;t&#92;n&#92;r&#92;f"</code>: the space character,
+     * the tab character, the newline character, the carriage-return character,
+     * and the form-feed character. Delimiter characters themselves will
+     * not be treated as tokens.
+     *
+     * @param   str   a string to be parsed.
+     * @exception NullPointerException if str is <CODE>null</CODE>
+     */
+    public StringTokenizer(String str) {
+        this(str, " \t\n\r\f", false);
+    }
+
+    /**
+     * Skips delimiters starting from the specified position. If retDelims
+     * is false, returns the index of the first non-delimiter character at or
+     * after startPos. If retDelims is true, startPos is returned.
+     */
+    private int skipDelimiters(int startPos) {
+        if (delimiters == null)
+            throw new NullPointerException();
+
+        int position = startPos;
+        while (!retDelims && position < maxPosition) {
+            if (!hasSurrogates) {
+                char c = str.charAt(position);
+                if ((c > maxDelimCodePoint) || (delimiters.indexOf(c) < 0))
+                    break;
+                position++;
+            } else {
+                int c = str.codePointAt(position);
+                if ((c > maxDelimCodePoint) || !isDelimiter(c)) {
+                    break;
+                }
+                position += Character.charCount(c);
+            }
+        }
+        return position;
+    }
+
+    /**
+     * Skips ahead from startPos and returns the index of the next delimiter
+     * character encountered, or maxPosition if no such delimiter is found.
+     */
+    private int scanToken(int startPos) {
+        int position = startPos;
+        while (position < maxPosition) {
+            if (!hasSurrogates) {
+                char c = str.charAt(position);
+                if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
+                    break;
+                position++;
+            } else {
+                int c = str.codePointAt(position);
+                if ((c <= maxDelimCodePoint) && isDelimiter(c))
+                    break;
+                position += Character.charCount(c);
+            }
+        }
+        if (retDelims && (startPos == position)) {
+            if (!hasSurrogates) {
+                char c = str.charAt(position);
+                if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
+                    position++;
+            } else {
+                int c = str.codePointAt(position);
+                if ((c <= maxDelimCodePoint) && isDelimiter(c))
+                    position += Character.charCount(c);
+            }
+        }
+        return position;
+    }
+
+    private boolean isDelimiter(int codePoint) {
+        for (int i = 0; i < delimiterCodePoints.length; i++) {
+            if (delimiterCodePoints[i] == codePoint) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tests if there are more tokens available from this tokenizer's string.
+     * If this method returns <tt>true</tt>, then a subsequent call to
+     * <tt>nextToken</tt> with no argument will successfully return a token.
+     *
+     * @return  <code>true</code> if and only if there is at least one token
+     *          in the string after the current position; <code>false</code>
+     *          otherwise.
+     */
+    public boolean hasMoreTokens() {
+        /*
+         * Temporarily store this position and use it in the following
+         * nextToken() method only if the delimiters haven't been changed in
+         * that nextToken() invocation.
+         */
+        newPosition = skipDelimiters(currentPosition);
+        return (newPosition < maxPosition);
+    }
+
+    /**
+     * Returns the next token from this string tokenizer.
+     *
+     * @return     the next token from this string tokenizer.
+     * @exception  NoSuchElementException  if there are no more tokens in this
+     *               tokenizer's string.
+     */
+    public String nextToken() {
+        /*
+         * If next position already computed in hasMoreElements() and
+         * delimiters have changed between the computation and this invocation,
+         * then use the computed value.
+         */
+
+        currentPosition = (newPosition >= 0 && !delimsChanged) ?
+            newPosition : skipDelimiters(currentPosition);
+
+        /* Reset these anyway */
+        delimsChanged = false;
+        newPosition = -1;
+
+        if (currentPosition >= maxPosition)
+            throw new NoSuchElementException();
+        int start = currentPosition;
+        currentPosition = scanToken(currentPosition);
+        return str.substring(start, currentPosition);
+    }
+
+    /**
+     * Returns the next token in this string tokenizer's string. First,
+     * the set of characters considered to be delimiters by this
+     * <tt>StringTokenizer</tt> object is changed to be the characters in
+     * the string <tt>delim</tt>. Then the next token in the string
+     * after the current position is returned. The current position is
+     * advanced beyond the recognized token.  The new delimiter set
+     * remains the default after this call.
+     *
+     * @param      delim   the new delimiters.
+     * @return     the next token, after switching to the new delimiter set.
+     * @exception  NoSuchElementException  if there are no more tokens in this
+     *               tokenizer's string.
+     * @exception NullPointerException if delim is <CODE>null</CODE>
+     */
+    public String nextToken(String delim) {
+        delimiters = delim;
+
+        /* delimiter string specified, so set the appropriate flag. */
+        delimsChanged = true;
+
+        setMaxDelimCodePoint();
+        return nextToken();
+    }
+
+    /**
+     * Returns the same value as the <code>hasMoreTokens</code>
+     * method. It exists so that this class can implement the
+     * <code>Enumeration</code> interface.
+     *
+     * @return  <code>true</code> if there are more tokens;
+     *          <code>false</code> otherwise.
+     * @see     java.util.Enumeration
+     * @see     java.util.StringTokenizer#hasMoreTokens()
+     */
+    public boolean hasMoreElements() {
+        return hasMoreTokens();
+    }
+
+    /**
+     * Returns the same value as the <code>nextToken</code> method,
+     * except that its declared return value is <code>Object</code> rather than
+     * <code>String</code>. It exists so that this class can implement the
+     * <code>Enumeration</code> interface.
+     *
+     * @return     the next token in the string.
+     * @exception  NoSuchElementException  if there are no more tokens in this
+     *               tokenizer's string.
+     * @see        java.util.Enumeration
+     * @see        java.util.StringTokenizer#nextToken()
+     */
+    public Object nextElement() {
+        return nextToken();
+    }
+
+    /**
+     * Calculates the number of times that this tokenizer's
+     * <code>nextToken</code> method can be called before it generates an
+     * exception. The current position is not advanced.
+     *
+     * @return  the number of tokens remaining in the string using the current
+     *          delimiter set.
+     * @see     java.util.StringTokenizer#nextToken()
+     */
+    public int countTokens() {
+        int count = 0;
+        int currpos = currentPosition;
+        while (currpos < maxPosition) {
+            currpos = skipDelimiters(currpos);
+            if (currpos >= maxPosition)
+                break;
+            currpos = scanToken(currpos);
+            count++;
+        }
+        return count;
+    }
+}
diff --git a/java/util/TimSort.java b/java/util/TimSort.java
new file mode 100644
index 0000000..ea0d58f
--- /dev/null
+++ b/java/util/TimSort.java
@@ -0,0 +1,941 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A stable, adaptive, iterative mergesort that requires far fewer than
+ * n lg(n) comparisons when running on partially sorted arrays, while
+ * offering performance comparable to a traditional mergesort when run
+ * on random arrays.  Like all proper mergesorts, this sort is stable and
+ * runs O(n log n) time (worst case).  In the worst case, this sort requires
+ * temporary storage space for n/2 object references; in the best case,
+ * it requires only a small constant amount of space.
+ *
+ * This implementation was adapted from Tim Peters's list sort for
+ * Python, which is described in detail here:
+ *
+ *   http://svn.python.org/projects/python/trunk/Objects/listsort.txt
+ *
+ * Tim's C code may be found here:
+ *
+ *   http://svn.python.org/projects/python/trunk/Objects/listobject.c
+ *
+ * The underlying techniques are described in this paper (and may have
+ * even earlier origins):
+ *
+ *  "Optimistic Sorting and Information Theoretic Complexity"
+ *  Peter McIlroy
+ *  SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms),
+ *  pp 467-474, Austin, Texas, 25-27 January 1993.
+ *
+ * While the API to this class consists solely of static methods, it is
+ * (privately) instantiable; a TimSort instance holds the state of an ongoing
+ * sort, assuming the input array is large enough to warrant the full-blown
+ * TimSort. Small arrays are sorted in place, using a binary insertion sort.
+ *
+ * @author Josh Bloch
+ */
+class TimSort<T> {
+    /**
+     * This is the minimum sized sequence that will be merged.  Shorter
+     * sequences will be lengthened by calling binarySort.  If the entire
+     * array is less than this length, no merges will be performed.
+     *
+     * This constant should be a power of two.  It was 64 in Tim Peter's C
+     * implementation, but 32 was empirically determined to work better in
+     * this implementation.  In the unlikely event that you set this constant
+     * to be a number that's not a power of two, you'll need to change the
+     * {@link #minRunLength} computation.
+     *
+     * If you decrease this constant, you must change the stackLen
+     * computation in the TimSort constructor, or you risk an
+     * ArrayOutOfBounds exception.  See listsort.txt for a discussion
+     * of the minimum stack length required as a function of the length
+     * of the array being sorted and the minimum merge sequence length.
+     */
+    private static final int MIN_MERGE = 32;
+
+    /**
+     * The array being sorted.
+     */
+    private final T[] a;
+
+    /**
+     * The comparator for this sort.
+     */
+    private final Comparator<? super T> c;
+
+    /**
+     * When we get into galloping mode, we stay there until both runs win less
+     * often than MIN_GALLOP consecutive times.
+     */
+    private static final int  MIN_GALLOP = 7;
+
+    /**
+     * This controls when we get *into* galloping mode.  It is initialized
+     * to MIN_GALLOP.  The mergeLo and mergeHi methods nudge it higher for
+     * random data, and lower for highly structured data.
+     */
+    private int minGallop = MIN_GALLOP;
+
+    /**
+     * Maximum initial size of tmp array, which is used for merging.  The array
+     * can grow to accommodate demand.
+     *
+     * Unlike Tim's original C version, we do not allocate this much storage
+     * when sorting smaller arrays.  This change was required for performance.
+     */
+    private static final int INITIAL_TMP_STORAGE_LENGTH = 256;
+
+    /**
+     * Temp storage for merges. A workspace array may optionally be
+     * provided in constructor, and if so will be used as long as it
+     * is big enough.
+     */
+    private T[] tmp;
+    private int tmpBase; // base of tmp array slice
+    private int tmpLen;  // length of tmp array slice
+
+    /**
+     * A stack of pending runs yet to be merged.  Run i starts at
+     * address base[i] and extends for len[i] elements.  It's always
+     * true (so long as the indices are in bounds) that:
+     *
+     *     runBase[i] + runLen[i] == runBase[i + 1]
+     *
+     * so we could cut the storage for this, but it's a minor amount,
+     * and keeping all the info explicit simplifies the code.
+     */
+    private int stackSize = 0;  // Number of pending runs on stack
+    private final int[] runBase;
+    private final int[] runLen;
+
+    /**
+     * Creates a TimSort instance to maintain the state of an ongoing sort.
+     *
+     * @param a the array to be sorted
+     * @param c the comparator to determine the order of the sort
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private TimSort(T[] a, Comparator<? super T> c, T[] work, int workBase, int workLen) {
+        this.a = a;
+        this.c = c;
+
+        // Allocate temp storage (which may be increased later if necessary)
+        int len = a.length;
+        int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?
+            len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;
+        if (work == null || workLen < tlen || workBase + tlen > work.length) {
+            @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
+            T[] newArray = (T[])java.lang.reflect.Array.newInstance
+                (a.getClass().getComponentType(), tlen);
+            tmp = newArray;
+            tmpBase = 0;
+            tmpLen = tlen;
+        }
+        else {
+            tmp = work;
+            tmpBase = workBase;
+            tmpLen = workLen;
+        }
+
+        /*
+         * Allocate runs-to-be-merged stack (which cannot be expanded).  The
+         * stack length requirements are described in listsort.txt.  The C
+         * version always uses the same stack length (85), but this was
+         * measured to be too expensive when sorting "mid-sized" arrays (e.g.,
+         * 100 elements) in Java.  Therefore, we use smaller (but sufficiently
+         * large) stack lengths for smaller arrays.  The "magic numbers" in the
+         * computation below must be changed if MIN_MERGE is decreased.  See
+         * the MIN_MERGE declaration above for more information.
+         * The maximum value of 49 allows for an array up to length
+         * Integer.MAX_VALUE-4, if array is filled by the worst case stack size
+         * increasing scenario. More explanations are given in section 4 of:
+         * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf
+         */
+        int stackLen = (len <    120  ?  5 :
+                        len <   1542  ? 10 :
+                        len < 119151  ? 24 : 49);
+        runBase = new int[stackLen];
+        runLen = new int[stackLen];
+    }
+
+    /*
+     * The next method (package private and static) constitutes the
+     * entire API of this class.
+     */
+
+    /**
+     * Sorts the given range, using the given workspace array slice
+     * for temp storage when possible. This method is designed to be
+     * invoked from public methods (in class Arrays) after performing
+     * any necessary array bounds checks and expanding parameters into
+     * the required forms.
+     *
+     * @param a the array to be sorted
+     * @param lo the index of the first element, inclusive, to be sorted
+     * @param hi the index of the last element, exclusive, to be sorted
+     * @param c the comparator to use
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     * @since 1.8
+     */
+    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
+                         T[] work, int workBase, int workLen) {
+        assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;
+
+        int nRemaining  = hi - lo;
+        if (nRemaining < 2)
+            return;  // Arrays of size 0 and 1 are always sorted
+
+        // If array is small, do a "mini-TimSort" with no merges
+        if (nRemaining < MIN_MERGE) {
+            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
+            binarySort(a, lo, hi, lo + initRunLen, c);
+            return;
+        }
+
+        /**
+         * March over the array once, left to right, finding natural runs,
+         * extending short natural runs to minRun elements, and merging runs
+         * to maintain stack invariant.
+         */
+        TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen);
+        int minRun = minRunLength(nRemaining);
+        do {
+            // Identify next run
+            int runLen = countRunAndMakeAscending(a, lo, hi, c);
+
+            // If run is short, extend to min(minRun, nRemaining)
+            if (runLen < minRun) {
+                int force = nRemaining <= minRun ? nRemaining : minRun;
+                binarySort(a, lo, lo + force, lo + runLen, c);
+                runLen = force;
+            }
+
+            // Push run onto pending-run stack, and maybe merge
+            ts.pushRun(lo, runLen);
+            ts.mergeCollapse();
+
+            // Advance to find next run
+            lo += runLen;
+            nRemaining -= runLen;
+        } while (nRemaining != 0);
+
+        // Merge all remaining runs to complete sort
+        assert lo == hi;
+        ts.mergeForceCollapse();
+        assert ts.stackSize == 1;
+    }
+
+    /**
+     * Sorts the specified portion of the specified array using a binary
+     * insertion sort.  This is the best method for sorting small numbers
+     * of elements.  It requires O(n log n) compares, but O(n^2) data
+     * movement (worst case).
+     *
+     * If the initial part of the specified range is already sorted,
+     * this method can take advantage of it: the method assumes that the
+     * elements from index {@code lo}, inclusive, to {@code start},
+     * exclusive are already sorted.
+     *
+     * @param a the array in which a range is to be sorted
+     * @param lo the index of the first element in the range to be sorted
+     * @param hi the index after the last element in the range to be sorted
+     * @param start the index of the first element in the range that is
+     *        not already known to be sorted ({@code lo <= start <= hi})
+     * @param c comparator to used for the sort
+     */
+    @SuppressWarnings("fallthrough")
+    private static <T> void binarySort(T[] a, int lo, int hi, int start,
+                                       Comparator<? super T> c) {
+        assert lo <= start && start <= hi;
+        if (start == lo)
+            start++;
+        for ( ; start < hi; start++) {
+            T pivot = a[start];
+
+            // Set left (and right) to the index where a[start] (pivot) belongs
+            int left = lo;
+            int right = start;
+            assert left <= right;
+            /*
+             * Invariants:
+             *   pivot >= all in [lo, left).
+             *   pivot <  all in [right, start).
+             */
+            while (left < right) {
+                int mid = (left + right) >>> 1;
+                if (c.compare(pivot, a[mid]) < 0)
+                    right = mid;
+                else
+                    left = mid + 1;
+            }
+            assert left == right;
+
+            /*
+             * The invariants still hold: pivot >= all in [lo, left) and
+             * pivot < all in [left, start), so pivot belongs at left.  Note
+             * that if there are elements equal to pivot, left points to the
+             * first slot after them -- that's why this sort is stable.
+             * Slide elements over to make room for pivot.
+             */
+            int n = start - left;  // The number of elements to move
+            // Switch is just an optimization for arraycopy in default case
+            switch (n) {
+                case 2:  a[left + 2] = a[left + 1];
+                case 1:  a[left + 1] = a[left];
+                         break;
+                default: System.arraycopy(a, left, a, left + 1, n);
+            }
+            a[left] = pivot;
+        }
+    }
+
+    /**
+     * Returns the length of the run beginning at the specified position in
+     * the specified array and reverses the run if it is descending (ensuring
+     * that the run will always be ascending when the method returns).
+     *
+     * A run is the longest ascending sequence with:
+     *
+     *    a[lo] <= a[lo + 1] <= a[lo + 2] <= ...
+     *
+     * or the longest descending sequence with:
+     *
+     *    a[lo] >  a[lo + 1] >  a[lo + 2] >  ...
+     *
+     * For its intended use in a stable mergesort, the strictness of the
+     * definition of "descending" is needed so that the call can safely
+     * reverse a descending sequence without violating stability.
+     *
+     * @param a the array in which a run is to be counted and possibly reversed
+     * @param lo index of the first element in the run
+     * @param hi index after the last element that may be contained in the run.
+              It is required that {@code lo < hi}.
+     * @param c the comparator to used for the sort
+     * @return  the length of the run beginning at the specified position in
+     *          the specified array
+     */
+    private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,
+                                                    Comparator<? super T> c) {
+        assert lo < hi;
+        int runHi = lo + 1;
+        if (runHi == hi)
+            return 1;
+
+        // Find end of run, and reverse range if descending
+        if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
+            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
+                runHi++;
+            reverseRange(a, lo, runHi);
+        } else {                              // Ascending
+            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
+                runHi++;
+        }
+
+        return runHi - lo;
+    }
+
+    /**
+     * Reverse the specified range of the specified array.
+     *
+     * @param a the array in which a range is to be reversed
+     * @param lo the index of the first element in the range to be reversed
+     * @param hi the index after the last element in the range to be reversed
+     */
+    private static void reverseRange(Object[] a, int lo, int hi) {
+        hi--;
+        while (lo < hi) {
+            Object t = a[lo];
+            a[lo++] = a[hi];
+            a[hi--] = t;
+        }
+    }
+
+    /**
+     * Returns the minimum acceptable run length for an array of the specified
+     * length. Natural runs shorter than this will be extended with
+     * {@link #binarySort}.
+     *
+     * Roughly speaking, the computation is:
+     *
+     *  If n < MIN_MERGE, return n (it's too small to bother with fancy stuff).
+     *  Else if n is an exact power of 2, return MIN_MERGE/2.
+     *  Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k
+     *   is close to, but strictly less than, an exact power of 2.
+     *
+     * For the rationale, see listsort.txt.
+     *
+     * @param n the length of the array to be sorted
+     * @return the length of the minimum run to be merged
+     */
+    private static int minRunLength(int n) {
+        assert n >= 0;
+        int r = 0;      // Becomes 1 if any 1 bits are shifted off
+        while (n >= MIN_MERGE) {
+            r |= (n & 1);
+            n >>= 1;
+        }
+        return n + r;
+    }
+
+    /**
+     * Pushes the specified run onto the pending-run stack.
+     *
+     * @param runBase index of the first element in the run
+     * @param runLen  the number of elements in the run
+     */
+    private void pushRun(int runBase, int runLen) {
+        this.runBase[stackSize] = runBase;
+        this.runLen[stackSize] = runLen;
+        stackSize++;
+    }
+
+    /**
+     * Examines the stack of runs waiting to be merged and merges adjacent runs
+     * until the stack invariants are reestablished:
+     *
+     *     1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1]
+     *     2. runLen[i - 2] > runLen[i - 1]
+     *
+     * This method is called each time a new run is pushed onto the stack,
+     * so the invariants are guaranteed to hold for i < stackSize upon
+     * entry to the method.
+     */
+    private void mergeCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1]) {
+                if (runLen[n - 1] < runLen[n + 1])
+                    n--;
+                mergeAt(n);
+            } else if (runLen[n] <= runLen[n + 1]) {
+                mergeAt(n);
+            } else {
+                break; // Invariant is established
+            }
+        }
+    }
+
+    /**
+     * Merges all runs on the stack until only one remains.  This method is
+     * called once, to complete the sort.
+     */
+    private void mergeForceCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n - 1] < runLen[n + 1])
+                n--;
+            mergeAt(n);
+        }
+    }
+
+    /**
+     * Merges the two runs at stack indices i and i+1.  Run i must be
+     * the penultimate or antepenultimate run on the stack.  In other words,
+     * i must be equal to stackSize-2 or stackSize-3.
+     *
+     * @param i stack index of the first of the two runs to merge
+     */
+    private void mergeAt(int i) {
+        assert stackSize >= 2;
+        assert i >= 0;
+        assert i == stackSize - 2 || i == stackSize - 3;
+
+        int base1 = runBase[i];
+        int len1 = runLen[i];
+        int base2 = runBase[i + 1];
+        int len2 = runLen[i + 1];
+        assert len1 > 0 && len2 > 0;
+        assert base1 + len1 == base2;
+
+        /*
+         * Record the length of the combined runs; if i is the 3rd-last
+         * run now, also slide over the last run (which isn't involved
+         * in this merge).  The current run (i+1) goes away in any case.
+         */
+        runLen[i] = len1 + len2;
+        if (i == stackSize - 3) {
+            runBase[i + 1] = runBase[i + 2];
+            runLen[i + 1] = runLen[i + 2];
+        }
+        stackSize--;
+
+        /*
+         * Find where the first element of run2 goes in run1. Prior elements
+         * in run1 can be ignored (because they're already in place).
+         */
+        int k = gallopRight(a[base2], a, base1, len1, 0, c);
+        assert k >= 0;
+        base1 += k;
+        len1 -= k;
+        if (len1 == 0)
+            return;
+
+        /*
+         * Find where the last element of run1 goes in run2. Subsequent elements
+         * in run2 can be ignored (because they're already in place).
+         */
+        len2 = gallopLeft(a[base1 + len1 - 1], a, base2, len2, len2 - 1, c);
+        assert len2 >= 0;
+        if (len2 == 0)
+            return;
+
+        // Merge remaining runs, using tmp array with min(len1, len2) elements
+        if (len1 <= len2)
+            mergeLo(base1, len1, base2, len2);
+        else
+            mergeHi(base1, len1, base2, len2);
+    }
+
+    /**
+     * Locates the position at which to insert the specified key into the
+     * specified sorted range; if the range contains an element equal to key,
+     * returns the index of the leftmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @param c the comparator used to order the range, and to search
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] < key <= a[b + k],
+     *    pretending that a[b - 1] is minus infinity and a[b + n] is infinity.
+     *    In other words, key belongs at index b + k; or in other words,
+     *    the first k elements of a should precede key, and the last n - k
+     *    should follow it.
+     */
+    private static <T> int gallopLeft(T key, T[] a, int base, int len, int hint,
+                                      Comparator<? super T> c) {
+        assert len > 0 && hint >= 0 && hint < len;
+        int lastOfs = 0;
+        int ofs = 1;
+        if (c.compare(key, a[base + hint]) > 0) {
+            // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && c.compare(key, a[base + hint + ofs]) > 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            lastOfs += hint;
+            ofs += hint;
+        } else { // key <= a[base + hint]
+            // Gallop left until a[base+hint-ofs] < key <= a[base+hint-lastOfs]
+            final int maxOfs = hint + 1;
+            while (ofs < maxOfs && c.compare(key, a[base + hint - ofs]) <= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[base+lastOfs] < key <= a[base+ofs], so key belongs somewhere
+         * to the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[base + lastOfs - 1] < key <= a[base + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (c.compare(key, a[base + m]) > 0)
+                lastOfs = m + 1;  // a[base + m] < key
+            else
+                ofs = m;          // key <= a[base + m]
+        }
+        assert lastOfs == ofs;    // so a[base + ofs - 1] < key <= a[base + ofs]
+        return ofs;
+    }
+
+    /**
+     * Like gallopLeft, except that if the range contains an element equal to
+     * key, gallopRight returns the index after the rightmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @param c the comparator used to order the range, and to search
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] <= key < a[b + k]
+     */
+    private static <T> int gallopRight(T key, T[] a, int base, int len,
+                                       int hint, Comparator<? super T> c) {
+        assert len > 0 && hint >= 0 && hint < len;
+
+        int ofs = 1;
+        int lastOfs = 0;
+        if (c.compare(key, a[base + hint]) < 0) {
+            // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs]
+            int maxOfs = hint + 1;
+            while (ofs < maxOfs && c.compare(key, a[base + hint - ofs]) < 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        } else { // a[b + hint] <= key
+            // Gallop right until a[b+hint + lastOfs] <= key < a[b+hint + ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && c.compare(key, a[base + hint + ofs]) >= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            lastOfs += hint;
+            ofs += hint;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[b + lastOfs] <= key < a[b + ofs], so key belongs somewhere to
+         * the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[b + lastOfs - 1] <= key < a[b + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (c.compare(key, a[base + m]) < 0)
+                ofs = m;          // key < a[b + m]
+            else
+                lastOfs = m + 1;  // a[b + m] <= key
+        }
+        assert lastOfs == ofs;    // so a[b + ofs - 1] <= key < a[b + ofs]
+        return ofs;
+    }
+
+    /**
+     * Merges two adjacent runs in place, in a stable fashion.  The first
+     * element of the first run must be greater than the first element of the
+     * second run (a[base1] > a[base2]), and the last element of the first run
+     * (a[base1 + len1-1]) must be greater than all elements of the second run.
+     *
+     * For performance, this method should be called only when len1 <= len2;
+     * its twin, mergeHi should be called if len1 >= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    private void mergeLo(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy first run into temp array
+        T[] a = this.a; // For performance
+        T[] tmp = ensureCapacity(len1);
+        int cursor1 = tmpBase; // Indexes into tmp array
+        int cursor2 = base2;   // Indexes int a
+        int dest = base1;      // Indexes int a
+        System.arraycopy(a, base1, tmp, cursor1, len1);
+
+        // Move first element of second run and deal with degenerate cases
+        a[dest++] = a[cursor2++];
+        if (--len2 == 0) {
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+            return;
+        }
+        if (len1 == 1) {
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; // Last elt of run 1 to end of merge
+            return;
+        }
+
+        Comparator<? super T> c = this.c;  // Use local variable for performance
+        int minGallop = this.minGallop;    //  "    "       "     "      "
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run starts
+             * winning consistently.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                if (c.compare(a[cursor2], tmp[cursor1]) < 0) {
+                    a[dest++] = a[cursor2++];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 0)
+                        break outer;
+                } else {
+                    a[dest++] = tmp[cursor1++];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                count1 = gallopRight(a[cursor2], tmp, cursor1, len1, 0, c);
+                if (count1 != 0) {
+                    System.arraycopy(tmp, cursor1, a, dest, count1);
+                    dest += count1;
+                    cursor1 += count1;
+                    len1 -= count1;
+                    if (len1 <= 1) // len1 == 1 || len1 == 0
+                        break outer;
+                }
+                a[dest++] = a[cursor2++];
+                if (--len2 == 0)
+                    break outer;
+
+                count2 = gallopLeft(tmp[cursor1], a, cursor2, len2, 0, c);
+                if (count2 != 0) {
+                    System.arraycopy(a, cursor2, a, dest, count2);
+                    dest += count2;
+                    cursor2 += count2;
+                    len2 -= count2;
+                    if (len2 == 0)
+                        break outer;
+                }
+                a[dest++] = tmp[cursor1++];
+                if (--len1 == 1)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len1 == 1) {
+            assert len2 > 0;
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; //  Last elt of run 1 to end of merge
+        } else if (len1 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len2 == 0;
+            assert len1 > 1;
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+        }
+    }
+
+    /**
+     * Like mergeLo, except that this method should be called only if
+     * len1 >= len2; mergeLo should be called if len1 <= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    private void mergeHi(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy second run into temp array
+        T[] a = this.a; // For performance
+        T[] tmp = ensureCapacity(len2);
+        int tmpBase = this.tmpBase;
+        System.arraycopy(a, base2, tmp, tmpBase, len2);
+
+        int cursor1 = base1 + len1 - 1;  // Indexes into a
+        int cursor2 = tmpBase + len2 - 1; // Indexes into tmp array
+        int dest = base2 + len2 - 1;     // Indexes into a
+
+        // Move last element of first run and deal with degenerate cases
+        a[dest--] = a[cursor1--];
+        if (--len1 == 0) {
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+            return;
+        }
+        if (len2 == 1) {
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];
+            return;
+        }
+
+        Comparator<? super T> c = this.c;  // Use local variable for performance
+        int minGallop = this.minGallop;    //  "    "       "     "      "
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run
+             * appears to win consistently.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                if (c.compare(tmp[cursor2], a[cursor1]) < 0) {
+                    a[dest--] = a[cursor1--];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 0)
+                        break outer;
+                } else {
+                    a[dest--] = tmp[cursor2--];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                count1 = len1 - gallopRight(tmp[cursor2], a, base1, len1, len1 - 1, c);
+                if (count1 != 0) {
+                    dest -= count1;
+                    cursor1 -= count1;
+                    len1 -= count1;
+                    System.arraycopy(a, cursor1 + 1, a, dest + 1, count1);
+                    if (len1 == 0)
+                        break outer;
+                }
+                a[dest--] = tmp[cursor2--];
+                if (--len2 == 1)
+                    break outer;
+
+                count2 = len2 - gallopLeft(a[cursor1], tmp, tmpBase, len2, len2 - 1, c);
+                if (count2 != 0) {
+                    dest -= count2;
+                    cursor2 -= count2;
+                    len2 -= count2;
+                    System.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2);
+                    if (len2 <= 1)  // len2 == 1 || len2 == 0
+                        break outer;
+                }
+                a[dest--] = a[cursor1--];
+                if (--len1 == 0)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len2 == 1) {
+            assert len1 > 0;
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];  // Move first elt of run2 to front of merge
+        } else if (len2 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len1 == 0;
+            assert len2 > 0;
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+        }
+    }
+
+    /**
+     * Ensures that the external array tmp has at least the specified
+     * number of elements, increasing its size if necessary.  The size
+     * increases exponentially to ensure amortized linear time complexity.
+     *
+     * @param minCapacity the minimum required capacity of the tmp array
+     * @return tmp, whether or not it grew
+     */
+    private T[] ensureCapacity(int minCapacity) {
+        if (tmpLen < minCapacity) {
+            // Compute smallest power of 2 > minCapacity
+            int newSize = minCapacity;
+            newSize |= newSize >> 1;
+            newSize |= newSize >> 2;
+            newSize |= newSize >> 4;
+            newSize |= newSize >> 8;
+            newSize |= newSize >> 16;
+            newSize++;
+
+            if (newSize < 0) // Not bloody likely!
+                newSize = minCapacity;
+            else
+                newSize = Math.min(newSize, a.length >>> 1);
+
+            @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
+            T[] newArray = (T[])java.lang.reflect.Array.newInstance
+                (a.getClass().getComponentType(), newSize);
+            tmp = newArray;
+            tmpLen = newSize;
+            tmpBase = 0;
+        }
+        return tmp;
+    }
+}
diff --git a/java/util/TimeZone.java b/java/util/TimeZone.java
new file mode 100644
index 0000000..cf5e5f8
--- /dev/null
+++ b/java/util/TimeZone.java
@@ -0,0 +1,798 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import android.icu.text.TimeZoneNames;
+import java.io.IOException;
+import java.io.Serializable;
+import java.time.ZoneId;
+import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import libcore.io.IoUtils;
+import libcore.timezone.ZoneInfoDb;
+
+import dalvik.system.RuntimeHooks;
+
+/**
+ * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
+ * savings.
+ *
+ * <p>
+ * Typically, you get a <code>TimeZone</code> using <code>getDefault</code>
+ * which creates a <code>TimeZone</code> based on the time zone where the program
+ * is running. For example, for a program running in Japan, <code>getDefault</code>
+ * creates a <code>TimeZone</code> object based on Japanese Standard Time.
+ *
+ * <p>
+ * You can also get a <code>TimeZone</code> using <code>getTimeZone</code>
+ * along with a time zone ID. For instance, the time zone ID for the
+ * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
+ * U.S. Pacific Time <code>TimeZone</code> object with:
+ * <blockquote><pre>
+ * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ * </pre></blockquote>
+ * You can use the <code>getAvailableIDs</code> method to iterate through
+ * all the supported time zone IDs. You can then choose a
+ * supported ID to get a <code>TimeZone</code>.
+ * If the time zone you want is not represented by one of the
+ * supported IDs, then a custom time zone ID can be specified to
+ * produce a TimeZone. The syntax of a custom time zone ID is:
+ *
+ * <blockquote><pre>
+ * <a name="CustomID"><i>CustomID:</i></a>
+ *         <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
+ *         <code>GMT</code> <i>Sign</i> <i>Hours</i> <i>Minutes</i>
+ *         <code>GMT</code> <i>Sign</i> <i>Hours</i>
+ * <i>Sign:</i> one of
+ *         <code>+ -</code>
+ * <i>Hours:</i>
+ *         <i>Digit</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Minutes:</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Digit:</i> one of
+ *         <code>0 1 2 3 4 5 6 7 8 9</code>
+ * </pre></blockquote>
+ *
+ * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be
+ * between 00 to 59.  For example, "GMT+10" and "GMT+0010" mean ten
+ * hours and ten minutes ahead of GMT, respectively.
+ * <p>
+ * The format is locale independent and digits must be taken from the
+ * Basic Latin block of the Unicode standard. No daylight saving time
+ * transition schedule can be specified with a custom time zone ID. If
+ * the specified string doesn't match the syntax, <code>"GMT"</code>
+ * is used.
+ * <p>
+ * When creating a <code>TimeZone</code>, the specified custom time
+ * zone ID is normalized in the following syntax:
+ * <blockquote><pre>
+ * <a name="NormalizedCustomID"><i>NormalizedCustomID:</i></a>
+ *         <code>GMT</code> <i>Sign</i> <i>TwoDigitHours</i> <code>:</code> <i>Minutes</i>
+ * <i>Sign:</i> one of
+ *         <code>+ -</code>
+ * <i>TwoDigitHours:</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Minutes:</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Digit:</i> one of
+ *         <code>0 1 2 3 4 5 6 7 8 9</code>
+ * </pre></blockquote>
+ * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00".
+ *
+ * <h3>Three-letter time zone IDs</h3>
+ *
+ * For compatibility with JDK 1.1.x, some other three-letter time zone IDs
+ * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
+ * use is deprecated</strong> because the same abbreviation is often used
+ * for multiple time zones (for example, "CST" could be U.S. "Central Standard
+ * Time" and "China Standard Time"), and the Java platform can then only
+ * recognize one of them.
+ *
+ *
+ * @see          Calendar
+ * @see          GregorianCalendar
+ * @see          SimpleTimeZone
+ * @author       Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
+ * @since        JDK1.1
+ */
+abstract public class TimeZone implements Serializable, Cloneable {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public TimeZone() {
+    }
+
+    /**
+     * A style specifier for <code>getDisplayName()</code> indicating
+     * a short name, such as "PST."
+     * @see #LONG
+     * @since 1.2
+     */
+    public static final int SHORT = 0;
+
+    /**
+     * A style specifier for <code>getDisplayName()</code> indicating
+     * a long name, such as "Pacific Standard Time."
+     * @see #SHORT
+     * @since 1.2
+     */
+    public static final int LONG  = 1;
+
+    // Android-changed: Use a preload holder to allow compile-time initialization of TimeZone and
+    // dependents.
+    private static class NoImagePreloadHolder {
+        public static final Pattern CUSTOM_ZONE_ID_PATTERN = Pattern.compile("^GMT[-+](\\d{1,2})(:?(\\d\\d))?$");
+    }
+
+    // Proclaim serialization compatibility with JDK 1.1
+    static final long serialVersionUID = 3581463369166924961L;
+
+    // Android-changed: common timezone instances.
+    private static final TimeZone GMT = new SimpleTimeZone(0, "GMT");
+    private static final TimeZone UTC = new SimpleTimeZone(0, "UTC");
+
+    /**
+     * Gets the time zone offset, for current date, modified in case of
+     * daylight savings. This is the offset to add to UTC to get local time.
+     * <p>
+     * This method returns a historically correct offset if an
+     * underlying <code>TimeZone</code> implementation subclass
+     * supports historical Daylight Saving Time schedule and GMT
+     * offset changes.
+     *
+     * @param era the era of the given date.
+     * @param year the year in the given date.
+     * @param month the month in the given date.
+     * Month is 0-based. e.g., 0 for January.
+     * @param day the day-in-month of the given date.
+     * @param dayOfWeek the day-of-week of the given date.
+     * @param milliseconds the milliseconds in day in <em>standard</em>
+     * local time.
+     *
+     * @return the offset in milliseconds to add to GMT to get local time.
+     *
+     * @see Calendar#ZONE_OFFSET
+     * @see Calendar#DST_OFFSET
+     */
+    public abstract int getOffset(int era, int year, int month, int day,
+                                  int dayOfWeek, int milliseconds);
+
+    /**
+     * Returns the offset of this time zone from UTC at the specified
+     * date. If Daylight Saving Time is in effect at the specified
+     * date, the offset value is adjusted with the amount of daylight
+     * saving.
+     * <p>
+     * This method returns a historically correct offset value if an
+     * underlying TimeZone implementation subclass supports historical
+     * Daylight Saving Time schedule and GMT offset changes.
+     *
+     * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
+     * @return the amount of time in milliseconds to add to UTC to get local time.
+     *
+     * @see Calendar#ZONE_OFFSET
+     * @see Calendar#DST_OFFSET
+     * @since 1.4
+     */
+    public int getOffset(long date) {
+        if (inDaylightTime(new Date(date))) {
+            return getRawOffset() + getDSTSavings();
+        }
+        return getRawOffset();
+    }
+
+    /**
+     * Gets the raw GMT offset and the amount of daylight saving of this
+     * time zone at the given time.
+     * @param date the milliseconds (since January 1, 1970,
+     * 00:00:00.000 GMT) at which the time zone offset and daylight
+     * saving amount are found
+     * @param offsets an array of int where the raw GMT offset
+     * (offset[0]) and daylight saving amount (offset[1]) are stored,
+     * or null if those values are not needed. The method assumes that
+     * the length of the given array is two or larger.
+     * @return the total amount of the raw GMT offset and daylight
+     * saving at the specified date.
+     *
+     * @see Calendar#ZONE_OFFSET
+     * @see Calendar#DST_OFFSET
+     */
+    int getOffsets(long date, int[] offsets) {
+        int rawoffset = getRawOffset();
+        int dstoffset = 0;
+        if (inDaylightTime(new Date(date))) {
+            dstoffset = getDSTSavings();
+        }
+        if (offsets != null) {
+            offsets[0] = rawoffset;
+            offsets[1] = dstoffset;
+        }
+        return rawoffset + dstoffset;
+    }
+
+    /**
+     * Sets the base time zone offset to GMT.
+     * This is the offset to add to UTC to get local time.
+     * <p>
+     * If an underlying <code>TimeZone</code> implementation subclass
+     * supports historical GMT offset changes, the specified GMT
+     * offset is set as the latest GMT offset and the difference from
+     * the known latest GMT offset value is used to adjust all
+     * historical GMT offset values.
+     *
+     * @param offsetMillis the given base time zone offset to GMT.
+     */
+    abstract public void setRawOffset(int offsetMillis);
+
+    /**
+     * Returns the amount of time in milliseconds to add to UTC to get
+     * standard time in this time zone. Because this value is not
+     * affected by daylight saving time, it is called <I>raw
+     * offset</I>.
+     * <p>
+     * If an underlying <code>TimeZone</code> implementation subclass
+     * supports historical GMT offset changes, the method returns the
+     * raw offset value of the current date. In Honolulu, for example,
+     * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
+     * this method always returns -36000000 milliseconds (i.e., -10
+     * hours).
+     *
+     * @return the amount of raw offset time in milliseconds to add to UTC.
+     * @see Calendar#ZONE_OFFSET
+     */
+    public abstract int getRawOffset();
+
+    /**
+     * Gets the ID of this time zone.
+     * @return the ID of this time zone.
+     */
+    public String getID()
+    {
+        return ID;
+    }
+
+    /**
+     * Sets the time zone ID. This does not change any other data in
+     * the time zone object.
+     * @param ID the new time zone ID.
+     */
+    public void setID(String ID)
+    {
+        if (ID == null) {
+            throw new NullPointerException();
+        }
+        this.ID = ID;
+    }
+
+    /**
+     * Returns a long standard time name of this {@code TimeZone} suitable for
+     * presentation to the user in the default locale.
+     *
+     * <p>This method is equivalent to:
+     * <blockquote><pre>
+     * getDisplayName(false, {@link #LONG},
+     *                Locale.getDefault({@link Locale.Category#DISPLAY}))
+     * </pre></blockquote>
+     *
+     * @return the human-readable name of this time zone in the default locale.
+     * @since 1.2
+     * @see #getDisplayName(boolean, int, Locale)
+     * @see Locale#getDefault(Locale.Category)
+     * @see Locale.Category
+     */
+    public final String getDisplayName() {
+        return getDisplayName(false, LONG,
+                              Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    /**
+     * Returns a long standard time name of this {@code TimeZone} suitable for
+     * presentation to the user in the specified {@code locale}.
+     *
+     * <p>This method is equivalent to:
+     * <blockquote><pre>
+     * getDisplayName(false, {@link #LONG}, locale)
+     * </pre></blockquote>
+     *
+     * @param locale the locale in which to supply the display name.
+     * @return the human-readable name of this time zone in the given locale.
+     * @exception NullPointerException if {@code locale} is {@code null}.
+     * @since 1.2
+     * @see #getDisplayName(boolean, int, Locale)
+     */
+    public final String getDisplayName(Locale locale) {
+        return getDisplayName(false, LONG, locale);
+    }
+
+    /**
+     * Returns a name in the specified {@code style} of this {@code TimeZone}
+     * suitable for presentation to the user in the default locale. If the
+     * specified {@code daylight} is {@code true}, a Daylight Saving Time name
+     * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving
+     * Time). Otherwise, a Standard Time name is returned.
+     *
+     * <p>This method is equivalent to:
+     * <blockquote><pre>
+     * getDisplayName(daylight, style,
+     *                Locale.getDefault({@link Locale.Category#DISPLAY}))
+     * </pre></blockquote>
+     *
+     * @param daylight {@code true} specifying a Daylight Saving Time name, or
+     *                 {@code false} specifying a Standard Time name
+     * @param style either {@link #LONG} or {@link #SHORT}
+     * @return the human-readable name of this time zone in the default locale.
+     * @exception IllegalArgumentException if {@code style} is invalid.
+     * @since 1.2
+     * @see #getDisplayName(boolean, int, Locale)
+     * @see Locale#getDefault(Locale.Category)
+     * @see Locale.Category
+     * @see java.text.DateFormatSymbols#getZoneStrings()
+     */
+    public final String getDisplayName(boolean daylight, int style) {
+        return getDisplayName(daylight, style,
+                              Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    /**
+     * Returns the {@link #SHORT short} or {@link #LONG long} name of this time
+     * zone with either standard or daylight time, as written in {@code locale}.
+     * If the name is not available, the result is in the format
+     * {@code GMT[+-]hh:mm}.
+     *
+     * @param daylightTime true for daylight time, false for standard time.
+     * @param style either {@link TimeZone#LONG} or {@link TimeZone#SHORT}.
+     * @param locale the display locale.
+     */
+    public String getDisplayName(boolean daylightTime, int style, Locale locale) {
+        // BEGIN Android-changed: implement using android.icu.text.TimeZoneNames
+        TimeZoneNames.NameType nameType;
+        switch (style) {
+            case SHORT:
+                nameType = daylightTime
+                        ? TimeZoneNames.NameType.SHORT_DAYLIGHT
+                        : TimeZoneNames.NameType.SHORT_STANDARD;
+                break;
+            case LONG:
+                nameType = daylightTime
+                        ? TimeZoneNames.NameType.LONG_DAYLIGHT
+                        : TimeZoneNames.NameType.LONG_STANDARD;
+                break;
+            default:
+                throw new IllegalArgumentException("Illegal style: " + style);
+        }
+        String canonicalID = android.icu.util.TimeZone.getCanonicalID(getID());
+        if (canonicalID != null) {
+            TimeZoneNames names = TimeZoneNames.getInstance(locale);
+            long now = System.currentTimeMillis();
+            String displayName = names.getDisplayName(canonicalID, nameType, now);
+            if (displayName != null) {
+                return displayName;
+            }
+        }
+
+        // We get here if this is a custom timezone or ICU doesn't have name data for the specific
+        // style and locale.
+        int offsetMillis = getRawOffset();
+        if (daylightTime) {
+            offsetMillis += getDSTSavings();
+        }
+        return createGmtOffsetString(true /* includeGmt */, true /* includeMinuteSeparator */,
+                offsetMillis);
+        // END Android-changed: implement using android.icu.text.TimeZoneNames
+    }
+
+    // BEGIN Android-added: utility method to format an offset as a GMT offset string.
+    /**
+     * Returns a string representation of an offset from UTC.
+     *
+     * <p>The format is "[GMT](+|-)HH[:]MM". The output is not localized.
+     *
+     * @param includeGmt true to include "GMT", false to exclude
+     * @param includeMinuteSeparator true to include the separator between hours and minutes, false
+     *     to exclude.
+     * @param offsetMillis the offset from UTC
+     *
+     * @hide used internally by SimpleDateFormat
+     */
+    public static String createGmtOffsetString(boolean includeGmt,
+            boolean includeMinuteSeparator, int offsetMillis) {
+        int offsetMinutes = offsetMillis / 60000;
+        char sign = '+';
+        if (offsetMinutes < 0) {
+            sign = '-';
+            offsetMinutes = -offsetMinutes;
+        }
+        StringBuilder builder = new StringBuilder(9);
+        if (includeGmt) {
+            builder.append("GMT");
+        }
+        builder.append(sign);
+        appendNumber(builder, 2, offsetMinutes / 60);
+        if (includeMinuteSeparator) {
+            builder.append(':');
+        }
+        appendNumber(builder, 2, offsetMinutes % 60);
+        return builder.toString();
+    }
+
+    private static void appendNumber(StringBuilder builder, int count, int value) {
+        String string = Integer.toString(value);
+        for (int i = 0; i < count - string.length(); i++) {
+            builder.append('0');
+        }
+        builder.append(string);
+    }
+    // END Android-added: utility method to format an offset as a GMT offset string.
+
+    /**
+     * Returns the amount of time to be added to local standard time
+     * to get local wall clock time.
+     *
+     * <p>The default implementation returns 3600000 milliseconds
+     * (i.e., one hour) if a call to {@link #useDaylightTime()}
+     * returns {@code true}. Otherwise, 0 (zero) is returned.
+     *
+     * <p>If an underlying {@code TimeZone} implementation subclass
+     * supports historical and future Daylight Saving Time schedule
+     * changes, this method returns the amount of saving time of the
+     * last known Daylight Saving Time rule that can be a future
+     * prediction.
+     *
+     * <p>If the amount of saving time at any given time stamp is
+     * required, construct a {@link Calendar} with this {@code
+     * TimeZone} and the time stamp, and call {@link Calendar#get(int)
+     * Calendar.get}{@code (}{@link Calendar#DST_OFFSET}{@code )}.
+     *
+     * @return the amount of saving time in milliseconds
+     * @since 1.4
+     * @see #inDaylightTime(Date)
+     * @see #getOffset(long)
+     * @see #getOffset(int,int,int,int,int,int)
+     * @see Calendar#ZONE_OFFSET
+     */
+    public int getDSTSavings() {
+        if (useDaylightTime()) {
+            return 3600000;
+        }
+        return 0;
+    }
+
+    /**
+     * Queries if this {@code TimeZone} uses Daylight Saving Time.
+     *
+     * <p>If an underlying {@code TimeZone} implementation subclass
+     * supports historical and future Daylight Saving Time schedule
+     * changes, this method refers to the last known Daylight Saving Time
+     * rule that can be a future prediction and may not be the same as
+     * the current rule. Consider calling {@link #observesDaylightTime()}
+     * if the current rule should also be taken into account.
+     *
+     * @return {@code true} if this {@code TimeZone} uses Daylight Saving Time,
+     *         {@code false}, otherwise.
+     * @see #inDaylightTime(Date)
+     * @see Calendar#DST_OFFSET
+     */
+    public abstract boolean useDaylightTime();
+
+    /**
+     * Returns {@code true} if this {@code TimeZone} is currently in
+     * Daylight Saving Time, or if a transition from Standard Time to
+     * Daylight Saving Time occurs at any future time.
+     *
+     * <p>The default implementation returns {@code true} if
+     * {@code useDaylightTime()} or {@code inDaylightTime(new Date())}
+     * returns {@code true}.
+     *
+     * @return {@code true} if this {@code TimeZone} is currently in
+     * Daylight Saving Time, or if a transition from Standard Time to
+     * Daylight Saving Time occurs at any future time; {@code false}
+     * otherwise.
+     * @since 1.7
+     * @see #useDaylightTime()
+     * @see #inDaylightTime(Date)
+     * @see Calendar#DST_OFFSET
+     */
+    public boolean observesDaylightTime() {
+        return useDaylightTime() || inDaylightTime(new Date());
+    }
+
+    /**
+     * Queries if the given {@code date} is in Daylight Saving Time in
+     * this time zone.
+     *
+     * @param date the given Date.
+     * @return {@code true} if the given date is in Daylight Saving Time,
+     *         {@code false}, otherwise.
+     */
+    abstract public boolean inDaylightTime(Date date);
+
+    /**
+     * Gets the <code>TimeZone</code> for the given ID.
+     *
+     * @param id the ID for a <code>TimeZone</code>, either an abbreviation
+     * such as "PST", a full name such as "America/Los_Angeles", or a custom
+     * ID such as "GMT-8:00". Note that the support of abbreviations is
+     * for JDK 1.1.x compatibility only and full names should be used.
+     *
+     * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
+     * cannot be understood.
+     */
+    // Android-changed: param s/ID/id; use ZoneInfoDb instead of ZoneInfo class.
+    public static synchronized TimeZone getTimeZone(String id) {
+        if (id == null) {
+            throw new NullPointerException("id == null");
+        }
+
+        // Special cases? These can clone an existing instance.
+        if (id.length() == 3) {
+            if (id.equals("GMT")) {
+                return (TimeZone) GMT.clone();
+            }
+            if (id.equals("UTC")) {
+                return (TimeZone) UTC.clone();
+            }
+        }
+
+        // In the database?
+        TimeZone zone = null;
+        try {
+            zone = ZoneInfoDb.getInstance().makeTimeZone(id);
+        } catch (IOException ignored) {
+        }
+
+        // Custom time zone?
+        if (zone == null && id.length() > 3 && id.startsWith("GMT")) {
+            zone = getCustomTimeZone(id);
+        }
+
+        // We never return null; on failure we return the equivalent of "GMT".
+        return (zone != null) ? zone : (TimeZone) GMT.clone();
+    }
+
+    /**
+     * Gets the {@code TimeZone} for the given {@code zoneId}.
+     *
+     * @param zoneId a {@link ZoneId} from which the time zone ID is obtained
+     * @return the specified {@code TimeZone}, or the GMT zone if the given ID
+     *         cannot be understood.
+     * @throws NullPointerException if {@code zoneId} is {@code null}
+     * @since 1.8
+     */
+    public static TimeZone getTimeZone(ZoneId zoneId) {
+        String tzid = zoneId.getId(); // throws an NPE if null
+        char c = tzid.charAt(0);
+        if (c == '+' || c == '-') {
+            tzid = "GMT" + tzid;
+        } else if (c == 'Z' && tzid.length() == 1) {
+            tzid = "UTC";
+        }
+        return getTimeZone(tzid);
+    }
+
+    /**
+     * Converts this {@code TimeZone} object to a {@code ZoneId}.
+     *
+     * @return a {@code ZoneId} representing the same time zone as this
+     *         {@code TimeZone}
+     * @since 1.8
+     */
+    public ZoneId toZoneId() {
+        // Android-changed: don't support "old mapping"
+        return ZoneId.of(getID(), ZoneId.SHORT_IDS);
+    }
+
+    /**
+     * Returns a new SimpleTimeZone for an ID of the form "GMT[+|-]hh[[:]mm]", or null.
+     */
+    private static TimeZone getCustomTimeZone(String id) {
+        Matcher m = NoImagePreloadHolder.CUSTOM_ZONE_ID_PATTERN.matcher(id);
+        if (!m.matches()) {
+            return null;
+        }
+
+        int hour;
+        int minute = 0;
+        try {
+            hour = Integer.parseInt(m.group(1));
+            if (m.group(3) != null) {
+                minute = Integer.parseInt(m.group(3));
+            }
+        } catch (NumberFormatException impossible) {
+            throw new AssertionError(impossible);
+        }
+
+        if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
+            return null;
+        }
+
+        char sign = id.charAt(3);
+        int raw = (hour * 3600000) + (minute * 60000);
+        if (sign == '-') {
+            raw = -raw;
+        }
+
+        String cleanId = String.format(Locale.ROOT, "GMT%c%02d:%02d", sign, hour, minute);
+
+        return new SimpleTimeZone(raw, cleanId);
+    }
+
+    /**
+     * Gets the available IDs according to the given time zone offset in milliseconds.
+     *
+     * @param rawOffset the given time zone GMT offset in milliseconds.
+     * @return an array of IDs, where the time zone for that ID has
+     * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
+     * both have GMT-07:00, but differ in daylight saving behavior.
+     * @see #getRawOffset()
+     */
+    public static synchronized String[] getAvailableIDs(int rawOffset) {
+        return ZoneInfoDb.getInstance().getAvailableIDs(rawOffset);
+    }
+
+    /**
+     * Gets all the available IDs supported.
+     * @return an array of IDs.
+     */
+    public static synchronized String[] getAvailableIDs() {
+        return ZoneInfoDb.getInstance().getAvailableIDs();
+    }
+
+    /**
+     * Gets the platform defined TimeZone ID.
+     **/
+    private static native String getSystemTimeZoneID(String javaHome,
+                                                     String country);
+
+    /**
+     * Gets the custom time zone ID based on the GMT offset of the
+     * platform. (e.g., "GMT+08:00")
+     */
+    private static native String getSystemGMTOffsetID();
+
+    /**
+     * Gets the default <code>TimeZone</code> for this host.
+     * The source of the default <code>TimeZone</code>
+     * may vary with implementation.
+     * @return a default <code>TimeZone</code>.
+     * @see #setDefault
+     */
+    public static TimeZone getDefault() {
+        return (TimeZone) getDefaultRef().clone();
+    }
+
+    /**
+     * Returns the reference to the default TimeZone object. This
+     * method doesn't create a clone.
+     */
+    static synchronized TimeZone getDefaultRef() {
+        if (defaultTimeZone == null) {
+            Supplier<String> tzGetter = RuntimeHooks.getTimeZoneIdSupplier();
+            String zoneName = (tzGetter != null) ? tzGetter.get() : null;
+            if (zoneName != null) {
+                zoneName = zoneName.trim();
+            }
+            if (zoneName == null || zoneName.isEmpty()) {
+                try {
+                    // On the host, we can find the configured timezone here.
+                    zoneName = IoUtils.readFileAsString("/etc/timezone");
+                } catch (IOException ex) {
+                    // "vogar --mode device" can end up here.
+                    // TODO: give libcore access to Android system properties and read "persist.sys.timezone".
+                    zoneName = "GMT";
+                }
+            }
+            defaultTimeZone = TimeZone.getTimeZone(zoneName);
+        }
+        return defaultTimeZone;
+    }
+
+    /**
+     * Sets the {@code TimeZone} that is returned by the {@code getDefault}
+     * method. {@code timeZone} is cached. If {@code timeZone} is null, the cached
+     * default {@code TimeZone} is cleared. This method doesn't change the value
+     * of the {@code user.timezone} property.
+     *
+     * @param timeZone the new default {@code TimeZone}, or null
+     * @see #getDefault
+     */
+    // Android-changed: s/zone/timeZone, synchronized, removed mention of SecurityException
+    public synchronized static void setDefault(TimeZone timeZone)
+    {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new PropertyPermission
+                    ("user.timezone", "write"));
+        }
+        defaultTimeZone = timeZone != null ? (TimeZone) timeZone.clone() : null;
+        // Android-changed: notify ICU4J of changed default TimeZone.
+        android.icu.util.TimeZone.setICUDefault(null);
+    }
+
+    /**
+     * Returns true if this zone has the same rule and offset as another zone.
+     * That is, if this zone differs only in ID, if at all.  Returns false
+     * if the other zone is null.
+     * @param other the <code>TimeZone</code> object to be compared with
+     * @return true if the other zone is not null and is the same as this one,
+     * with the possible exception of the ID
+     * @since 1.2
+     */
+    public boolean hasSameRules(TimeZone other) {
+        return other != null && getRawOffset() == other.getRawOffset() &&
+            useDaylightTime() == other.useDaylightTime();
+    }
+
+    /**
+     * Creates a copy of this <code>TimeZone</code>.
+     *
+     * @return a clone of this <code>TimeZone</code>
+     */
+    public Object clone()
+    {
+        try {
+            TimeZone other = (TimeZone) super.clone();
+            other.ID = ID;
+            return other;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * The null constant as a TimeZone.
+     */
+    static final TimeZone NO_TIMEZONE = null;
+
+    // =======================privates===============================
+
+    /**
+     * The string identifier of this <code>TimeZone</code>.  This is a
+     * programmatic identifier used internally to look up <code>TimeZone</code>
+     * objects from the system table and also to map them to their localized
+     * display names.  <code>ID</code> values are unique in the system
+     * table but may not be for dynamically created zones.
+     * @serial
+     */
+    private String           ID;
+    private static volatile TimeZone defaultTimeZone;
+}
diff --git a/java/util/Timer.java b/java/util/Timer.java
new file mode 100644
index 0000000..487db0d
--- /dev/null
+++ b/java/util/Timer.java
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A facility for threads to schedule tasks for future execution in a
+ * background thread.  Tasks may be scheduled for one-time execution, or for
+ * repeated execution at regular intervals.
+ *
+ * <p>Corresponding to each <tt>Timer</tt> object is a single background
+ * thread that is used to execute all of the timer's tasks, sequentially.
+ * Timer tasks should complete quickly.  If a timer task takes excessive time
+ * to complete, it "hogs" the timer's task execution thread.  This can, in
+ * turn, delay the execution of subsequent tasks, which may "bunch up" and
+ * execute in rapid succession when (and if) the offending task finally
+ * completes.
+ *
+ * <p>After the last live reference to a <tt>Timer</tt> object goes away
+ * <i>and</i> all outstanding tasks have completed execution, the timer's task
+ * execution thread terminates gracefully (and becomes subject to garbage
+ * collection).  However, this can take arbitrarily long to occur.  By
+ * default, the task execution thread does not run as a <i>daemon thread</i>,
+ * so it is capable of keeping an application from terminating.  If a caller
+ * wants to terminate a timer's task execution thread rapidly, the caller
+ * should invoke the timer's <tt>cancel</tt> method.
+ *
+ * <p>If the timer's task execution thread terminates unexpectedly, for
+ * example, because its <tt>stop</tt> method is invoked, any further
+ * attempt to schedule a task on the timer will result in an
+ * <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt>
+ * method had been invoked.
+ *
+ * <p>This class is thread-safe: multiple threads can share a single
+ * <tt>Timer</tt> object without the need for external synchronization.
+ *
+ * <p>This class does <i>not</i> offer real-time guarantees: it schedules
+ * tasks using the <tt>Object.wait(long)</tt> method.
+ *
+ * <p>Java 5.0 introduced the {@code java.util.concurrent} package and
+ * one of the concurrency utilities therein is the {@link
+ * java.util.concurrent.ScheduledThreadPoolExecutor
+ * ScheduledThreadPoolExecutor} which is a thread pool for repeatedly
+ * executing tasks at a given rate or delay.  It is effectively a more
+ * versatile replacement for the {@code Timer}/{@code TimerTask}
+ * combination, as it allows multiple service threads, accepts various
+ * time units, and doesn't require subclassing {@code TimerTask} (just
+ * implement {@code Runnable}).  Configuring {@code
+ * ScheduledThreadPoolExecutor} with one thread makes it equivalent to
+ * {@code Timer}.
+ *
+ * <p>Implementation note: This class scales to large numbers of concurrently
+ * scheduled tasks (thousands should present no problem).  Internally,
+ * it uses a binary heap to represent its task queue, so the cost to schedule
+ * a task is O(log n), where n is the number of concurrently scheduled tasks.
+ *
+ * <p>Implementation note: All constructors start a timer thread.
+ *
+ * @author  Josh Bloch
+ * @see     TimerTask
+ * @see     Object#wait(long)
+ * @since   1.3
+ */
+
+public class Timer {
+    /**
+     * The timer task queue.  This data structure is shared with the timer
+     * thread.  The timer produces tasks, via its various schedule calls,
+     * and the timer thread consumes, executing timer tasks as appropriate,
+     * and removing them from the queue when they're obsolete.
+     */
+    // Android-added: @ReachabilitySensitive
+    // Otherwise the finalizer may cancel the Timer in the middle of a
+    // sched() call.
+    @ReachabilitySensitive
+    private final TaskQueue queue = new TaskQueue();
+
+    /**
+     * The timer thread.
+     */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private final TimerThread thread = new TimerThread(queue);
+
+    /**
+     * This object causes the timer's task execution thread to exit
+     * gracefully when there are no live references to the Timer object and no
+     * tasks in the timer queue.  It is used in preference to a finalizer on
+     * Timer as such a finalizer would be susceptible to a subclass's
+     * finalizer forgetting to call it.
+     */
+    private final Object threadReaper = new Object() {
+        protected void finalize() throws Throwable {
+            synchronized(queue) {
+                thread.newTasksMayBeScheduled = false;
+                queue.notify(); // In case queue is empty.
+            }
+        }
+    };
+
+    /**
+     * This ID is used to generate thread names.
+     */
+    private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
+    private static int serialNumber() {
+        return nextSerialNumber.getAndIncrement();
+    }
+
+    /**
+     * Creates a new timer.  The associated thread does <i>not</i>
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     */
+    public Timer() {
+        this("Timer-" + serialNumber());
+    }
+
+    /**
+     * Creates a new timer whose associated thread may be specified to
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     * A daemon thread is called for if the timer will be used to
+     * schedule repeating "maintenance activities", which must be
+     * performed as long as the application is running, but should not
+     * prolong the lifetime of the application.
+     *
+     * @param isDaemon true if the associated thread should run as a daemon.
+     */
+    public Timer(boolean isDaemon) {
+        this("Timer-" + serialNumber(), isDaemon);
+    }
+
+    /**
+     * Creates a new timer whose associated thread has the specified name.
+     * The associated thread does <i>not</i>
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     *
+     * @param name the name of the associated thread
+     * @throws NullPointerException if {@code name} is null
+     * @since 1.5
+     */
+    public Timer(String name) {
+        thread.setName(name);
+        thread.start();
+    }
+
+    /**
+     * Creates a new timer whose associated thread has the specified name,
+     * and may be specified to
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     *
+     * @param name the name of the associated thread
+     * @param isDaemon true if the associated thread should run as a daemon
+     * @throws NullPointerException if {@code name} is null
+     * @since 1.5
+     */
+    public Timer(String name, boolean isDaemon) {
+        thread.setName(name);
+        thread.setDaemon(isDaemon);
+        thread.start();
+    }
+
+    /**
+     * Schedules the specified task for execution after the specified delay.
+     *
+     * @param task  task to be scheduled.
+     * @param delay delay in milliseconds before task is to be executed.
+     * @throws IllegalArgumentException if <tt>delay</tt> is negative, or
+     *         <tt>delay + System.currentTimeMillis()</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    public void schedule(TimerTask task, long delay) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        sched(task, System.currentTimeMillis()+delay, 0);
+    }
+
+    /**
+     * Schedules the specified task for execution at the specified time.  If
+     * the time is in the past, the task is scheduled for immediate execution.
+     *
+     * @param task task to be scheduled.
+     * @param time time at which task is to be executed.
+     * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} or {@code time} is null
+     */
+    public void schedule(TimerTask task, Date time) {
+        sched(task, time.getTime(), 0);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-delay execution</i>,
+     * beginning after the specified delay.  Subsequent executions take place
+     * at approximately regular intervals separated by the specified period.
+     *
+     * <p>In fixed-delay execution, each execution is scheduled relative to
+     * the actual execution time of the previous execution.  If an execution
+     * is delayed for any reason (such as garbage collection or other
+     * background activity), subsequent executions will be delayed as well.
+     * In the long run, the frequency of execution will generally be slightly
+     * lower than the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).
+     *
+     * <p>Fixed-delay execution is appropriate for recurring activities
+     * that require "smoothness."  In other words, it is appropriate for
+     * activities where it is more important to keep the frequency accurate
+     * in the short run than in the long run.  This includes most animation
+     * tasks, such as blinking a cursor at regular intervals.  It also includes
+     * tasks wherein regular activity is performed in response to human
+     * input, such as automatically repeating a character as long as a key
+     * is held down.
+     *
+     * @param task   task to be scheduled.
+     * @param delay  delay in milliseconds before task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code delay < 0}, or
+     *         {@code delay + System.currentTimeMillis() < 0}, or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    public void schedule(TimerTask task, long delay, long period) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, System.currentTimeMillis()+delay, -period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-delay execution</i>,
+     * beginning at the specified time. Subsequent executions take place at
+     * approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-delay execution, each execution is scheduled relative to
+     * the actual execution time of the previous execution.  If an execution
+     * is delayed for any reason (such as garbage collection or other
+     * background activity), subsequent executions will be delayed as well.
+     * In the long run, the frequency of execution will generally be slightly
+     * lower than the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).  As a
+     * consequence of the above, if the scheduled first time is in the past,
+     * it is scheduled for immediate execution.
+     *
+     * <p>Fixed-delay execution is appropriate for recurring activities
+     * that require "smoothness."  In other words, it is appropriate for
+     * activities where it is more important to keep the frequency accurate
+     * in the short run than in the long run.  This includes most animation
+     * tasks, such as blinking a cursor at regular intervals.  It also includes
+     * tasks wherein regular activity is performed in response to human
+     * input, such as automatically repeating a character as long as a key
+     * is held down.
+     *
+     * @param task   task to be scheduled.
+     * @param firstTime First time at which task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code firstTime.getTime() < 0}, or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} or {@code firstTime} is null
+     */
+    public void schedule(TimerTask task, Date firstTime, long period) {
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, firstTime.getTime(), -period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-rate execution</i>,
+     * beginning after the specified delay.  Subsequent executions take place
+     * at approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-rate execution, each execution is scheduled relative to the
+     * scheduled execution time of the initial execution.  If an execution is
+     * delayed for any reason (such as garbage collection or other background
+     * activity), two or more executions will occur in rapid succession to
+     * "catch up."  In the long run, the frequency of execution will be
+     * exactly the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).
+     *
+     * <p>Fixed-rate execution is appropriate for recurring activities that
+     * are sensitive to <i>absolute</i> time, such as ringing a chime every
+     * hour on the hour, or running scheduled maintenance every day at a
+     * particular time.  It is also appropriate for recurring activities
+     * where the total time to perform a fixed number of executions is
+     * important, such as a countdown timer that ticks once every second for
+     * ten seconds.  Finally, fixed-rate execution is appropriate for
+     * scheduling multiple repeating timer tasks that must remain synchronized
+     * with respect to one another.
+     *
+     * @param task   task to be scheduled.
+     * @param delay  delay in milliseconds before task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code delay < 0}, or
+     *         {@code delay + System.currentTimeMillis() < 0}, or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, System.currentTimeMillis()+delay, period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-rate execution</i>,
+     * beginning at the specified time. Subsequent executions take place at
+     * approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-rate execution, each execution is scheduled relative to the
+     * scheduled execution time of the initial execution.  If an execution is
+     * delayed for any reason (such as garbage collection or other background
+     * activity), two or more executions will occur in rapid succession to
+     * "catch up."  In the long run, the frequency of execution will be
+     * exactly the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).  As a
+     * consequence of the above, if the scheduled first time is in the past,
+     * then any "missed" executions will be scheduled for immediate "catch up"
+     * execution.
+     *
+     * <p>Fixed-rate execution is appropriate for recurring activities that
+     * are sensitive to <i>absolute</i> time, such as ringing a chime every
+     * hour on the hour, or running scheduled maintenance every day at a
+     * particular time.  It is also appropriate for recurring activities
+     * where the total time to perform a fixed number of executions is
+     * important, such as a countdown timer that ticks once every second for
+     * ten seconds.  Finally, fixed-rate execution is appropriate for
+     * scheduling multiple repeating timer tasks that must remain synchronized
+     * with respect to one another.
+     *
+     * @param task   task to be scheduled.
+     * @param firstTime First time at which task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code firstTime.getTime() < 0} or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} or {@code firstTime} is null
+     */
+    public void scheduleAtFixedRate(TimerTask task, Date firstTime,
+                                    long period) {
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, firstTime.getTime(), period);
+    }
+
+    /**
+     * Schedule the specified timer task for execution at the specified
+     * time with the specified period, in milliseconds.  If period is
+     * positive, the task is scheduled for repeated execution; if period is
+     * zero, the task is scheduled for one-time execution. Time is specified
+     * in Date.getTime() format.  This method checks timer state, task state,
+     * and initial execution time, but not period.
+     *
+     * @throws IllegalArgumentException if <tt>time</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    private void sched(TimerTask task, long time, long period) {
+        if (time < 0)
+            throw new IllegalArgumentException("Illegal execution time.");
+
+        // Constrain value of period sufficiently to prevent numeric
+        // overflow while still being effectively infinitely large.
+        if (Math.abs(period) > (Long.MAX_VALUE >> 1))
+            period >>= 1;
+
+        synchronized(queue) {
+            if (!thread.newTasksMayBeScheduled)
+                throw new IllegalStateException("Timer already cancelled.");
+
+            synchronized(task.lock) {
+                if (task.state != TimerTask.VIRGIN)
+                    throw new IllegalStateException(
+                        "Task already scheduled or cancelled");
+                task.nextExecutionTime = time;
+                task.period = period;
+                task.state = TimerTask.SCHEDULED;
+            }
+
+            queue.add(task);
+            if (queue.getMin() == task)
+                queue.notify();
+        }
+    }
+
+    /**
+     * Terminates this timer, discarding any currently scheduled tasks.
+     * Does not interfere with a currently executing task (if it exists).
+     * Once a timer has been terminated, its execution thread terminates
+     * gracefully, and no more tasks may be scheduled on it.
+     *
+     * <p>Note that calling this method from within the run method of a
+     * timer task that was invoked by this timer absolutely guarantees that
+     * the ongoing task execution is the last task execution that will ever
+     * be performed by this timer.
+     *
+     * <p>This method may be called repeatedly; the second and subsequent
+     * calls have no effect.
+     */
+    public void cancel() {
+        synchronized(queue) {
+            thread.newTasksMayBeScheduled = false;
+            queue.clear();
+            queue.notify();  // In case queue was already empty.
+        }
+    }
+
+    /**
+     * Removes all cancelled tasks from this timer's task queue.  <i>Calling
+     * this method has no effect on the behavior of the timer</i>, but
+     * eliminates the references to the cancelled tasks from the queue.
+     * If there are no external references to these tasks, they become
+     * eligible for garbage collection.
+     *
+     * <p>Most programs will have no need to call this method.
+     * It is designed for use by the rare application that cancels a large
+     * number of tasks.  Calling this method trades time for space: the
+     * runtime of the method may be proportional to n + c log n, where n
+     * is the number of tasks in the queue and c is the number of cancelled
+     * tasks.
+     *
+     * <p>Note that it is permissible to call this method from within a
+     * a task scheduled on this timer.
+     *
+     * @return the number of tasks removed from the queue.
+     * @since 1.5
+     */
+     public int purge() {
+         int result = 0;
+
+         synchronized(queue) {
+             for (int i = queue.size(); i > 0; i--) {
+                 if (queue.get(i).state == TimerTask.CANCELLED) {
+                     queue.quickRemove(i);
+                     result++;
+                 }
+             }
+
+             if (result != 0)
+                 queue.heapify();
+         }
+
+         return result;
+     }
+}
+
+/**
+ * This "helper class" implements the timer's task execution thread, which
+ * waits for tasks on the timer queue, executions them when they fire,
+ * reschedules repeating tasks, and removes cancelled tasks and spent
+ * non-repeating tasks from the queue.
+ */
+class TimerThread extends Thread {
+    /**
+     * This flag is set to false by the reaper to inform us that there
+     * are no more live references to our Timer object.  Once this flag
+     * is true and there are no more tasks in our queue, there is no
+     * work left for us to do, so we terminate gracefully.  Note that
+     * this field is protected by queue's monitor!
+     */
+    boolean newTasksMayBeScheduled = true;
+
+    /**
+     * Our Timer's queue.  We store this reference in preference to
+     * a reference to the Timer so the reference graph remains acyclic.
+     * Otherwise, the Timer would never be garbage-collected and this
+     * thread would never go away.
+     */
+    private TaskQueue queue;
+
+    TimerThread(TaskQueue queue) {
+        this.queue = queue;
+    }
+
+    public void run() {
+        try {
+            mainLoop();
+        } finally {
+            // Someone killed this Thread, behave as if Timer cancelled
+            synchronized(queue) {
+                newTasksMayBeScheduled = false;
+                queue.clear();  // Eliminate obsolete references
+            }
+        }
+    }
+
+    /**
+     * The main timer loop.  (See class comment.)
+     */
+    private void mainLoop() {
+        while (true) {
+            try {
+                TimerTask task;
+                boolean taskFired;
+                synchronized(queue) {
+                    // Wait for queue to become non-empty
+                    while (queue.isEmpty() && newTasksMayBeScheduled)
+                        queue.wait();
+                    if (queue.isEmpty())
+                        break; // Queue is empty and will forever remain; die
+
+                    // Queue nonempty; look at first evt and do the right thing
+                    long currentTime, executionTime;
+                    task = queue.getMin();
+                    synchronized(task.lock) {
+                        if (task.state == TimerTask.CANCELLED) {
+                            queue.removeMin();
+                            continue;  // No action required, poll queue again
+                        }
+                        currentTime = System.currentTimeMillis();
+                        executionTime = task.nextExecutionTime;
+                        if (taskFired = (executionTime<=currentTime)) {
+                            if (task.period == 0) { // Non-repeating, remove
+                                queue.removeMin();
+                                task.state = TimerTask.EXECUTED;
+                            } else { // Repeating task, reschedule
+                                queue.rescheduleMin(
+                                  task.period<0 ? currentTime   - task.period
+                                                : executionTime + task.period);
+                            }
+                        }
+                    }
+                    if (!taskFired) // Task hasn't yet fired; wait
+                        queue.wait(executionTime - currentTime);
+                }
+                if (taskFired)  // Task fired; run it, holding no locks
+                    task.run();
+            } catch(InterruptedException e) {
+            }
+        }
+    }
+}
+
+/**
+ * This class represents a timer task queue: a priority queue of TimerTasks,
+ * ordered on nextExecutionTime.  Each Timer object has one of these, which it
+ * shares with its TimerThread.  Internally this class uses a heap, which
+ * offers log(n) performance for the add, removeMin and rescheduleMin
+ * operations, and constant time performance for the getMin operation.
+ */
+class TaskQueue {
+    /**
+     * Priority queue represented as a balanced binary heap: the two children
+     * of queue[n] are queue[2*n] and queue[2*n+1].  The priority queue is
+     * ordered on the nextExecutionTime field: The TimerTask with the lowest
+     * nextExecutionTime is in queue[1] (assuming the queue is nonempty).  For
+     * each node n in the heap, and each descendant of n, d,
+     * n.nextExecutionTime <= d.nextExecutionTime.
+     */
+    private TimerTask[] queue = new TimerTask[128];
+
+    /**
+     * The number of tasks in the priority queue.  (The tasks are stored in
+     * queue[1] up to queue[size]).
+     */
+    private int size = 0;
+
+    /**
+     * Returns the number of tasks currently on the queue.
+     */
+    int size() {
+        return size;
+    }
+
+    /**
+     * Adds a new task to the priority queue.
+     */
+    void add(TimerTask task) {
+        // Grow backing store if necessary
+        if (size + 1 == queue.length)
+            queue = Arrays.copyOf(queue, 2*queue.length);
+
+        queue[++size] = task;
+        fixUp(size);
+    }
+
+    /**
+     * Return the "head task" of the priority queue.  (The head task is an
+     * task with the lowest nextExecutionTime.)
+     */
+    TimerTask getMin() {
+        return queue[1];
+    }
+
+    /**
+     * Return the ith task in the priority queue, where i ranges from 1 (the
+     * head task, which is returned by getMin) to the number of tasks on the
+     * queue, inclusive.
+     */
+    TimerTask get(int i) {
+        return queue[i];
+    }
+
+    /**
+     * Remove the head task from the priority queue.
+     */
+    void removeMin() {
+        queue[1] = queue[size];
+        queue[size--] = null;  // Drop extra reference to prevent memory leak
+        fixDown(1);
+    }
+
+    /**
+     * Removes the ith element from queue without regard for maintaining
+     * the heap invariant.  Recall that queue is one-based, so
+     * 1 <= i <= size.
+     */
+    void quickRemove(int i) {
+        assert i <= size;
+
+        queue[i] = queue[size];
+        queue[size--] = null;  // Drop extra ref to prevent memory leak
+    }
+
+    /**
+     * Sets the nextExecutionTime associated with the head task to the
+     * specified value, and adjusts priority queue accordingly.
+     */
+    void rescheduleMin(long newTime) {
+        queue[1].nextExecutionTime = newTime;
+        fixDown(1);
+    }
+
+    /**
+     * Returns true if the priority queue contains no elements.
+     */
+    boolean isEmpty() {
+        return size==0;
+    }
+
+    /**
+     * Removes all elements from the priority queue.
+     */
+    void clear() {
+        // Null out task references to prevent memory leak
+        for (int i=1; i<=size; i++)
+            queue[i] = null;
+
+        size = 0;
+    }
+
+    /**
+     * Establishes the heap invariant (described above) assuming the heap
+     * satisfies the invariant except possibly for the leaf-node indexed by k
+     * (which may have a nextExecutionTime less than its parent's).
+     *
+     * This method functions by "promoting" queue[k] up the hierarchy
+     * (by swapping it with its parent) repeatedly until queue[k]'s
+     * nextExecutionTime is greater than or equal to that of its parent.
+     */
+    private void fixUp(int k) {
+        while (k > 1) {
+            int j = k >> 1;
+            if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
+                break;
+            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
+            k = j;
+        }
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the subtree
+     * rooted at k, which is assumed to satisfy the heap invariant except
+     * possibly for node k itself (which may have a nextExecutionTime greater
+     * than its children's).
+     *
+     * This method functions by "demoting" queue[k] down the hierarchy
+     * (by swapping it with its smaller child) repeatedly until queue[k]'s
+     * nextExecutionTime is less than or equal to those of its children.
+     */
+    private void fixDown(int k) {
+        int j;
+        while ((j = k << 1) <= size && j > 0) {
+            if (j < size &&
+                queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
+                j++; // j indexes smallest kid
+            if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
+                break;
+            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
+            k = j;
+        }
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the entire tree,
+     * assuming nothing about the order of the elements prior to the call.
+     */
+    void heapify() {
+        for (int i = size/2; i >= 1; i--)
+            fixDown(i);
+    }
+}
diff --git a/java/util/TimerTask.java b/java/util/TimerTask.java
new file mode 100644
index 0000000..5750486
--- /dev/null
+++ b/java/util/TimerTask.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A task that can be scheduled for one-time or repeated execution by a Timer.
+ *
+ * @author  Josh Bloch
+ * @see     Timer
+ * @since   1.3
+ */
+
+public abstract class TimerTask implements Runnable {
+    /**
+     * This object is used to control access to the TimerTask internals.
+     */
+    final Object lock = new Object();
+
+    /**
+     * The state of this task, chosen from the constants below.
+     */
+    int state = VIRGIN;
+
+    /**
+     * This task has not yet been scheduled.
+     */
+    static final int VIRGIN = 0;
+
+    /**
+     * This task is scheduled for execution.  If it is a non-repeating task,
+     * it has not yet been executed.
+     */
+    static final int SCHEDULED   = 1;
+
+    /**
+     * This non-repeating task has already executed (or is currently
+     * executing) and has not been cancelled.
+     */
+    static final int EXECUTED    = 2;
+
+    /**
+     * This task has been cancelled (with a call to TimerTask.cancel).
+     */
+    static final int CANCELLED   = 3;
+
+    /**
+     * Next execution time for this task in the format returned by
+     * System.currentTimeMillis, assuming this task is scheduled for execution.
+     * For repeating tasks, this field is updated prior to each task execution.
+     */
+    long nextExecutionTime;
+
+    /**
+     * Period in milliseconds for repeating tasks.  A positive value indicates
+     * fixed-rate execution.  A negative value indicates fixed-delay execution.
+     * A value of 0 indicates a non-repeating task.
+     */
+    long period = 0;
+
+    /**
+     * Creates a new timer task.
+     */
+    protected TimerTask() {
+    }
+
+    /**
+     * The action to be performed by this timer task.
+     */
+    public abstract void run();
+
+    /**
+     * Cancels this timer task.  If the task has been scheduled for one-time
+     * execution and has not yet run, or has not yet been scheduled, it will
+     * never run.  If the task has been scheduled for repeated execution, it
+     * will never run again.  (If the task is running when this call occurs,
+     * the task will run to completion, but will never run again.)
+     *
+     * <p>Note that calling this method from within the <tt>run</tt> method of
+     * a repeating timer task absolutely guarantees that the timer task will
+     * not run again.
+     *
+     * <p>This method may be called repeatedly; the second and subsequent
+     * calls have no effect.
+     *
+     * @return true if this task is scheduled for one-time execution and has
+     *         not yet run, or this task is scheduled for repeated execution.
+     *         Returns false if the task was scheduled for one-time execution
+     *         and has already run, or if the task was never scheduled, or if
+     *         the task was already cancelled.  (Loosely speaking, this method
+     *         returns <tt>true</tt> if it prevents one or more scheduled
+     *         executions from taking place.)
+     */
+    public boolean cancel() {
+        synchronized(lock) {
+            boolean result = (state == SCHEDULED);
+            state = CANCELLED;
+            return result;
+        }
+    }
+
+    /**
+     * Returns the <i>scheduled</i> execution time of the most recent
+     * <i>actual</i> execution of this task.  (If this method is invoked
+     * while task execution is in progress, the return value is the scheduled
+     * execution time of the ongoing task execution.)
+     *
+     * <p>This method is typically invoked from within a task's run method, to
+     * determine whether the current execution of the task is sufficiently
+     * timely to warrant performing the scheduled activity:
+     * <pre>{@code
+     *   public void run() {
+     *       if (System.currentTimeMillis() - scheduledExecutionTime() >=
+     *           MAX_TARDINESS)
+     *               return;  // Too late; skip this execution.
+     *       // Perform the task
+     *   }
+     * }</pre>
+     * This method is typically <i>not</i> used in conjunction with
+     * <i>fixed-delay execution</i> repeating tasks, as their scheduled
+     * execution times are allowed to drift over time, and so are not terribly
+     * significant.
+     *
+     * @return the time at which the most recent execution of this task was
+     *         scheduled to occur, in the format returned by Date.getTime().
+     *         The return value is undefined if the task has yet to commence
+     *         its first execution.
+     * @see Date#getTime()
+     */
+    public long scheduledExecutionTime() {
+        synchronized(lock) {
+            return (period < 0 ? nextExecutionTime + period
+                               : nextExecutionTime - period);
+        }
+    }
+}
diff --git a/java/util/TooManyListenersException.java b/java/util/TooManyListenersException.java
new file mode 100644
index 0000000..134dea8
--- /dev/null
+++ b/java/util/TooManyListenersException.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * <p>
+ * The <code> TooManyListenersException </code> Exception is used as part of
+ * the Java Event model to annotate and implement a unicast special case of
+ * a multicast Event Source.
+ * </p>
+ * <p>
+ * The presence of a "throws TooManyListenersException" clause on any given
+ * concrete implementation of the normally multicast "void addXyzEventListener"
+ * event listener registration pattern is used to annotate that interface as
+ * implementing a unicast Listener special case, that is, that one and only
+ * one Listener may be registered on the particular event listener source
+ * concurrently.
+ * </p>
+ *
+ * @see java.util.EventObject
+ * @see java.util.EventListener
+ *
+ * @author Laurence P. G. Cable
+ * @since  JDK1.1
+ */
+
+public class TooManyListenersException extends Exception {
+    private static final long serialVersionUID = 5074640544770687831L;
+
+    /**
+     * Constructs a TooManyListenersException with no detail message.
+     * A detail message is a String that describes this particular exception.
+     */
+
+    public TooManyListenersException() {
+        super();
+    }
+
+    /**
+     * Constructs a TooManyListenersException with the specified detail message.
+     * A detail message is a String that describes this particular exception.
+     * @param s the detail message
+     */
+
+    public TooManyListenersException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/TreeMap.annotated.java b/java/util/TreeMap.annotated.java
new file mode 100644
index 0000000..87f1f20
--- /dev/null
+++ b/java/util/TreeMap.annotated.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class TreeMap<K, V> extends java.util.AbstractMap<K,V> implements java.util.NavigableMap<K,V>, java.lang.Cloneable, java.io.Serializable {
+
+public TreeMap() { throw new RuntimeException("Stub!"); }
+
+public TreeMap(@libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam K> comparator) { throw new RuntimeException("Stub!"); }
+
+public TreeMap(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
+public TreeMap(@libcore.util.NonNull java.util.SortedMap<@libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean containsKey(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public boolean containsValue(@libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
[email protected] public V get(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Comparator<? super @libcore.util.NullFromTypeParam K> comparator() { throw new RuntimeException("Stub!"); }
+
[email protected] public K firstKey() { throw new RuntimeException("Stub!"); }
+
[email protected] public K lastKey() { throw new RuntimeException("Stub!"); }
+
+public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> map) { throw new RuntimeException("Stub!"); }
+
[email protected] public V put(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
[email protected] public V remove(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> firstEntry() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> lastEntry() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> pollFirstEntry() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> pollLastEntry() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> lowerEntry(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public K lowerKey(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> floorEntry(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public K floorKey(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> ceilingEntry(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public K ceilingKey(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> higherEntry(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public K higherKey(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableSet<@libcore.util.NullFromTypeParam K> navigableKeySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableSet<@libcore.util.NullFromTypeParam K> descendingKeySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> descendingMap() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> subMap(@libcore.util.NullFromTypeParam K fromKey, boolean fromInclusive, @libcore.util.NullFromTypeParam K toKey, boolean toInclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> headMap(@libcore.util.NullFromTypeParam K toKey, boolean inclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> tailMap(@libcore.util.NullFromTypeParam K fromKey, boolean inclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> subMap(@libcore.util.NullFromTypeParam K fromKey, @libcore.util.NullFromTypeParam K toKey) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> headMap(@libcore.util.NullFromTypeParam K toKey) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> tailMap(@libcore.util.NullFromTypeParam K fromKey) { throw new RuntimeException("Stub!"); }
+
+public boolean replace(@libcore.util.NullFromTypeParam K key, @libcore.util.Nullable V oldValue, @libcore.util.NullFromTypeParam V newValue) { throw new RuntimeException("Stub!"); }
+
[email protected] public V replace(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public void forEach(@libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V> action) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(@libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V,? extends @libcore.util.NullFromTypeParam V> function) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/TreeMap.java b/java/util/TreeMap.java
new file mode 100644
index 0000000..20d98bc
--- /dev/null
+++ b/java/util/TreeMap.java
@@ -0,0 +1,3049 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
+/**
+ * A Red-Black tree based {@link NavigableMap} implementation.
+ * The map is sorted according to the {@linkplain Comparable natural
+ * ordering} of its keys, or by a {@link Comparator} provided at map
+ * creation time, depending on which constructor is used.
+ *
+ * <p>This implementation provides guaranteed log(n) time cost for the
+ * {@code containsKey}, {@code get}, {@code put} and {@code remove}
+ * operations.  Algorithms are adaptations of those in Cormen, Leiserson, and
+ * Rivest's <em>Introduction to Algorithms</em>.
+ *
+ * <p>Note that the ordering maintained by a tree map, like any sorted map, and
+ * whether or not an explicit comparator is provided, must be <em>consistent
+ * with {@code equals}</em> if this sorted map is to correctly implement the
+ * {@code Map} interface.  (See {@code Comparable} or {@code Comparator} for a
+ * precise definition of <em>consistent with equals</em>.)  This is so because
+ * the {@code Map} interface is defined in terms of the {@code equals}
+ * operation, but a sorted map performs all key comparisons using its {@code
+ * compareTo} (or {@code compare}) method, so two keys that are deemed equal by
+ * this method are, from the standpoint of the sorted map, equal.  The behavior
+ * of a sorted map <em>is</em> well-defined even if its ordering is
+ * inconsistent with {@code equals}; it just fails to obey the general contract
+ * of the {@code Map} interface.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a map concurrently, and at least one of the
+ * threads modifies the map structurally, it <em>must</em> be synchronized
+ * externally.  (A structural modification is any operation that adds or
+ * deletes one or more mappings; merely changing the value associated
+ * with an existing key is not a structural modification.)  This is
+ * typically accomplished by synchronizing on some object that naturally
+ * encapsulates the map.
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedSortedMap Collections.synchronizedSortedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map: <pre>
+ *   SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));</pre>
+ *
+ * <p>The iterators returned by the {@code iterator} method of the collections
+ * returned by all of this class's "collection view methods" are
+ * <em>fail-fast</em>: if the map is structurally modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * {@code remove} method, 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 time in the future.
+ *
+ * <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 {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:   <em>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</em>
+ *
+ * <p>All {@code Map.Entry} pairs returned by methods in this class
+ * and its views represent snapshots of mappings at the time they were
+ * produced. They do <strong>not</strong> support the {@code Entry.setValue}
+ * method. (Note however that it is possible to change mappings in the
+ * associated map using {@code put}.)
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch and Doug Lea
+ * @see Map
+ * @see HashMap
+ * @see Hashtable
+ * @see Comparable
+ * @see Comparator
+ * @see Collection
+ * @since 1.2
+ */
+
+public class TreeMap<K,V>
+    extends AbstractMap<K,V>
+    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
+{
+    /**
+     * The comparator used to maintain order in this tree map, or
+     * null if it uses the natural ordering of its keys.
+     *
+     * @serial
+     */
+    private final Comparator<? super K> comparator;
+
+    private transient TreeMapEntry<K,V> root;
+
+    /**
+     * The number of entries in the tree
+     */
+    private transient int size = 0;
+
+    /**
+     * The number of structural modifications to the tree.
+     */
+    private transient int modCount = 0;
+
+    /**
+     * Constructs a new, empty tree map, using the natural ordering of its
+     * keys.  All keys inserted into the map must implement the {@link
+     * Comparable} interface.  Furthermore, all such keys must be
+     * <em>mutually comparable</em>: {@code k1.compareTo(k2)} must not throw
+     * a {@code ClassCastException} for any keys {@code k1} and
+     * {@code k2} in the map.  If the user attempts to put a key into the
+     * map that violates this constraint (for example, the user attempts to
+     * put a string key into a map whose keys are integers), the
+     * {@code put(Object key, Object value)} call will throw a
+     * {@code ClassCastException}.
+     */
+    public TreeMap() {
+        comparator = null;
+    }
+
+    /**
+     * Constructs a new, empty tree map, ordered according to the given
+     * comparator.  All keys inserted into the map must be <em>mutually
+     * comparable</em> by the given comparator: {@code comparator.compare(k1,
+     * k2)} must not throw a {@code ClassCastException} for any keys
+     * {@code k1} and {@code k2} in the map.  If the user attempts to put
+     * a key into the map that violates this constraint, the {@code put(Object
+     * key, Object value)} call will throw a
+     * {@code ClassCastException}.
+     *
+     * @param comparator the comparator that will be used to order this map.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the keys will be used.
+     */
+    public TreeMap(Comparator<? super K> comparator) {
+        this.comparator = comparator;
+    }
+
+    /**
+     * Constructs a new tree map containing the same mappings as the given
+     * map, ordered according to the <em>natural ordering</em> of its keys.
+     * All keys inserted into the new map must implement the {@link
+     * Comparable} interface.  Furthermore, all such keys must be
+     * <em>mutually comparable</em>: {@code k1.compareTo(k2)} must not throw
+     * a {@code ClassCastException} for any keys {@code k1} and
+     * {@code k2} in the map.  This method runs in n*log(n) time.
+     *
+     * @param  m the map whose mappings are to be placed in this map
+     * @throws ClassCastException if the keys in m are not {@link Comparable},
+     *         or are not mutually comparable
+     * @throws NullPointerException if the specified map is null
+     */
+    public TreeMap(Map<? extends K, ? extends V> m) {
+        comparator = null;
+        putAll(m);
+    }
+
+    /**
+     * Constructs a new tree map containing the same mappings and
+     * using the same ordering as the specified sorted map.  This
+     * method runs in linear time.
+     *
+     * @param  m the sorted map whose mappings are to be placed in this map,
+     *         and whose comparator is to be used to sort this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public TreeMap(SortedMap<K, ? extends V> m) {
+        comparator = m.comparator();
+        try {
+            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
+        } catch (java.io.IOException cannotHappen) {
+        } catch (ClassNotFoundException cannotHappen) {
+        }
+    }
+
+
+    // Query Operations
+
+    /**
+     * 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 {@code true} if this map contains a mapping for the specified
+     * key.
+     *
+     * @param key key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the
+     *         specified key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public boolean containsKey(Object key) {
+        return getEntry(key) != null;
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.  More formally, returns {@code true} if and only if
+     * this map contains at least one mapping to a value {@code v} such
+     * that {@code (value==null ? v==null : value.equals(v))}.  This
+     * operation will probably require time linear in the map size for
+     * most implementations.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if a mapping to {@code value} exists;
+     *         {@code false} otherwise
+     * @since 1.2
+     */
+    public boolean containsValue(Object value) {
+        for (TreeMapEntry<K,V> e = getFirstEntry(); e != null; e = successor(e))
+            if (valEquals(value, e.value))
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code key} compares
+     * equal to {@code k} according to the map's ordering, then this
+     * method returns {@code v}; otherwise it returns {@code null}.
+     * (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <em>necessarily</em>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public V get(Object key) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        return (p==null ? null : p.value);
+    }
+
+    public Comparator<? super K> comparator() {
+        return comparator;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K firstKey() {
+        return key(getFirstEntry());
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K lastKey() {
+        return key(getLastEntry());
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings replace any mappings that this map had for any
+     * of the keys currently in the specified map.
+     *
+     * @param  map mappings to be stored in this map
+     * @throws ClassCastException if the class of a key or value in
+     *         the specified map prevents it from being stored in this map
+     * @throws NullPointerException if the specified map is null or
+     *         the specified map contains a null key and this map does not
+     *         permit null keys
+     */
+    public void putAll(Map<? extends K, ? extends V> map) {
+        int mapSize = map.size();
+        if (size==0 && mapSize!=0 && map instanceof SortedMap) {
+            Comparator<?> c = ((SortedMap<?,?>)map).comparator();
+            if (c == comparator || (c != null && c.equals(comparator))) {
+                ++modCount;
+                try {
+                    buildFromSorted(mapSize, map.entrySet().iterator(),
+                                    null, null);
+                } catch (java.io.IOException cannotHappen) {
+                } catch (ClassNotFoundException cannotHappen) {
+                }
+                return;
+            }
+        }
+        super.putAll(map);
+    }
+
+    /**
+     * Returns this map's entry for the given key, or {@code null} if the map
+     * does not contain an entry for the key.
+     *
+     * @return this map's entry for the given key, or {@code null} if the map
+     *         does not contain an entry for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    final TreeMapEntry<K,V> getEntry(Object key) {
+        // Offload comparator-based version for sake of performance
+        if (comparator != null)
+            return getEntryUsingComparator(key);
+        if (key == null)
+            throw new NullPointerException();
+        @SuppressWarnings("unchecked")
+            Comparable<? super K> k = (Comparable<? super K>) key;
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = k.compareTo(p.key);
+            if (cmp < 0)
+                p = p.left;
+            else if (cmp > 0)
+                p = p.right;
+            else
+                return p;
+        }
+        return null;
+    }
+
+    /**
+     * Version of getEntry using comparator. Split off from getEntry
+     * for performance. (This is not worth doing for most methods,
+     * that are less dependent on comparator performance, but is
+     * worthwhile here.)
+     */
+    final TreeMapEntry<K,V> getEntryUsingComparator(Object key) {
+        @SuppressWarnings("unchecked")
+            K k = (K) key;
+        Comparator<? super K> cpr = comparator;
+        if (cpr != null) {
+            TreeMapEntry<K,V> p = root;
+            while (p != null) {
+                int cmp = cpr.compare(k, p.key);
+                if (cmp < 0)
+                    p = p.left;
+                else if (cmp > 0)
+                    p = p.right;
+                else
+                    return p;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the entry corresponding to the specified key; if no such entry
+     * exists, returns the entry for the least key greater than the specified
+     * key; if no such entry exists (i.e., the greatest key in the Tree is less
+     * than the specified key), returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getCeilingEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp < 0) {
+                if (p.left != null)
+                    p = p.left;
+                else
+                    return p;
+            } else if (cmp > 0) {
+                if (p.right != null) {
+                    p = p.right;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.right) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            } else
+                return p;
+        }
+        return null;
+    }
+
+    /**
+     * Gets the entry corresponding to the specified key; if no such entry
+     * exists, returns the entry for the greatest key less than the specified
+     * key; if no such entry exists, returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getFloorEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp > 0) {
+                if (p.right != null)
+                    p = p.right;
+                else
+                    return p;
+            } else if (cmp < 0) {
+                if (p.left != null) {
+                    p = p.left;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.left) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            } else
+                return p;
+
+        }
+        return null;
+    }
+
+    /**
+     * Gets the entry for the least key greater than the specified
+     * key; if no such entry exists, returns the entry for the least
+     * key greater than the specified key; if no such entry exists
+     * returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getHigherEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp < 0) {
+                if (p.left != null)
+                    p = p.left;
+                else
+                    return p;
+            } else {
+                if (p.right != null) {
+                    p = p.right;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.right) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the entry for the greatest key less than the specified key; if
+     * no such entry exists (i.e., the least key in the Tree is greater than
+     * the specified key), returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getLowerEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp > 0) {
+                if (p.right != null)
+                    p = p.right;
+                else
+                    return p;
+            } else {
+                if (p.left != null) {
+                    p = p.left;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.left) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for the 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 the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key}.)
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public V put(K key, V value) {
+        TreeMapEntry<K,V> t = root;
+        if (t == null) {
+            compare(key, key); // type (and possibly null) check
+
+            root = new TreeMapEntry<>(key, value, null);
+            size = 1;
+            modCount++;
+            return null;
+        }
+        int cmp;
+        TreeMapEntry<K,V> parent;
+        // split comparator and comparable paths
+        Comparator<? super K> cpr = comparator;
+        if (cpr != null) {
+            do {
+                parent = t;
+                cmp = cpr.compare(key, t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else
+                    return t.setValue(value);
+            } while (t != null);
+        }
+        else {
+            if (key == null)
+                throw new NullPointerException();
+            @SuppressWarnings("unchecked")
+                Comparable<? super K> k = (Comparable<? super K>) key;
+            do {
+                parent = t;
+                cmp = k.compareTo(t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else
+                    return t.setValue(value);
+            } while (t != null);
+        }
+        TreeMapEntry<K,V> e = new TreeMapEntry<>(key, value, parent);
+        if (cmp < 0)
+            parent.left = e;
+        else
+            parent.right = e;
+        fixAfterInsertion(e);
+        size++;
+        modCount++;
+        return null;
+    }
+
+    /**
+     * Removes the mapping for this key from this TreeMap if present.
+     *
+     * @param  key key for which mapping should be removed
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key}.)
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public V remove(Object key) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        if (p == null)
+            return null;
+
+        V oldValue = p.value;
+        deleteEntry(p);
+        return oldValue;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+        size = 0;
+        root = null;
+    }
+
+    /**
+     * Returns a shallow copy of this {@code TreeMap} instance. (The keys and
+     * values themselves are not cloned.)
+     *
+     * @return a shallow copy of this map
+     */
+    public Object clone() {
+        TreeMap<?,?> clone;
+        try {
+            clone = (TreeMap<?,?>) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+
+        // Put clone into "virgin" state (except for comparator)
+        clone.root = null;
+        clone.size = 0;
+        clone.modCount = 0;
+        clone.entrySet = null;
+        clone.navigableKeySet = null;
+        clone.descendingMap = null;
+
+        // Initialize clone with our mappings
+        try {
+            clone.buildFromSorted(size, entrySet().iterator(), null, null);
+        } catch (java.io.IOException cannotHappen) {
+        } catch (ClassNotFoundException cannotHappen) {
+        }
+
+        return clone;
+    }
+
+    // NavigableMap API methods
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> firstEntry() {
+        return exportEntry(getFirstEntry());
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> lastEntry() {
+        return exportEntry(getLastEntry());
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> pollFirstEntry() {
+        TreeMapEntry<K,V> p = getFirstEntry();
+        Map.Entry<K,V> result = exportEntry(p);
+        if (p != null)
+            deleteEntry(p);
+        return result;
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> pollLastEntry() {
+        TreeMapEntry<K,V> p = getLastEntry();
+        Map.Entry<K,V> result = exportEntry(p);
+        if (p != null)
+            deleteEntry(p);
+        return result;
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> lowerEntry(K key) {
+        return exportEntry(getLowerEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K lowerKey(K key) {
+        return keyOrNull(getLowerEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> floorEntry(K key) {
+        return exportEntry(getFloorEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K floorKey(K key) {
+        return keyOrNull(getFloorEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> ceilingEntry(K key) {
+        return exportEntry(getCeilingEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K ceilingKey(K key) {
+        return keyOrNull(getCeilingEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> higherEntry(K key) {
+        return exportEntry(getHigherEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K higherKey(K key) {
+        return keyOrNull(getHigherEntry(key));
+    }
+
+    // Views
+
+    /**
+     * Fields initialized to contain an instance of the entry set view
+     * the first time this view is requested.  Views are stateless, so
+     * there's no reason to create more than one.
+     */
+    private transient EntrySet entrySet;
+    private transient KeySet<K> navigableKeySet;
+    private transient NavigableMap<K,V> descendingMap;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     *
+     * <p>The set's iterator returns the keys in ascending order.
+     * The set's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#SORTED}
+     * and {@link Spliterator#ORDERED} with an encounter order that is ascending
+     * key order.  The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the tree map's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the tree map's comparator.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     */
+    public Set<K> keySet() {
+        return navigableKeySet();
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableSet<K> navigableKeySet() {
+        KeySet<K> nks = navigableKeySet;
+        return (nks != null) ? nks : (navigableKeySet = new KeySet<>(this));
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableSet<K> descendingKeySet() {
+        return descendingMap().navigableKeySet();
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     *
+     * <p>The collection's iterator returns the values in ascending order
+     * of the corresponding keys. The collection's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#ORDERED}
+     * with an encounter order that is ascending order of the corresponding
+     * keys.
+     *
+     * <p>The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     *
+     * <p>The set's iterator returns the entries in ascending key order. The
+     * sets's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#SORTED} and
+     * {@link Spliterator#ORDERED} with an encounter order that is ascending key
+     * order.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        EntrySet es = entrySet;
+        return (es != null) ? es : (entrySet = new EntrySet());
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableMap<K, V> descendingMap() {
+        NavigableMap<K, V> km = descendingMap;
+        return (km != null) ? km :
+            (descendingMap = new DescendingSubMap<>(this,
+                                                    true, null, true,
+                                                    true, null, true));
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is
+     *         null and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                    K toKey,   boolean toInclusive) {
+        return new AscendingSubMap<>(this,
+                                     false, fromKey, fromInclusive,
+                                     false, toKey,   toInclusive);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
+        return new AscendingSubMap<>(this,
+                                     true,  null,  true,
+                                     false, toKey, inclusive);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
+        return new AscendingSubMap<>(this,
+                                     false, fromKey, inclusive,
+                                     true,  null,    true);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is
+     *         null and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedMap<K,V> subMap(K fromKey, K toKey) {
+        return subMap(fromKey, true, toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedMap<K,V> headMap(K toKey) {
+        return headMap(toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedMap<K,V> tailMap(K fromKey) {
+        return tailMap(fromKey, true);
+    }
+
+    @Override
+    public boolean replace(K key, V oldValue, V newValue) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        if (p!=null && Objects.equals(oldValue, p.value)) {
+            p.value = newValue;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public V replace(K key, V value) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        if (p!=null) {
+            V oldValue = p.value;
+            p.value = value;
+            return oldValue;
+        }
+        return null;
+    }
+
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+        for (TreeMapEntry<K, V> e = getFirstEntry(); e != null; e = successor(e)) {
+            action.accept(e.key, e.value);
+
+            if (expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        int expectedModCount = modCount;
+
+        for (TreeMapEntry<K, V> e = getFirstEntry(); e != null; e = successor(e)) {
+            e.value = function.apply(e.key, e.value);
+
+            if (expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    // View class support
+
+    class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator(getFirstEntry());
+        }
+
+        public int size() {
+            return TreeMap.this.size();
+        }
+
+        public boolean contains(Object o) {
+            return TreeMap.this.containsValue(o);
+        }
+
+        public boolean remove(Object o) {
+            for (TreeMapEntry<K,V> e = getFirstEntry(); e != null; e = successor(e)) {
+                if (valEquals(e.getValue(), o)) {
+                    deleteEntry(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public void clear() {
+            TreeMap.this.clear();
+        }
+
+        public Spliterator<V> spliterator() {
+            return new ValueSpliterator<K,V>(TreeMap.this, null, null, 0, -1, 0);
+        }
+    }
+
+    class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator(getFirstEntry());
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
+            Object value = entry.getValue();
+            TreeMapEntry<K,V> p = getEntry(entry.getKey());
+            return p != null && valEquals(p.getValue(), value);
+        }
+
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
+            Object value = entry.getValue();
+            TreeMapEntry<K,V> p = getEntry(entry.getKey());
+            if (p != null && valEquals(p.getValue(), value)) {
+                deleteEntry(p);
+                return true;
+            }
+            return false;
+        }
+
+        public int size() {
+            return TreeMap.this.size();
+        }
+
+        public void clear() {
+            TreeMap.this.clear();
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<K,V>(TreeMap.this, null, null, 0, -1, 0);
+        }
+    }
+
+    /*
+     * Unlike Values and EntrySet, the KeySet class is static,
+     * delegating to a NavigableMap to allow use by SubMaps, which
+     * outweighs the ugliness of needing type-tests for the following
+     * Iterator methods that are defined appropriately in main versus
+     * submap classes.
+     */
+
+    Iterator<K> keyIterator() {
+        return new KeyIterator(getFirstEntry());
+    }
+
+    Iterator<K> descendingKeyIterator() {
+        return new DescendingKeyIterator(getLastEntry());
+    }
+
+    static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> {
+        private final NavigableMap<E, ?> m;
+        KeySet(NavigableMap<E,?> map) { m = map; }
+
+        public Iterator<E> iterator() {
+            if (m instanceof TreeMap)
+                return ((TreeMap<E,?>)m).keyIterator();
+            else
+                return ((TreeMap.NavigableSubMap<E,?>)m).keyIterator();
+        }
+
+        public Iterator<E> descendingIterator() {
+            if (m instanceof TreeMap)
+                return ((TreeMap<E,?>)m).descendingKeyIterator();
+            else
+                return ((TreeMap.NavigableSubMap<E,?>)m).descendingKeyIterator();
+        }
+
+        public int size() { return m.size(); }
+        public boolean isEmpty() { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsKey(o); }
+        public void clear() { m.clear(); }
+        public E lower(E e) { return m.lowerKey(e); }
+        public E floor(E e) { return m.floorKey(e); }
+        public E ceiling(E e) { return m.ceilingKey(e); }
+        public E higher(E e) { return m.higherKey(e); }
+        public E first() { return m.firstKey(); }
+        public E last() { return m.lastKey(); }
+        public Comparator<? super E> comparator() { return m.comparator(); }
+        public E pollFirst() {
+            Map.Entry<E,?> e = m.pollFirstEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public E pollLast() {
+            Map.Entry<E,?> e = m.pollLastEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public boolean remove(Object o) {
+            int oldSize = size();
+            m.remove(o);
+            return size() != oldSize;
+        }
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
+                                      E toElement,   boolean toInclusive) {
+            return new KeySet<>(m.subMap(fromElement, fromInclusive,
+                                          toElement,   toInclusive));
+        }
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            return new KeySet<>(m.headMap(toElement, inclusive));
+        }
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            return new KeySet<>(m.tailMap(fromElement, inclusive));
+        }
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            return subSet(fromElement, true, toElement, false);
+        }
+        public SortedSet<E> headSet(E toElement) {
+            return headSet(toElement, false);
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            return tailSet(fromElement, true);
+        }
+        public NavigableSet<E> descendingSet() {
+            return new KeySet<>(m.descendingMap());
+        }
+
+        public Spliterator<E> spliterator() {
+            return keySpliteratorFor(m);
+        }
+    }
+
+    /**
+     * Base class for TreeMap Iterators
+     */
+    abstract class PrivateEntryIterator<T> implements Iterator<T> {
+        TreeMapEntry<K,V> next;
+        TreeMapEntry<K,V> lastReturned;
+        int expectedModCount;
+
+        PrivateEntryIterator(TreeMapEntry<K,V> first) {
+            expectedModCount = modCount;
+            lastReturned = null;
+            next = first;
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        final TreeMapEntry<K,V> nextEntry() {
+            TreeMapEntry<K,V> e = next;
+            if (e == null)
+                throw new NoSuchElementException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            next = successor(e);
+            lastReturned = e;
+            return e;
+        }
+
+        final TreeMapEntry<K,V> prevEntry() {
+            TreeMapEntry<K,V> e = next;
+            if (e == null)
+                throw new NoSuchElementException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            next = predecessor(e);
+            lastReturned = e;
+            return e;
+        }
+
+        public void remove() {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            // deleted entries are replaced by their successors
+            if (lastReturned.left != null && lastReturned.right != null)
+                next = lastReturned;
+            deleteEntry(lastReturned);
+            expectedModCount = modCount;
+            lastReturned = null;
+        }
+    }
+
+    final class EntryIterator extends PrivateEntryIterator<Map.Entry<K,V>> {
+        EntryIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public Map.Entry<K,V> next() {
+            return nextEntry();
+        }
+    }
+
+    final class ValueIterator extends PrivateEntryIterator<V> {
+        ValueIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public V next() {
+            return nextEntry().value;
+        }
+    }
+
+    final class KeyIterator extends PrivateEntryIterator<K> {
+        KeyIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public K next() {
+            return nextEntry().key;
+        }
+    }
+
+    final class DescendingKeyIterator extends PrivateEntryIterator<K> {
+        DescendingKeyIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public K next() {
+            return prevEntry().key;
+        }
+        public void remove() {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            deleteEntry(lastReturned);
+            lastReturned = null;
+            expectedModCount = modCount;
+        }
+    }
+
+    // Little utilities
+
+    /**
+     * Compares two keys using the correct comparison method for this TreeMap.
+     */
+    @SuppressWarnings("unchecked")
+    final int compare(Object k1, Object k2) {
+        return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
+            : comparator.compare((K)k1, (K)k2);
+    }
+
+    /**
+     * Test two values for equality.  Differs from o1.equals(o2) only in
+     * that it copes with {@code null} o1 properly.
+     */
+    static final boolean valEquals(Object o1, Object o2) {
+        return (o1==null ? o2==null : o1.equals(o2));
+    }
+
+    /**
+     * Return SimpleImmutableEntry for entry, or null if null
+     */
+    static <K,V> Map.Entry<K,V> exportEntry(TreeMapEntry<K,V> e) {
+        return (e == null) ? null :
+            new AbstractMap.SimpleImmutableEntry<>(e);
+    }
+
+    /**
+     * Return key for entry, or null if null
+     */
+    static <K,V> K keyOrNull(TreeMapEntry<K,V> e) {
+        return (e == null) ? null : e.key;
+    }
+
+    /**
+     * Returns the key corresponding to the specified Entry.
+     * @throws NoSuchElementException if the Entry is null
+     */
+    static <K> K key(TreeMapEntry<K,?> e) {
+        if (e==null)
+            throw new NoSuchElementException();
+        return e.key;
+    }
+
+
+    // SubMaps
+
+    /**
+     * Dummy value serving as unmatchable fence key for unbounded
+     * SubMapIterators
+     */
+    private static final Object UNBOUNDED = new Object();
+
+    /**
+     * @serial include
+     */
+    abstract static class NavigableSubMap<K,V> extends AbstractMap<K,V>
+        implements NavigableMap<K,V>, java.io.Serializable {
+        // Android-changed: Explicitly add a serialVersionUID so that we're serialization
+        // compatible with the Java-7 version of this class. Several new methods were added
+        // in Java-8 but none of them have any bearing on the serialized format of the class
+        // or require any additional state to be preserved.
+        private static final long serialVersionUID = 2765629423043303731L;
+
+        /**
+         * The backing map.
+         */
+        final TreeMap<K,V> m;
+
+        /**
+         * Endpoints are represented as triples (fromStart, lo,
+         * loInclusive) and (toEnd, hi, hiInclusive). If fromStart is
+         * true, then the low (absolute) bound is the start of the
+         * backing map, and the other values are ignored. Otherwise,
+         * if loInclusive is true, lo is the inclusive bound, else lo
+         * is the exclusive bound. Similarly for the upper bound.
+         */
+        final K lo, hi;
+        final boolean fromStart, toEnd;
+        final boolean loInclusive, hiInclusive;
+
+        NavigableSubMap(TreeMap<K,V> m,
+                        boolean fromStart, K lo, boolean loInclusive,
+                        boolean toEnd,     K hi, boolean hiInclusive) {
+            if (!fromStart && !toEnd) {
+                if (m.compare(lo, hi) > 0)
+                    throw new IllegalArgumentException("fromKey > toKey");
+            } else {
+                if (!fromStart) // type check
+                    m.compare(lo, lo);
+                if (!toEnd)
+                    m.compare(hi, hi);
+            }
+
+            this.m = m;
+            this.fromStart = fromStart;
+            this.lo = lo;
+            this.loInclusive = loInclusive;
+            this.toEnd = toEnd;
+            this.hi = hi;
+            this.hiInclusive = hiInclusive;
+        }
+
+        // internal utilities
+
+        final boolean tooLow(Object key) {
+            if (!fromStart) {
+                int c = m.compare(key, lo);
+                if (c < 0 || (c == 0 && !loInclusive))
+                    return true;
+            }
+            return false;
+        }
+
+        final boolean tooHigh(Object key) {
+            if (!toEnd) {
+                int c = m.compare(key, hi);
+                if (c > 0 || (c == 0 && !hiInclusive))
+                    return true;
+            }
+            return false;
+        }
+
+        final boolean inRange(Object key) {
+            return !tooLow(key) && !tooHigh(key);
+        }
+
+        final boolean inClosedRange(Object key) {
+            return (fromStart || m.compare(key, lo) >= 0)
+                && (toEnd || m.compare(hi, key) >= 0);
+        }
+
+        final boolean inRange(Object key, boolean inclusive) {
+            return inclusive ? inRange(key) : inClosedRange(key);
+        }
+
+        /*
+         * Absolute versions of relation operations.
+         * Subclasses map to these using like-named "sub"
+         * versions that invert senses for descending maps
+         */
+
+        final TreeMapEntry<K,V> absLowest() {
+            TreeMapEntry<K,V> e =
+                (fromStart ?  m.getFirstEntry() :
+                 (loInclusive ? m.getCeilingEntry(lo) :
+                                m.getHigherEntry(lo)));
+            return (e == null || tooHigh(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absHighest() {
+            TreeMapEntry<K,V> e =
+                (toEnd ?  m.getLastEntry() :
+                 (hiInclusive ?  m.getFloorEntry(hi) :
+                                 m.getLowerEntry(hi)));
+            return (e == null || tooLow(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absCeiling(K key) {
+            if (tooLow(key))
+                return absLowest();
+            TreeMapEntry<K,V> e = m.getCeilingEntry(key);
+            return (e == null || tooHigh(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absHigher(K key) {
+            if (tooLow(key))
+                return absLowest();
+            TreeMapEntry<K,V> e = m.getHigherEntry(key);
+            return (e == null || tooHigh(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absFloor(K key) {
+            if (tooHigh(key))
+                return absHighest();
+            TreeMapEntry<K,V> e = m.getFloorEntry(key);
+            return (e == null || tooLow(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absLower(K key) {
+            if (tooHigh(key))
+                return absHighest();
+            TreeMapEntry<K,V> e = m.getLowerEntry(key);
+            return (e == null || tooLow(e.key)) ? null : e;
+        }
+
+        /** Returns the absolute high fence for ascending traversal */
+        final TreeMapEntry<K,V> absHighFence() {
+            return (toEnd ? null : (hiInclusive ?
+                                    m.getHigherEntry(hi) :
+                                    m.getCeilingEntry(hi)));
+        }
+
+        /** Return the absolute low fence for descending traversal  */
+        final TreeMapEntry<K,V> absLowFence() {
+            return (fromStart ? null : (loInclusive ?
+                                        m.getLowerEntry(lo) :
+                                        m.getFloorEntry(lo)));
+        }
+
+        // Abstract methods defined in ascending vs descending classes
+        // These relay to the appropriate absolute versions
+
+        abstract TreeMapEntry<K,V> subLowest();
+        abstract TreeMapEntry<K,V> subHighest();
+        abstract TreeMapEntry<K,V> subCeiling(K key);
+        abstract TreeMapEntry<K,V> subHigher(K key);
+        abstract TreeMapEntry<K,V> subFloor(K key);
+        abstract TreeMapEntry<K,V> subLower(K key);
+
+        /** Returns ascending iterator from the perspective of this submap */
+        abstract Iterator<K> keyIterator();
+
+        abstract Spliterator<K> keySpliterator();
+
+        /** Returns descending iterator from the perspective of this submap */
+        abstract Iterator<K> descendingKeyIterator();
+
+        // public methods
+
+        public boolean isEmpty() {
+            return (fromStart && toEnd) ? m.isEmpty() : entrySet().isEmpty();
+        }
+
+        public int size() {
+            return (fromStart && toEnd) ? m.size() : entrySet().size();
+        }
+
+        public final boolean containsKey(Object key) {
+            return inRange(key) && m.containsKey(key);
+        }
+
+        public final V put(K key, V value) {
+            if (!inRange(key))
+                throw new IllegalArgumentException("key out of range");
+            return m.put(key, value);
+        }
+
+        public final V get(Object key) {
+            return !inRange(key) ? null :  m.get(key);
+        }
+
+        public final V remove(Object key) {
+            return !inRange(key) ? null : m.remove(key);
+        }
+
+        public final Map.Entry<K,V> ceilingEntry(K key) {
+            return exportEntry(subCeiling(key));
+        }
+
+        public final K ceilingKey(K key) {
+            return keyOrNull(subCeiling(key));
+        }
+
+        public final Map.Entry<K,V> higherEntry(K key) {
+            return exportEntry(subHigher(key));
+        }
+
+        public final K higherKey(K key) {
+            return keyOrNull(subHigher(key));
+        }
+
+        public final Map.Entry<K,V> floorEntry(K key) {
+            return exportEntry(subFloor(key));
+        }
+
+        public final K floorKey(K key) {
+            return keyOrNull(subFloor(key));
+        }
+
+        public final Map.Entry<K,V> lowerEntry(K key) {
+            return exportEntry(subLower(key));
+        }
+
+        public final K lowerKey(K key) {
+            return keyOrNull(subLower(key));
+        }
+
+        public final K firstKey() {
+            return key(subLowest());
+        }
+
+        public final K lastKey() {
+            return key(subHighest());
+        }
+
+        public final Map.Entry<K,V> firstEntry() {
+            return exportEntry(subLowest());
+        }
+
+        public final Map.Entry<K,V> lastEntry() {
+            return exportEntry(subHighest());
+        }
+
+        public final Map.Entry<K,V> pollFirstEntry() {
+            TreeMapEntry<K,V> e = subLowest();
+            Map.Entry<K,V> result = exportEntry(e);
+            if (e != null)
+                m.deleteEntry(e);
+            return result;
+        }
+
+        public final Map.Entry<K,V> pollLastEntry() {
+            TreeMapEntry<K,V> e = subHighest();
+            Map.Entry<K,V> result = exportEntry(e);
+            if (e != null)
+                m.deleteEntry(e);
+            return result;
+        }
+
+        // Views
+        transient NavigableMap<K,V> descendingMapView;
+        transient EntrySetView entrySetView;
+        transient KeySet<K> navigableKeySetView;
+
+        public final NavigableSet<K> navigableKeySet() {
+            KeySet<K> nksv = navigableKeySetView;
+            return (nksv != null) ? nksv :
+                (navigableKeySetView = new TreeMap.KeySet<>(this));
+        }
+
+        public final Set<K> keySet() {
+            return navigableKeySet();
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            return descendingMap().navigableKeySet();
+        }
+
+        public final SortedMap<K,V> subMap(K fromKey, K toKey) {
+            return subMap(fromKey, true, toKey, false);
+        }
+
+        public final SortedMap<K,V> headMap(K toKey) {
+            return headMap(toKey, false);
+        }
+
+        public final SortedMap<K,V> tailMap(K fromKey) {
+            return tailMap(fromKey, true);
+        }
+
+        // View classes
+
+        abstract class EntrySetView extends AbstractSet<Map.Entry<K,V>> {
+            private transient int size = -1, sizeModCount;
+
+            public int size() {
+                if (fromStart && toEnd)
+                    return m.size();
+                if (size == -1 || sizeModCount != m.modCount) {
+                    sizeModCount = m.modCount;
+                    size = 0;
+                    Iterator<?> i = iterator();
+                    while (i.hasNext()) {
+                        size++;
+                        i.next();
+                    }
+                }
+                return size;
+            }
+
+            public boolean isEmpty() {
+                TreeMapEntry<K,V> n = absLowest();
+                return n == null || tooHigh(n.key);
+            }
+
+            public boolean contains(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
+                Object key = entry.getKey();
+                if (!inRange(key))
+                    return false;
+                TreeMapEntry<?, ?> node = m.getEntry(key);
+                return node != null &&
+                    valEquals(node.getValue(), entry.getValue());
+            }
+
+            public boolean remove(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
+                Object key = entry.getKey();
+                if (!inRange(key))
+                    return false;
+                TreeMapEntry<K,V> node = m.getEntry(key);
+                if (node!=null && valEquals(node.getValue(),
+                                            entry.getValue())) {
+                    m.deleteEntry(node);
+                    return true;
+                }
+                return false;
+            }
+        }
+
+        /**
+         * Iterators for SubMaps
+         */
+        abstract class SubMapIterator<T> implements Iterator<T> {
+            TreeMapEntry<K,V> lastReturned;
+            TreeMapEntry<K,V> next;
+            final Object fenceKey;
+            int expectedModCount;
+
+            SubMapIterator(TreeMapEntry<K,V> first,
+                           TreeMapEntry<K,V> fence) {
+                expectedModCount = m.modCount;
+                lastReturned = null;
+                next = first;
+                fenceKey = fence == null ? UNBOUNDED : fence.key;
+            }
+
+            public final boolean hasNext() {
+                return next != null && next.key != fenceKey;
+            }
+
+            final TreeMapEntry<K,V> nextEntry() {
+                TreeMapEntry<K,V> e = next;
+                if (e == null || e.key == fenceKey)
+                    throw new NoSuchElementException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                next = successor(e);
+                lastReturned = e;
+                return e;
+            }
+
+            final TreeMapEntry<K,V> prevEntry() {
+                TreeMapEntry<K,V> e = next;
+                if (e == null || e.key == fenceKey)
+                    throw new NoSuchElementException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                next = predecessor(e);
+                lastReturned = e;
+                return e;
+            }
+
+            final void removeAscending() {
+                if (lastReturned == null)
+                    throw new IllegalStateException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                // deleted entries are replaced by their successors
+                if (lastReturned.left != null && lastReturned.right != null)
+                    next = lastReturned;
+                m.deleteEntry(lastReturned);
+                lastReturned = null;
+                expectedModCount = m.modCount;
+            }
+
+            final void removeDescending() {
+                if (lastReturned == null)
+                    throw new IllegalStateException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                m.deleteEntry(lastReturned);
+                lastReturned = null;
+                expectedModCount = m.modCount;
+            }
+
+        }
+
+        final class SubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
+            SubMapEntryIterator(TreeMapEntry<K,V> first,
+                                TreeMapEntry<K,V> fence) {
+                super(first, fence);
+            }
+            public Map.Entry<K,V> next() {
+                return nextEntry();
+            }
+            public void remove() {
+                removeAscending();
+            }
+        }
+
+        final class DescendingSubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
+            DescendingSubMapEntryIterator(TreeMapEntry<K,V> last,
+                                          TreeMapEntry<K,V> fence) {
+                super(last, fence);
+            }
+
+            public Map.Entry<K,V> next() {
+                return prevEntry();
+            }
+            public void remove() {
+                removeDescending();
+            }
+        }
+
+        // Implement minimal Spliterator as KeySpliterator backup
+        final class SubMapKeyIterator extends SubMapIterator<K>
+            implements Spliterator<K> {
+            SubMapKeyIterator(TreeMapEntry<K,V> first,
+                              TreeMapEntry<K,V> fence) {
+                super(first, fence);
+            }
+            public K next() {
+                return nextEntry().key;
+            }
+            public void remove() {
+                removeAscending();
+            }
+            public Spliterator<K> trySplit() {
+                return null;
+            }
+            public void forEachRemaining(Consumer<? super K> action) {
+                while (hasNext())
+                    action.accept(next());
+            }
+            public boolean tryAdvance(Consumer<? super K> action) {
+                if (hasNext()) {
+                    action.accept(next());
+                    return true;
+                }
+                return false;
+            }
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT | Spliterator.ORDERED |
+                    Spliterator.SORTED;
+            }
+            public final Comparator<? super K>  getComparator() {
+                return NavigableSubMap.this.comparator();
+            }
+        }
+
+        final class DescendingSubMapKeyIterator extends SubMapIterator<K>
+            implements Spliterator<K> {
+            DescendingSubMapKeyIterator(TreeMapEntry<K,V> last,
+                                        TreeMapEntry<K,V> fence) {
+                super(last, fence);
+            }
+            public K next() {
+                return prevEntry().key;
+            }
+            public void remove() {
+                removeDescending();
+            }
+            public Spliterator<K> trySplit() {
+                return null;
+            }
+            public void forEachRemaining(Consumer<? super K> action) {
+                while (hasNext())
+                    action.accept(next());
+            }
+            public boolean tryAdvance(Consumer<? super K> action) {
+                if (hasNext()) {
+                    action.accept(next());
+                    return true;
+                }
+                return false;
+            }
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT | Spliterator.ORDERED;
+            }
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static final class AscendingSubMap<K,V> extends NavigableSubMap<K,V> {
+        private static final long serialVersionUID = 912986545866124060L;
+
+        AscendingSubMap(TreeMap<K,V> m,
+                        boolean fromStart, K lo, boolean loInclusive,
+                        boolean toEnd,     K hi, boolean hiInclusive) {
+            super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
+        }
+
+        public Comparator<? super K> comparator() {
+            return m.comparator();
+        }
+
+        public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                        K toKey,   boolean toInclusive) {
+            if (!inRange(fromKey, fromInclusive))
+                throw new IllegalArgumentException("fromKey out of range");
+            if (!inRange(toKey, toInclusive))
+                throw new IllegalArgumentException("toKey out of range");
+            return new AscendingSubMap<>(m,
+                                         false, fromKey, fromInclusive,
+                                         false, toKey,   toInclusive);
+        }
+
+        public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases
+            // if (!inRange(toKey, inclusive))
+            if (!inRange(toKey) && !(!toEnd && m.compare(toKey, hi) == 0 &&
+                !hiInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases
+                throw new IllegalArgumentException("toKey out of range");
+            return new AscendingSubMap<>(m,
+                                         fromStart, lo,    loInclusive,
+                                         false,     toKey, inclusive);
+        }
+
+        public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases
+            // if (!inRange(fromKey, inclusive))
+            if (!inRange(fromKey) && !(!fromStart && m.compare(fromKey, lo) == 0 &&
+                !loInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases
+                throw new IllegalArgumentException("fromKey out of range");
+            return new AscendingSubMap<>(m,
+                                         false, fromKey, inclusive,
+                                         toEnd, hi,      hiInclusive);
+        }
+
+        public NavigableMap<K,V> descendingMap() {
+            NavigableMap<K,V> mv = descendingMapView;
+            return (mv != null) ? mv :
+                (descendingMapView =
+                 new DescendingSubMap<>(m,
+                                        fromStart, lo, loInclusive,
+                                        toEnd,     hi, hiInclusive));
+        }
+
+        Iterator<K> keyIterator() {
+            return new SubMapKeyIterator(absLowest(), absHighFence());
+        }
+
+        Spliterator<K> keySpliterator() {
+            return new SubMapKeyIterator(absLowest(), absHighFence());
+        }
+
+        Iterator<K> descendingKeyIterator() {
+            return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
+        }
+
+        final class AscendingEntrySetView extends EntrySetView {
+            public Iterator<Map.Entry<K,V>> iterator() {
+                return new SubMapEntryIterator(absLowest(), absHighFence());
+            }
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            EntrySetView es = entrySetView;
+            return (es != null) ? es : (entrySetView = new AscendingEntrySetView());
+        }
+
+        TreeMapEntry<K,V> subLowest()       { return absLowest(); }
+        TreeMapEntry<K,V> subHighest()      { return absHighest(); }
+        TreeMapEntry<K,V> subCeiling(K key) { return absCeiling(key); }
+        TreeMapEntry<K,V> subHigher(K key)  { return absHigher(key); }
+        TreeMapEntry<K,V> subFloor(K key)   { return absFloor(key); }
+        TreeMapEntry<K,V> subLower(K key)   { return absLower(key); }
+    }
+
+    /**
+     * @serial include
+     */
+    static final class DescendingSubMap<K,V>  extends NavigableSubMap<K,V> {
+        private static final long serialVersionUID = 912986545866120460L;
+        DescendingSubMap(TreeMap<K,V> m,
+                        boolean fromStart, K lo, boolean loInclusive,
+                        boolean toEnd,     K hi, boolean hiInclusive) {
+            super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
+        }
+
+        private final Comparator<? super K> reverseComparator =
+            Collections.reverseOrder(m.comparator);
+
+        public Comparator<? super K> comparator() {
+            return reverseComparator;
+        }
+
+        public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                        K toKey,   boolean toInclusive) {
+            if (!inRange(fromKey, fromInclusive))
+                throw new IllegalArgumentException("fromKey out of range");
+            if (!inRange(toKey, toInclusive))
+                throw new IllegalArgumentException("toKey out of range");
+            return new DescendingSubMap<>(m,
+                                          false, toKey,   toInclusive,
+                                          false, fromKey, fromInclusive);
+        }
+
+        public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases
+            // if (!inRange(toKey, inclusive))
+            if (!inRange(toKey) && !(!fromStart && m.compare(toKey, lo) == 0 &&
+                !loInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases
+                throw new IllegalArgumentException("toKey out of range");
+            return new DescendingSubMap<>(m,
+                                          false, toKey, inclusive,
+                                          toEnd, hi,    hiInclusive);
+        }
+
+        public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases
+            // if (!inRange(fromKey, inclusive))
+            if (!inRange(fromKey) && !(!toEnd && m.compare(fromKey, hi) == 0 &&
+                !hiInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases
+                throw new IllegalArgumentException("fromKey out of range");
+            return new DescendingSubMap<>(m,
+                                          fromStart, lo, loInclusive,
+                                          false, fromKey, inclusive);
+        }
+
+        public NavigableMap<K,V> descendingMap() {
+            NavigableMap<K,V> mv = descendingMapView;
+            return (mv != null) ? mv :
+                (descendingMapView =
+                 new AscendingSubMap<>(m,
+                                       fromStart, lo, loInclusive,
+                                       toEnd,     hi, hiInclusive));
+        }
+
+        Iterator<K> keyIterator() {
+            return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
+        }
+
+        Spliterator<K> keySpliterator() {
+            return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
+        }
+
+        Iterator<K> descendingKeyIterator() {
+            return new SubMapKeyIterator(absLowest(), absHighFence());
+        }
+
+        final class DescendingEntrySetView extends EntrySetView {
+            public Iterator<Map.Entry<K,V>> iterator() {
+                return new DescendingSubMapEntryIterator(absHighest(), absLowFence());
+            }
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            EntrySetView es = entrySetView;
+            return (es != null) ? es : (entrySetView = new DescendingEntrySetView());
+        }
+
+        TreeMapEntry<K,V> subLowest()       { return absHighest(); }
+        TreeMapEntry<K,V> subHighest()      { return absLowest(); }
+        TreeMapEntry<K,V> subCeiling(K key) { return absFloor(key); }
+        TreeMapEntry<K,V> subHigher(K key)  { return absLower(key); }
+        TreeMapEntry<K,V> subFloor(K key)   { return absCeiling(key); }
+        TreeMapEntry<K,V> subLower(K key)   { return absHigher(key); }
+    }
+
+    /**
+     * This class exists solely for the sake of serialization
+     * compatibility with previous releases of TreeMap that did not
+     * support NavigableMap.  It translates an old-version SubMap into
+     * a new-version AscendingSubMap. This class is never otherwise
+     * used.
+     *
+     * @serial include
+     */
+    private class SubMap extends AbstractMap<K,V>
+        implements SortedMap<K,V>, java.io.Serializable {
+        private static final long serialVersionUID = -6520786458950516097L;
+        private boolean fromStart = false, toEnd = false;
+        private K fromKey, toKey;
+        private Object readResolve() {
+            return new AscendingSubMap<>(TreeMap.this,
+                                         fromStart, fromKey, true,
+                                         toEnd, toKey, false);
+        }
+        public Set<Map.Entry<K,V>> entrySet() { throw new InternalError(); }
+        public K lastKey() { throw new InternalError(); }
+        public K firstKey() { throw new InternalError(); }
+        public SortedMap<K,V> subMap(K fromKey, K toKey) { throw new InternalError(); }
+        public SortedMap<K,V> headMap(K toKey) { throw new InternalError(); }
+        public SortedMap<K,V> tailMap(K fromKey) { throw new InternalError(); }
+        public Comparator<? super K> comparator() { throw new InternalError(); }
+    }
+
+
+    // Red-black mechanics
+
+    private static final boolean RED   = false;
+    private static final boolean BLACK = true;
+
+    /**
+     * Node in the Tree.  Doubles as a means to pass key-value pairs back to
+     * user (see Map.Entry).
+     */
+    // BEGIN Android-changed: Renamed Entry -> TreeMapEntry.
+    // Code references to "TreeMap.Entry" must mean Map.Entry
+    //
+    // This mirrors the corresponding rename of LinkedHashMap's
+    // Entry->LinkedHashMapEntry.
+    //
+    // This is for source compatibility with earlier versions of Android.
+    // Otherwise, it would hide Map.Entry.
+    // END Android-changed: Renamed Entry -> TreeMapEntry.
+    static final class TreeMapEntry<K,V> implements Map.Entry<K,V> {
+        K key;
+        V value;
+        TreeMapEntry<K,V> left;
+        TreeMapEntry<K,V> right;
+        TreeMapEntry<K,V> parent;
+        boolean color = BLACK;
+
+        /**
+         * Make a new cell with given key, value, and parent, and with
+         * {@code null} child links, and BLACK color.
+         */
+        TreeMapEntry(K key, V value, TreeMapEntry<K,V> parent) {
+            this.key = key;
+            this.value = value;
+            this.parent = parent;
+        }
+
+        /**
+         * Returns the key.
+         *
+         * @return the key
+         */
+        public K getKey() {
+            return key;
+        }
+
+        /**
+         * Returns the value associated with the key.
+         *
+         * @return the value associated with the key
+         */
+        public V getValue() {
+            return value;
+        }
+
+        /**
+         * Replaces the value currently associated with the key with the given
+         * value.
+         *
+         * @return the value associated with the key before this method was
+         *         called
+         */
+        public V setValue(V value) {
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+
+            return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
+        }
+
+        public int hashCode() {
+            int keyHash = (key==null ? 0 : key.hashCode());
+            int valueHash = (value==null ? 0 : value.hashCode());
+            return keyHash ^ valueHash;
+        }
+
+        public String toString() {
+            return key + "=" + value;
+        }
+    }
+
+    /**
+     * Returns the first Entry in the TreeMap (according to the TreeMap's
+     * key-sort function).  Returns null if the TreeMap is empty.
+     */
+    final TreeMapEntry<K,V> getFirstEntry() {
+        TreeMapEntry<K,V> p = root;
+        if (p != null)
+            while (p.left != null)
+                p = p.left;
+        return p;
+    }
+
+    /**
+     * Returns the last Entry in the TreeMap (according to the TreeMap's
+     * key-sort function).  Returns null if the TreeMap is empty.
+     */
+    final TreeMapEntry<K,V> getLastEntry() {
+        TreeMapEntry<K,V> p = root;
+        if (p != null)
+            while (p.right != null)
+                p = p.right;
+        return p;
+    }
+
+    /**
+     * Returns the successor of the specified Entry, or null if no such.
+     */
+    static <K,V> TreeMapEntry<K,V> successor(TreeMapEntry<K,V> t) {
+        if (t == null)
+            return null;
+        else if (t.right != null) {
+            TreeMapEntry<K,V> p = t.right;
+            while (p.left != null)
+                p = p.left;
+            return p;
+        } else {
+            TreeMapEntry<K,V> p = t.parent;
+            TreeMapEntry<K,V> ch = t;
+            while (p != null && ch == p.right) {
+                ch = p;
+                p = p.parent;
+            }
+            return p;
+        }
+    }
+
+    /**
+     * Returns the predecessor of the specified Entry, or null if no such.
+     */
+    static <K,V> TreeMapEntry<K,V> predecessor(TreeMapEntry<K,V> t) {
+        if (t == null)
+            return null;
+        else if (t.left != null) {
+            TreeMapEntry<K,V> p = t.left;
+            while (p.right != null)
+                p = p.right;
+            return p;
+        } else {
+            TreeMapEntry<K,V> p = t.parent;
+            TreeMapEntry<K,V> ch = t;
+            while (p != null && ch == p.left) {
+                ch = p;
+                p = p.parent;
+            }
+            return p;
+        }
+    }
+
+    /**
+     * Balancing operations.
+     *
+     * Implementations of rebalancings during insertion and deletion are
+     * slightly different than the CLR version.  Rather than using dummy
+     * nilnodes, we use a set of accessors that deal properly with null.  They
+     * are used to avoid messiness surrounding nullness checks in the main
+     * algorithms.
+     */
+
+    private static <K,V> boolean colorOf(TreeMapEntry<K,V> p) {
+        return (p == null ? BLACK : p.color);
+    }
+
+    private static <K,V> TreeMapEntry<K,V> parentOf(TreeMapEntry<K,V> p) {
+        return (p == null ? null: p.parent);
+    }
+
+    private static <K,V> void setColor(TreeMapEntry<K,V> p, boolean c) {
+        if (p != null)
+            p.color = c;
+    }
+
+    private static <K,V> TreeMapEntry<K,V> leftOf(TreeMapEntry<K,V> p) {
+        return (p == null) ? null: p.left;
+    }
+
+    private static <K,V> TreeMapEntry<K,V> rightOf(TreeMapEntry<K,V> p) {
+        return (p == null) ? null: p.right;
+    }
+
+    /** From CLR */
+    private void rotateLeft(TreeMapEntry<K,V> p) {
+        if (p != null) {
+            TreeMapEntry<K,V> r = p.right;
+            p.right = r.left;
+            if (r.left != null)
+                r.left.parent = p;
+            r.parent = p.parent;
+            if (p.parent == null)
+                root = r;
+            else if (p.parent.left == p)
+                p.parent.left = r;
+            else
+                p.parent.right = r;
+            r.left = p;
+            p.parent = r;
+        }
+    }
+
+    /** From CLR */
+    private void rotateRight(TreeMapEntry<K,V> p) {
+        if (p != null) {
+            TreeMapEntry<K,V> l = p.left;
+            p.left = l.right;
+            if (l.right != null) l.right.parent = p;
+            l.parent = p.parent;
+            if (p.parent == null)
+                root = l;
+            else if (p.parent.right == p)
+                p.parent.right = l;
+            else p.parent.left = l;
+            l.right = p;
+            p.parent = l;
+        }
+    }
+
+    /** From CLR */
+    private void fixAfterInsertion(TreeMapEntry<K,V> x) {
+        x.color = RED;
+
+        while (x != null && x != root && x.parent.color == RED) {
+            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
+                TreeMapEntry<K,V> y = rightOf(parentOf(parentOf(x)));
+                if (colorOf(y) == RED) {
+                    setColor(parentOf(x), BLACK);
+                    setColor(y, BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    x = parentOf(parentOf(x));
+                } else {
+                    if (x == rightOf(parentOf(x))) {
+                        x = parentOf(x);
+                        rotateLeft(x);
+                    }
+                    setColor(parentOf(x), BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    rotateRight(parentOf(parentOf(x)));
+                }
+            } else {
+                TreeMapEntry<K,V> y = leftOf(parentOf(parentOf(x)));
+                if (colorOf(y) == RED) {
+                    setColor(parentOf(x), BLACK);
+                    setColor(y, BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    x = parentOf(parentOf(x));
+                } else {
+                    if (x == leftOf(parentOf(x))) {
+                        x = parentOf(x);
+                        rotateRight(x);
+                    }
+                    setColor(parentOf(x), BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    rotateLeft(parentOf(parentOf(x)));
+                }
+            }
+        }
+        root.color = BLACK;
+    }
+
+    /**
+     * Delete node p, and then rebalance the tree.
+     */
+    private void deleteEntry(TreeMapEntry<K,V> p) {
+        modCount++;
+        size--;
+
+        // If strictly internal, copy successor's element to p and then make p
+        // point to successor.
+        if (p.left != null && p.right != null) {
+            TreeMapEntry<K,V> s = successor(p);
+            p.key = s.key;
+            p.value = s.value;
+            p = s;
+        } // p has 2 children
+
+        // Start fixup at replacement node, if it exists.
+        TreeMapEntry<K,V> replacement = (p.left != null ? p.left : p.right);
+
+        if (replacement != null) {
+            // Link replacement to parent
+            replacement.parent = p.parent;
+            if (p.parent == null)
+                root = replacement;
+            else if (p == p.parent.left)
+                p.parent.left  = replacement;
+            else
+                p.parent.right = replacement;
+
+            // Null out links so they are OK to use by fixAfterDeletion.
+            p.left = p.right = p.parent = null;
+
+            // Fix replacement
+            if (p.color == BLACK)
+                fixAfterDeletion(replacement);
+        } else if (p.parent == null) { // return if we are the only node.
+            root = null;
+        } else { //  No children. Use self as phantom replacement and unlink.
+            if (p.color == BLACK)
+                fixAfterDeletion(p);
+
+            if (p.parent != null) {
+                if (p == p.parent.left)
+                    p.parent.left = null;
+                else if (p == p.parent.right)
+                    p.parent.right = null;
+                p.parent = null;
+            }
+        }
+    }
+
+    /** From CLR */
+    private void fixAfterDeletion(TreeMapEntry<K,V> x) {
+        while (x != root && colorOf(x) == BLACK) {
+            if (x == leftOf(parentOf(x))) {
+                TreeMapEntry<K,V> sib = rightOf(parentOf(x));
+
+                if (colorOf(sib) == RED) {
+                    setColor(sib, BLACK);
+                    setColor(parentOf(x), RED);
+                    rotateLeft(parentOf(x));
+                    sib = rightOf(parentOf(x));
+                }
+
+                if (colorOf(leftOf(sib))  == BLACK &&
+                    colorOf(rightOf(sib)) == BLACK) {
+                    setColor(sib, RED);
+                    x = parentOf(x);
+                } else {
+                    if (colorOf(rightOf(sib)) == BLACK) {
+                        setColor(leftOf(sib), BLACK);
+                        setColor(sib, RED);
+                        rotateRight(sib);
+                        sib = rightOf(parentOf(x));
+                    }
+                    setColor(sib, colorOf(parentOf(x)));
+                    setColor(parentOf(x), BLACK);
+                    setColor(rightOf(sib), BLACK);
+                    rotateLeft(parentOf(x));
+                    x = root;
+                }
+            } else { // symmetric
+                TreeMapEntry<K,V> sib = leftOf(parentOf(x));
+
+                if (colorOf(sib) == RED) {
+                    setColor(sib, BLACK);
+                    setColor(parentOf(x), RED);
+                    rotateRight(parentOf(x));
+                    sib = leftOf(parentOf(x));
+                }
+
+                if (colorOf(rightOf(sib)) == BLACK &&
+                    colorOf(leftOf(sib)) == BLACK) {
+                    setColor(sib, RED);
+                    x = parentOf(x);
+                } else {
+                    if (colorOf(leftOf(sib)) == BLACK) {
+                        setColor(rightOf(sib), BLACK);
+                        setColor(sib, RED);
+                        rotateLeft(sib);
+                        sib = leftOf(parentOf(x));
+                    }
+                    setColor(sib, colorOf(parentOf(x)));
+                    setColor(parentOf(x), BLACK);
+                    setColor(leftOf(sib), BLACK);
+                    rotateRight(parentOf(x));
+                    x = root;
+                }
+            }
+        }
+
+        setColor(x, BLACK);
+    }
+
+    private static final long serialVersionUID = 919286545866124006L;
+
+    /**
+     * Save the state of the {@code TreeMap} instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <em>size</em> of the TreeMap (the number of key-value
+     *             mappings) is emitted (int), followed by the key (Object)
+     *             and value (Object) for each key-value mapping represented
+     *             by the TreeMap. The key-value mappings are emitted in
+     *             key-order (as determined by the TreeMap's Comparator,
+     *             or by the keys' natural ordering if the TreeMap has no
+     *             Comparator).
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out the Comparator and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out size (number of Mappings)
+        s.writeInt(size);
+
+        // Write out keys and values (alternating)
+        for (Iterator<Map.Entry<K,V>> i = entrySet().iterator(); i.hasNext(); ) {
+            Map.Entry<K,V> e = i.next();
+            s.writeObject(e.getKey());
+            s.writeObject(e.getValue());
+        }
+    }
+
+    /**
+     * Reconstitute the {@code TreeMap} instance from a stream (i.e.,
+     * deserialize it).
+     */
+    private void readObject(final java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in the Comparator and any hidden stuff
+        s.defaultReadObject();
+
+        // Read in size
+        int size = s.readInt();
+
+        buildFromSorted(size, null, s, null);
+    }
+
+    /** Intended to be called only from TreeSet.readObject */
+    void readTreeSet(int size, java.io.ObjectInputStream s, V defaultVal)
+        throws java.io.IOException, ClassNotFoundException {
+        buildFromSorted(size, null, s, defaultVal);
+    }
+
+    /** Intended to be called only from TreeSet.addAll */
+    void addAllForTreeSet(SortedSet<? extends K> set, V defaultVal) {
+        try {
+            buildFromSorted(set.size(), set.iterator(), null, defaultVal);
+        } catch (java.io.IOException cannotHappen) {
+        } catch (ClassNotFoundException cannotHappen) {
+        }
+    }
+
+
+    /**
+     * Linear time tree building algorithm from sorted data.  Can accept keys
+     * and/or values from iterator or stream. This leads to too many
+     * parameters, but seems better than alternatives.  The four formats
+     * that this method accepts are:
+     *
+     *    1) An iterator of Map.Entries.  (it != null, defaultVal == null).
+     *    2) An iterator of keys.         (it != null, defaultVal != null).
+     *    3) A stream of alternating serialized keys and values.
+     *                                   (it == null, defaultVal == null).
+     *    4) A stream of serialized keys. (it == null, defaultVal != null).
+     *
+     * It is assumed that the comparator of the TreeMap is already set prior
+     * to calling this method.
+     *
+     * @param size the number of keys (or key-value pairs) to be read from
+     *        the iterator or stream
+     * @param it If non-null, new entries are created from entries
+     *        or keys read from this iterator.
+     * @param str If non-null, new entries are created from keys and
+     *        possibly values read from this stream in serialized form.
+     *        Exactly one of it and str should be non-null.
+     * @param defaultVal if non-null, this default value is used for
+     *        each value in the map.  If null, each value is read from
+     *        iterator or stream, as described above.
+     * @throws java.io.IOException propagated from stream reads. This cannot
+     *         occur if str is null.
+     * @throws ClassNotFoundException propagated from readObject.
+     *         This cannot occur if str is null.
+     */
+    private void buildFromSorted(int size, Iterator<?> it,
+                                 java.io.ObjectInputStream str,
+                                 V defaultVal)
+        throws  java.io.IOException, ClassNotFoundException {
+        this.size = size;
+        root = buildFromSorted(0, 0, size-1, computeRedLevel(size),
+                               it, str, defaultVal);
+    }
+
+    /**
+     * Recursive "helper method" that does the real work of the
+     * previous method.  Identically named parameters have
+     * identical definitions.  Additional parameters are documented below.
+     * It is assumed that the comparator and size fields of the TreeMap are
+     * already set prior to calling this method.  (It ignores both fields.)
+     *
+     * @param level the current level of tree. Initial call should be 0.
+     * @param lo the first element index of this subtree. Initial should be 0.
+     * @param hi the last element index of this subtree.  Initial should be
+     *        size-1.
+     * @param redLevel the level at which nodes should be red.
+     *        Must be equal to computeRedLevel for tree of this size.
+     */
+    @SuppressWarnings("unchecked")
+    private final TreeMapEntry<K,V> buildFromSorted(int level, int lo, int hi,
+                                             int redLevel,
+                                             Iterator<?> it,
+                                             java.io.ObjectInputStream str,
+                                             V defaultVal)
+        throws  java.io.IOException, ClassNotFoundException {
+        /*
+         * Strategy: The root is the middlemost element. To get to it, we
+         * have to first recursively construct the entire left subtree,
+         * so as to grab all of its elements. We can then proceed with right
+         * subtree.
+         *
+         * The lo and hi arguments are the minimum and maximum
+         * indices to pull out of the iterator or stream for current subtree.
+         * They are not actually indexed, we just proceed sequentially,
+         * ensuring that items are extracted in corresponding order.
+         */
+
+        if (hi < lo) return null;
+
+        int mid = (lo + hi) >>> 1;
+
+        TreeMapEntry<K,V> left  = null;
+        if (lo < mid)
+            left = buildFromSorted(level+1, lo, mid - 1, redLevel,
+                                   it, str, defaultVal);
+
+        // extract key and/or value from iterator or stream
+        K key;
+        V value;
+        if (it != null) {
+            if (defaultVal==null) {
+                Map.Entry<?,?> entry = (Map.Entry<?,?>)it.next();
+                key = (K)entry.getKey();
+                value = (V)entry.getValue();
+            } else {
+                key = (K)it.next();
+                value = defaultVal;
+            }
+        } else { // use stream
+            key = (K) str.readObject();
+            value = (defaultVal != null ? defaultVal : (V) str.readObject());
+        }
+
+        TreeMapEntry<K,V> middle =  new TreeMapEntry<>(key, value, null);
+
+        // color nodes in non-full bottommost level red
+        if (level == redLevel)
+            middle.color = RED;
+
+        if (left != null) {
+            middle.left = left;
+            left.parent = middle;
+        }
+
+        if (mid < hi) {
+            TreeMapEntry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel,
+                                               it, str, defaultVal);
+            middle.right = right;
+            right.parent = middle;
+        }
+
+        return middle;
+    }
+
+    /**
+     * Find the level down to which to assign all nodes BLACK.  This is the
+     * last `full' level of the complete binary tree produced by
+     * buildTree. The remaining nodes are colored RED. (This makes a `nice'
+     * set of color assignments wrt future insertions.) This level number is
+     * computed by finding the number of splits needed to reach the zeroeth
+     * node.  (The answer is ~lg(N), but in any case must be computed by same
+     * quick O(lg(N)) loop.)
+     */
+    private static int computeRedLevel(int sz) {
+        int level = 0;
+        for (int m = sz - 1; m >= 0; m = m / 2 - 1)
+            level++;
+        return level;
+    }
+
+    /**
+     * Currently, we support Spliterator-based versions only for the
+     * full map, in either plain of descending form, otherwise relying
+     * on defaults because size estimation for submaps would dominate
+     * costs. The type tests needed to check these for key views are
+     * not very nice but avoid disrupting existing class
+     * structures. Callers must use plain default spliterators if this
+     * returns null.
+     */
+    static <K> Spliterator<K> keySpliteratorFor(NavigableMap<K,?> m) {
+        if (m instanceof TreeMap) {
+            @SuppressWarnings("unchecked") TreeMap<K,Object> t =
+                (TreeMap<K,Object>) m;
+            return t.keySpliterator();
+        }
+        if (m instanceof DescendingSubMap) {
+            @SuppressWarnings("unchecked") DescendingSubMap<K,?> dm =
+                (DescendingSubMap<K,?>) m;
+            TreeMap<K,?> tm = dm.m;
+            if (dm == tm.descendingMap) {
+                @SuppressWarnings("unchecked") TreeMap<K,Object> t =
+                    (TreeMap<K,Object>) tm;
+                return t.descendingKeySpliterator();
+            }
+        }
+        @SuppressWarnings("unchecked") NavigableSubMap<K,?> sm =
+            (NavigableSubMap<K,?>) m;
+        return sm.keySpliterator();
+    }
+
+    final Spliterator<K> keySpliterator() {
+        return new KeySpliterator<K,V>(this, null, null, 0, -1, 0);
+    }
+
+    final Spliterator<K> descendingKeySpliterator() {
+        return new DescendingKeySpliterator<K,V>(this, null, null, 0, -2, 0);
+    }
+
+    /**
+     * Base class for spliterators.  Iteration starts at a given
+     * origin and continues up to but not including a given fence (or
+     * null for end).  At top-level, for ascending cases, the first
+     * split uses the root as left-fence/right-origin. From there,
+     * right-hand splits replace the current fence with its left
+     * child, also serving as origin for the split-off spliterator.
+     * Left-hands are symmetric. Descending versions place the origin
+     * at the end and invert ascending split rules.  This base class
+     * is non-commital about directionality, or whether the top-level
+     * spliterator covers the whole tree. This means that the actual
+     * split mechanics are located in subclasses. Some of the subclass
+     * trySplit methods are identical (except for return types), but
+     * not nicely factorable.
+     *
+     * Currently, subclass versions exist only for the full map
+     * (including descending keys via its descendingMap).  Others are
+     * possible but currently not worthwhile because submaps require
+     * O(n) computations to determine size, which substantially limits
+     * potential speed-ups of using custom Spliterators versus default
+     * mechanics.
+     *
+     * To boostrap initialization, external constructors use
+     * negative size estimates: -1 for ascend, -2 for descend.
+     */
+    static class TreeMapSpliterator<K,V> {
+        final TreeMap<K,V> tree;
+        TreeMapEntry<K,V> current; // traverser; initially first node in range
+        TreeMapEntry<K,V> fence;   // one past last, or null
+        int side;                   // 0: top, -1: is a left split, +1: right
+        int est;                    // size estimate (exact only for top-level)
+        int expectedModCount;       // for CME checks
+
+        TreeMapSpliterator(TreeMap<K,V> tree,
+                           TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                           int side, int est, int expectedModCount) {
+            this.tree = tree;
+            this.current = origin;
+            this.fence = fence;
+            this.side = side;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getEstimate() { // force initialization
+            int s; TreeMap<K,V> t;
+            if ((s = est) < 0) {
+                if ((t = tree) != null) {
+                    current = (s == -1) ? t.getFirstEntry() : t.getLastEntry();
+                    s = est = t.size;
+                    expectedModCount = t.modCount;
+                }
+                else
+                    s = est = 0;
+            }
+            return s;
+        }
+
+        public final long estimateSize() {
+            return (long)getEstimate();
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends TreeMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(TreeMap<K,V> tree,
+                       TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                       int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                s = ((e == null || e == f) ? null :      // empty
+                     (d == 0)              ? tree.root : // was top
+                     (d >  0)              ? e.right :   // was right
+                     (d <  0 && f != null) ? f.left :    // was left
+                     null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) < 0) {        // e not already past s
+                side = 1;
+                return new KeySpliterator<>
+                    (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pl;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e.key);
+                    if ((p = e.right) != null) {
+                        while ((pl = p.left) != null)
+                            p = pl;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.right)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = successor(e);
+            action.accept(e.key);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED;
+        }
+
+        public final Comparator<? super K>  getComparator() {
+            return tree.comparator;
+        }
+
+    }
+
+    static final class DescendingKeySpliterator<K,V>
+        extends TreeMapSpliterator<K,V>
+        implements Spliterator<K> {
+        DescendingKeySpliterator(TreeMap<K,V> tree,
+                                 TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                                 int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public DescendingKeySpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                    s = ((e == null || e == f) ? null :      // empty
+                         (d == 0)              ? tree.root : // was top
+                         (d <  0)              ? e.left :    // was left
+                         (d >  0 && f != null) ? f.right :   // was right
+                         null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) > 0) {       // e not already past s
+                side = 1;
+                return new DescendingKeySpliterator<>
+                        (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pr;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e.key);
+                    if ((p = e.left) != null) {
+                        while ((pr = p.right) != null)
+                            p = pr;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.left)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = predecessor(e);
+            action.accept(e.key);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT | Spliterator.ORDERED;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+            extends TreeMapSpliterator<K,V>
+            implements Spliterator<V> {
+        ValueSpliterator(TreeMap<K,V> tree,
+                         TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                         int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                    s = ((e == null || e == f) ? null :      // empty
+                         (d == 0)              ? tree.root : // was top
+                         (d >  0)              ? e.right :   // was right
+                         (d <  0 && f != null) ? f.left :    // was left
+                         null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) < 0) {        // e not already past s
+                side = 1;
+                return new ValueSpliterator<>
+                        (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pl;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e.value);
+                    if ((p = e.right) != null) {
+                        while ((pl = p.left) != null)
+                            p = pl;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.right)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = successor(e);
+            action.accept(e.value);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) | Spliterator.ORDERED;
+        }
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends TreeMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(TreeMap<K,V> tree,
+                         TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                         int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                    s = ((e == null || e == f) ? null :      // empty
+                         (d == 0)              ? tree.root : // was top
+                         (d >  0)              ? e.right :   // was right
+                         (d <  0 && f != null) ? f.left :    // was left
+                         null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) < 0) {        // e not already past s
+                side = 1;
+                return new EntrySpliterator<>
+                        (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pl;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e);
+                    if ((p = e.right) != null) {
+                        while ((pl = p.left) != null)
+                            p = pl;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.right)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = successor(e);
+            action.accept(e);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) |
+                    Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED;
+        }
+
+        @Override
+        public Comparator<Map.Entry<K, V>> getComparator() {
+            // Adapt or create a key-based comparator
+            if (tree.comparator != null) {
+                return Map.Entry.comparingByKey(tree.comparator);
+            }
+            else {
+                return (Comparator<Map.Entry<K, V>> & Serializable) (e1, e2) -> {
+                    @SuppressWarnings("unchecked")
+                    Comparable<? super K> k1 = (Comparable<? super K>) e1.getKey();
+                    return k1.compareTo(e2.getKey());
+                };
+            }
+        }
+    }
+}
diff --git a/java/util/TreeSet.java b/java/util/TreeSet.java
new file mode 100644
index 0000000..54eeeda
--- /dev/null
+++ b/java/util/TreeSet.java
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A {@link NavigableSet} implementation based on a {@link TreeMap}.
+ * The elements are ordered using their {@linkplain Comparable natural
+ * ordering}, or by a {@link Comparator} provided at set creation
+ * time, depending on which constructor is used.
+ *
+ * <p>This implementation provides guaranteed log(n) time cost for the basic
+ * operations ({@code add}, {@code remove} and {@code contains}).
+ *
+ * <p>Note that the ordering maintained by a set (whether or not an explicit
+ * comparator is provided) must be <i>consistent with equals</i> if it is to
+ * correctly implement the {@code Set} interface.  (See {@code Comparable}
+ * or {@code Comparator} for a precise definition of <i>consistent with
+ * equals</i>.)  This is so because the {@code Set} interface is defined in
+ * terms of the {@code equals} operation, but a {@code TreeSet} instance
+ * performs all element comparisons using its {@code compareTo} (or
+ * {@code compare}) method, so two elements that are deemed equal by this method
+ * are, from the standpoint of the set, equal.  The behavior of a set
+ * <i>is</i> well-defined even if its ordering is inconsistent with equals; it
+ * just fails to obey the general contract of the {@code Set} interface.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a tree set concurrently, and at least one
+ * of the threads modifies the set, it <i>must</i> be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the set.
+ * If no such object exists, the set should be "wrapped" using the
+ * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the set: <pre>
+ *   SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));</pre>
+ *
+ * <p>The iterators returned by this class's {@code iterator} method are
+ * <i>fail-fast</i>: if the set is modified at any time after the iterator is
+ * created, in any way except through the iterator's own {@code remove}
+ * method, 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 time in the future.
+ *
+ * <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 {@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>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @see     Collection
+ * @see     Set
+ * @see     HashSet
+ * @see     Comparable
+ * @see     Comparator
+ * @see     TreeMap
+ * @since   1.2
+ */
+
+public class TreeSet<E> extends AbstractSet<E>
+    implements NavigableSet<E>, Cloneable, java.io.Serializable
+{
+    /**
+     * The backing map.
+     */
+    private transient NavigableMap<E,Object> m;
+
+    // Dummy value to associate with an Object in the backing Map
+    private static final Object PRESENT = new Object();
+
+    /**
+     * Constructs a set backed by the specified navigable map.
+     */
+    TreeSet(NavigableMap<E,Object> m) {
+        this.m = m;
+    }
+
+    /**
+     * Constructs a new, empty tree set, sorted according to the
+     * natural ordering of its elements.  All elements inserted into
+     * the set must implement the {@link Comparable} interface.
+     * Furthermore, all such elements must be <i>mutually
+     * comparable</i>: {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the set.  If the user attempts to add an element
+     * to the set that violates this constraint (for example, the user
+     * attempts to add a string element to a set whose elements are
+     * integers), the {@code add} call will throw a
+     * {@code ClassCastException}.
+     */
+    public TreeSet() {
+        this(new TreeMap<E,Object>());
+    }
+
+    /**
+     * Constructs a new, empty tree set, sorted according to the specified
+     * comparator.  All elements inserted into the set must be <i>mutually
+     * comparable</i> by the specified comparator: {@code comparator.compare(e1,
+     * e2)} must not throw a {@code ClassCastException} for any elements
+     * {@code e1} and {@code e2} in the set.  If the user attempts to add
+     * an element to the set that violates this constraint, the
+     * {@code add} call will throw a {@code ClassCastException}.
+     *
+     * @param comparator the comparator that will be used to order this set.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the elements will be used.
+     */
+    public TreeSet(Comparator<? super E> comparator) {
+        this(new TreeMap<>(comparator));
+    }
+
+    /**
+     * Constructs a new tree set containing the elements in the specified
+     * collection, sorted according to the <i>natural ordering</i> of its
+     * elements.  All elements inserted into the set must implement the
+     * {@link Comparable} interface.  Furthermore, all such elements must be
+     * <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the set.
+     *
+     * @param c collection whose elements will comprise the new set
+     * @throws ClassCastException if the elements in {@code c} are
+     *         not {@link Comparable}, or are not mutually comparable
+     * @throws NullPointerException if the specified collection is null
+     */
+    public TreeSet(Collection<? extends E> c) {
+        this();
+        addAll(c);
+    }
+
+    /**
+     * Constructs a new tree set containing the same elements and
+     * using the same ordering as the specified sorted set.
+     *
+     * @param s sorted set whose elements will comprise the new set
+     * @throws NullPointerException if the specified sorted set is null
+     */
+    public TreeSet(SortedSet<E> s) {
+        this(s.comparator());
+        addAll(s);
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in ascending order.
+     *
+     * @return an iterator over the elements in this set in ascending order
+     */
+    public Iterator<E> iterator() {
+        return m.navigableKeySet().iterator();
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in descending order.
+     *
+     * @return an iterator over the elements in this set in descending order
+     * @since 1.6
+     */
+    public Iterator<E> descendingIterator() {
+        return m.descendingKeySet().iterator();
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableSet<E> descendingSet() {
+        return new TreeSet<>(m.descendingMap());
+    }
+
+    /**
+     * Returns the number of elements in this set (its cardinality).
+     *
+     * @return the number of elements in this set (its cardinality)
+     */
+    public int size() {
+        return m.size();
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return m.isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     *
+     * @param o object to be checked for containment in this set
+     * @return {@code true} if this set contains the specified element
+     * @throws ClassCastException if the specified object cannot be compared
+     *         with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     */
+    public boolean contains(Object o) {
+        return m.containsKey(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element {@code e} to this set if
+     * the set contains no element {@code e2} such that
+     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the specified
+     *         element
+     * @throws ClassCastException if the specified object cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     */
+    public boolean add(E e) {
+        return m.put(e, PRESENT)==null;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element {@code e} such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>,
+     * if this set contains such an element.  Returns {@code true} if
+     * this set contained the element (or equivalently, if this set
+     * changed as a result of the call).  (This set will not contain the
+     * element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     * @throws ClassCastException if the specified object cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     */
+    public boolean remove(Object o) {
+        return m.remove(o)==PRESENT;
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     * The set will be empty after this call returns.
+     */
+    public void clear() {
+        m.clear();
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set.
+     *
+     * @param c collection containing elements to be added to this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the elements provided cannot be compared
+     *         with the elements currently in the set
+     * @throws NullPointerException if the specified collection is null or
+     *         if any element is null and this set uses natural ordering, or
+     *         its comparator does not permit null elements
+     */
+    public  boolean addAll(Collection<? extends E> c) {
+        // Use linear-time version if applicable
+        if (m.size()==0 && c.size() > 0 &&
+            c instanceof SortedSet &&
+            m instanceof TreeMap) {
+            SortedSet<? extends E> set = (SortedSet<? extends E>) c;
+            TreeMap<E,Object> map = (TreeMap<E, Object>) m;
+            Comparator<?> cc = set.comparator();
+            Comparator<? super E> mc = map.comparator();
+            if (cc==mc || (cc != null && cc.equals(mc))) {
+                map.addAllForTreeSet(set, PRESENT);
+                return true;
+            }
+        }
+        return super.addAll(c);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or {@code toElement}
+     *         is null and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
+                                  E toElement,   boolean toInclusive) {
+        return new TreeSet<>(m.subMap(fromElement, fromInclusive,
+                                       toElement,   toInclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null and
+     *         this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+        return new TreeSet<>(m.headMap(toElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null and
+     *         this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+        return new TreeSet<>(m.tailMap(fromElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null and this set uses natural ordering,
+     *         or its comparator does not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedSet<E> subSet(E fromElement, E toElement) {
+        return subSet(fromElement, true, toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null
+     *         and this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedSet<E> headSet(E toElement) {
+        return headSet(toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null
+     *         and this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedSet<E> tailSet(E fromElement) {
+        return tailSet(fromElement, true);
+    }
+
+    public Comparator<? super E> comparator() {
+        return m.comparator();
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E first() {
+        return m.firstKey();
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E last() {
+        return m.lastKey();
+    }
+
+    // NavigableSet API methods
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E lower(E e) {
+        return m.lowerKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E floor(E e) {
+        return m.floorKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E ceiling(E e) {
+        return m.ceilingKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E higher(E e) {
+        return m.higherKey(e);
+    }
+
+    /**
+     * @since 1.6
+     */
+    public E pollFirst() {
+        Map.Entry<E,?> e = m.pollFirstEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+    /**
+     * @since 1.6
+     */
+    public E pollLast() {
+        Map.Entry<E,?> e = m.pollLastEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+    /**
+     * Returns a shallow copy of this {@code TreeSet} instance. (The elements
+     * themselves are not cloned.)
+     *
+     * @return a shallow copy of this set
+     */
+    @SuppressWarnings("unchecked")
+    public Object clone() {
+        TreeSet<E> clone;
+        try {
+            clone = (TreeSet<E>) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+
+        clone.m = new TreeMap<>(m);
+        return clone;
+    }
+
+    /**
+     * Save the state of the {@code TreeSet} instance to a stream (that is,
+     * serialize it).
+     *
+     * @serialData Emits the comparator used to order this set, or
+     *             {@code null} if it obeys its elements' natural ordering
+     *             (Object), followed by the size of the set (the number of
+     *             elements it contains) (int), followed by all of its
+     *             elements (each an Object) in order (as determined by the
+     *             set's Comparator, or by the elements' natural ordering if
+     *             the set has no Comparator).
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out Comparator
+        s.writeObject(m.comparator());
+
+        // Write out size
+        s.writeInt(m.size());
+
+        // Write out all elements in the proper order.
+        for (E e : m.keySet())
+            s.writeObject(e);
+    }
+
+    /**
+     * Reconstitute the {@code TreeSet} instance from a stream (that is,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in any hidden stuff
+        s.defaultReadObject();
+
+        // Read in Comparator
+        @SuppressWarnings("unchecked")
+            Comparator<? super E> c = (Comparator<? super E>) s.readObject();
+
+        // Create backing TreeMap
+        TreeMap<E,Object> tm = new TreeMap<>(c);
+        m = tm;
+
+        // Read in size
+        int size = s.readInt();
+
+        tm.readTreeSet(size, s, PRESENT);
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#DISTINCT}, {@link Spliterator#SORTED}, and
+     * {@link Spliterator#ORDERED}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * <p>The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the tree set's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the tree set's comparator.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return TreeMap.keySpliteratorFor(m);
+    }
+
+    private static final long serialVersionUID = -2479143000061671589L;
+}
diff --git a/java/util/Tripwire.java b/java/util/Tripwire.java
new file mode 100644
index 0000000..d1bd39e
--- /dev/null
+++ b/java/util/Tripwire.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import sun.util.logging.PlatformLogger;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Utility class for detecting inadvertent uses of boxing in
+ * {@code java.util} classes.  The detection is turned on or off based on
+ * whether the system property {@code org.openjdk.java.util.stream.tripwire} is
+ * considered {@code true} according to {@link Boolean#getBoolean(String)}.
+ * This should normally be turned off for production use.
+ *
+ * @apiNote
+ * Typical usage would be for boxing code to do:
+ * <pre>{@code
+ *     if (Tripwire.ENABLED)
+ *         Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.nextInt()");
+ * }</pre>
+ *
+ * @since 1.8
+ */
+final class Tripwire {
+    private static final String TRIPWIRE_PROPERTY = "org.openjdk.java.util.stream.tripwire";
+
+    /** Should debugging checks be enabled? */
+    static final boolean ENABLED = AccessController.doPrivileged(
+            (PrivilegedAction<Boolean>) () -> Boolean.getBoolean(TRIPWIRE_PROPERTY));
+
+    private Tripwire() { }
+
+    /**
+     * Produces a log warning, using {@code PlatformLogger.getLogger(className)},
+     * using the supplied message.  The class name of {@code trippingClass} will
+     * be used as the first parameter to the message.
+     *
+     * @param trippingClass Name of the class generating the message
+     * @param msg A message format string of the type expected by
+     * {@link PlatformLogger}
+     */
+    static void trip(Class<?> trippingClass, String msg) {
+        PlatformLogger.getLogger(trippingClass.getName()).warning(msg, trippingClass.getName());
+    }
+}
diff --git a/java/util/UUID.java b/java/util/UUID.java
new file mode 100644
index 0000000..b4ea41f
--- /dev/null
+++ b/java/util/UUID.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.security.*;
+
+/**
+ * A class that represents an immutable universally unique identifier (UUID).
+ * A UUID represents a 128-bit value.
+ *
+ * <p> There exist different variants of these global identifiers.  The methods
+ * of this class are for manipulating the Leach-Salz variant, although the
+ * constructors allow the creation of any variant of UUID (described below).
+ *
+ * <p> The layout of a variant 2 (Leach-Salz) UUID is as follows:
+ *
+ * The most significant long consists of the following unsigned fields:
+ * <pre>
+ * 0xFFFFFFFF00000000 time_low
+ * 0x00000000FFFF0000 time_mid
+ * 0x000000000000F000 version
+ * 0x0000000000000FFF time_hi
+ * </pre>
+ * The least significant long consists of the following unsigned fields:
+ * <pre>
+ * 0xC000000000000000 variant
+ * 0x3FFF000000000000 clock_seq
+ * 0x0000FFFFFFFFFFFF node
+ * </pre>
+ *
+ * <p> The variant field contains a value which identifies the layout of the
+ * {@code UUID}.  The bit layout described above is valid only for a {@code
+ * UUID} with a variant value of 2, which indicates the Leach-Salz variant.
+ *
+ * <p> The version field holds a value that describes the type of this {@code
+ * UUID}.  There are four different basic types of UUIDs: time-based, DCE
+ * security, name-based, and randomly generated UUIDs.  These types have a
+ * version value of 1, 2, 3 and 4, respectively.
+ *
+ * <p> For more information including algorithms used to create {@code UUID}s,
+ * see <a href="http://www.ietf.org/rfc/rfc4122.txt"> <i>RFC&nbsp;4122: A
+ * Universally Unique IDentifier (UUID) URN Namespace</i></a>, section 4.2
+ * &quot;Algorithms for Creating a Time-Based UUID&quot;.
+ *
+ * @since   1.5
+ */
+public final class UUID implements java.io.Serializable, Comparable<UUID> {
+
+    /**
+     * Explicit serialVersionUID for interoperability.
+     */
+    private static final long serialVersionUID = -4856846361193249489L;
+
+    /*
+     * The most significant 64 bits of this UUID.
+     *
+     * @serial
+     */
+    private final long mostSigBits;
+
+    /*
+     * The least significant 64 bits of this UUID.
+     *
+     * @serial
+     */
+    private final long leastSigBits;
+
+    /*
+     * The random number generator used by this class to create random
+     * based UUIDs. In a holder class to defer initialization until needed.
+     */
+    private static class Holder {
+        static final SecureRandom numberGenerator = new SecureRandom();
+    }
+
+    // Constructors and Factories
+
+    /*
+     * Private constructor which uses a byte array to construct the new UUID.
+     */
+    private UUID(byte[] data) {
+        long msb = 0;
+        long lsb = 0;
+        assert data.length == 16 : "data must be 16 bytes in length";
+        for (int i=0; i<8; i++)
+            msb = (msb << 8) | (data[i] & 0xff);
+        for (int i=8; i<16; i++)
+            lsb = (lsb << 8) | (data[i] & 0xff);
+        this.mostSigBits = msb;
+        this.leastSigBits = lsb;
+    }
+
+    /**
+     * Constructs a new {@code UUID} using the specified data.  {@code
+     * mostSigBits} is used for the most significant 64 bits of the {@code
+     * UUID} and {@code leastSigBits} becomes the least significant 64 bits of
+     * the {@code UUID}.
+     *
+     * @param  mostSigBits
+     *         The most significant bits of the {@code UUID}
+     *
+     * @param  leastSigBits
+     *         The least significant bits of the {@code UUID}
+     */
+    public UUID(long mostSigBits, long leastSigBits) {
+        this.mostSigBits = mostSigBits;
+        this.leastSigBits = leastSigBits;
+    }
+
+    /**
+     * Static factory to retrieve a type 4 (pseudo randomly generated) UUID.
+     *
+     * The {@code UUID} is generated using a cryptographically strong pseudo
+     * random number generator.
+     *
+     * @return  A randomly generated {@code UUID}
+     */
+    public static UUID randomUUID() {
+        SecureRandom ng = Holder.numberGenerator;
+
+        byte[] randomBytes = new byte[16];
+        ng.nextBytes(randomBytes);
+        randomBytes[6]  &= 0x0f;  /* clear version        */
+        randomBytes[6]  |= 0x40;  /* set to version 4     */
+        randomBytes[8]  &= 0x3f;  /* clear variant        */
+        randomBytes[8]  |= 0x80;  /* set to IETF variant  */
+        return new UUID(randomBytes);
+    }
+
+    /**
+     * Static factory to retrieve a type 3 (name based) {@code UUID} based on
+     * the specified byte array.
+     *
+     * @param  name
+     *         A byte array to be used to construct a {@code UUID}
+     *
+     * @return  A {@code UUID} generated from the specified array
+     */
+    public static UUID nameUUIDFromBytes(byte[] name) {
+        MessageDigest md;
+        try {
+            md = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new InternalError("MD5 not supported", nsae);
+        }
+        byte[] md5Bytes = md.digest(name);
+        md5Bytes[6]  &= 0x0f;  /* clear version        */
+        md5Bytes[6]  |= 0x30;  /* set to version 3     */
+        md5Bytes[8]  &= 0x3f;  /* clear variant        */
+        md5Bytes[8]  |= 0x80;  /* set to IETF variant  */
+        return new UUID(md5Bytes);
+    }
+
+    /**
+     * Creates a {@code UUID} from the string standard representation as
+     * described in the {@link #toString} method.
+     *
+     * @param  name
+     *         A string that specifies a {@code UUID}
+     *
+     * @return  A {@code UUID} with the specified value
+     *
+     * @throws  IllegalArgumentException
+     *          If name does not conform to the string representation as
+     *          described in {@link #toString}
+     *
+     */
+    public static UUID fromString(String name) {
+        String[] components = name.split("-");
+        if (components.length != 5)
+            throw new IllegalArgumentException("Invalid UUID string: "+name);
+        for (int i=0; i<5; i++)
+            components[i] = "0x"+components[i];
+
+        long mostSigBits = Long.decode(components[0]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[1]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[2]).longValue();
+
+        long leastSigBits = Long.decode(components[3]).longValue();
+        leastSigBits <<= 48;
+        leastSigBits |= Long.decode(components[4]).longValue();
+
+        return new UUID(mostSigBits, leastSigBits);
+    }
+
+    // Field Accessor Methods
+
+    /**
+     * Returns the least significant 64 bits of this UUID's 128 bit value.
+     *
+     * @return  The least significant 64 bits of this UUID's 128 bit value
+     */
+    public long getLeastSignificantBits() {
+        return leastSigBits;
+    }
+
+    /**
+     * Returns the most significant 64 bits of this UUID's 128 bit value.
+     *
+     * @return  The most significant 64 bits of this UUID's 128 bit value
+     */
+    public long getMostSignificantBits() {
+        return mostSigBits;
+    }
+
+    /**
+     * The version number associated with this {@code UUID}.  The version
+     * number describes how this {@code UUID} was generated.
+     *
+     * The version number has the following meaning:
+     * <ul>
+     * <li>1    Time-based UUID
+     * <li>2    DCE security UUID
+     * <li>3    Name-based UUID
+     * <li>4    Randomly generated UUID
+     * </ul>
+     *
+     * @return  The version number of this {@code UUID}
+     */
+    public int version() {
+        // Version is bits masked by 0x000000000000F000 in MS long
+        return (int)((mostSigBits >> 12) & 0x0f);
+    }
+
+    /**
+     * The variant number associated with this {@code UUID}.  The variant
+     * number describes the layout of the {@code UUID}.
+     *
+     * The variant number has the following meaning:
+     * <ul>
+     * <li>0    Reserved for NCS backward compatibility
+     * <li>2    <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF&nbsp;RFC&nbsp;4122</a>
+     * (Leach-Salz), used by this class
+     * <li>6    Reserved, Microsoft Corporation backward compatibility
+     * <li>7    Reserved for future definition
+     * </ul>
+     *
+     * @return  The variant number of this {@code UUID}
+     */
+    public int variant() {
+        // This field is composed of a varying number of bits.
+        // 0    -    -    Reserved for NCS backward compatibility
+        // 1    0    -    The IETF aka Leach-Salz variant (used by this class)
+        // 1    1    0    Reserved, Microsoft backward compatibility
+        // 1    1    1    Reserved for future definition.
+        return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62)))
+                      & (leastSigBits >> 63));
+    }
+
+    /**
+     * The timestamp value associated with this UUID.
+     *
+     * <p> The 60 bit timestamp value is constructed from the time_low,
+     * time_mid, and time_hi fields of this {@code UUID}.  The resulting
+     * timestamp is measured in 100-nanosecond units since midnight,
+     * October 15, 1582 UTC.
+     *
+     * <p> The timestamp value is only meaningful in a time-based UUID, which
+     * has version type 1.  If this {@code UUID} is not a time-based UUID then
+     * this method throws UnsupportedOperationException.
+     *
+     * @throws UnsupportedOperationException
+     *         If this UUID is not a version 1 UUID
+     * @return The timestamp of this {@code UUID}.
+     */
+    public long timestamp() {
+        if (version() != 1) {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+
+        return (mostSigBits & 0x0FFFL) << 48
+             | ((mostSigBits >> 16) & 0x0FFFFL) << 32
+             | mostSigBits >>> 32;
+    }
+
+    /**
+     * The clock sequence value associated with this UUID.
+     *
+     * <p> The 14 bit clock sequence value is constructed from the clock
+     * sequence field of this UUID.  The clock sequence field is used to
+     * guarantee temporal uniqueness in a time-based UUID.
+     *
+     * <p> The {@code clockSequence} value is only meaningful in a time-based
+     * UUID, which has version type 1.  If this UUID is not a time-based UUID
+     * then this method throws UnsupportedOperationException.
+     *
+     * @return  The clock sequence of this {@code UUID}
+     *
+     * @throws  UnsupportedOperationException
+     *          If this UUID is not a version 1 UUID
+     */
+    public int clockSequence() {
+        if (version() != 1) {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+
+        return (int)((leastSigBits & 0x3FFF000000000000L) >>> 48);
+    }
+
+    /**
+     * The node value associated with this UUID.
+     *
+     * <p> The 48 bit node value is constructed from the node field of this
+     * UUID.  This field is intended to hold the IEEE 802 address of the machine
+     * that generated this UUID to guarantee spatial uniqueness.
+     *
+     * <p> The node value is only meaningful in a time-based UUID, which has
+     * version type 1.  If this UUID is not a time-based UUID then this method
+     * throws UnsupportedOperationException.
+     *
+     * @return  The node value of this {@code UUID}
+     *
+     * @throws  UnsupportedOperationException
+     *          If this UUID is not a version 1 UUID
+     */
+    public long node() {
+        if (version() != 1) {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+
+        return leastSigBits & 0x0000FFFFFFFFFFFFL;
+    }
+
+    // Object Inherited Methods
+
+    /**
+     * Returns a {@code String} object representing this {@code UUID}.
+     *
+     * <p> The UUID string representation is as described by this BNF:
+     * <blockquote><pre>
+     * {@code
+     * UUID                   = <time_low> "-" <time_mid> "-"
+     *                          <time_high_and_version> "-"
+     *                          <variant_and_sequence> "-"
+     *                          <node>
+     * time_low               = 4*<hexOctet>
+     * time_mid               = 2*<hexOctet>
+     * time_high_and_version  = 2*<hexOctet>
+     * variant_and_sequence   = 2*<hexOctet>
+     * node                   = 6*<hexOctet>
+     * hexOctet               = <hexDigit><hexDigit>
+     * hexDigit               =
+     *       "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+     *       | "a" | "b" | "c" | "d" | "e" | "f"
+     *       | "A" | "B" | "C" | "D" | "E" | "F"
+     * }</pre></blockquote>
+     *
+     * @return  A string representation of this {@code UUID}
+     */
+    public String toString() {
+        return (digits(mostSigBits >> 32, 8) + "-" +
+                digits(mostSigBits >> 16, 4) + "-" +
+                digits(mostSigBits, 4) + "-" +
+                digits(leastSigBits >> 48, 4) + "-" +
+                digits(leastSigBits, 12));
+    }
+
+    /** Returns val represented by the specified number of hex digits. */
+    private static String digits(long val, int digits) {
+        long hi = 1L << (digits * 4);
+        return Long.toHexString(hi | (val & (hi - 1))).substring(1);
+    }
+
+    /**
+     * Returns a hash code for this {@code UUID}.
+     *
+     * @return  A hash code value for this {@code UUID}
+     */
+    public int hashCode() {
+        long hilo = mostSigBits ^ leastSigBits;
+        return ((int)(hilo >> 32)) ^ (int) hilo;
+    }
+
+    /**
+     * Compares this object to the specified object.  The result is {@code
+     * true} if and only if the argument is not {@code null}, is a {@code UUID}
+     * object, has the same variant, and contains the same value, bit for bit,
+     * as this {@code UUID}.
+     *
+     * @param  obj
+     *         The object to be compared
+     *
+     * @return  {@code true} if the objects are the same; {@code false}
+     *          otherwise
+     */
+    public boolean equals(Object obj) {
+        if ((null == obj) || (obj.getClass() != UUID.class))
+            return false;
+        UUID id = (UUID)obj;
+        return (mostSigBits == id.mostSigBits &&
+                leastSigBits == id.leastSigBits);
+    }
+
+    // Comparison Operations
+
+    /**
+     * Compares this UUID with the specified UUID.
+     *
+     * <p> The first of two UUIDs is greater than the second if the most
+     * significant field in which the UUIDs differ is greater for the first
+     * UUID.
+     *
+     * @param  val
+     *         {@code UUID} to which this {@code UUID} is to be compared
+     *
+     * @return  -1, 0 or 1 as this {@code UUID} is less than, equal to, or
+     *          greater than {@code val}
+     *
+     */
+    public int compareTo(UUID val) {
+        // The ordering is intentionally set up so that the UUIDs
+        // can simply be numerically compared as two numbers
+        return (this.mostSigBits < val.mostSigBits ? -1 :
+                (this.mostSigBits > val.mostSigBits ? 1 :
+                 (this.leastSigBits < val.leastSigBits ? -1 :
+                  (this.leastSigBits > val.leastSigBits ? 1 :
+                   0))));
+    }
+}
diff --git a/java/util/UnknownFormatConversionException.java b/java/util/UnknownFormatConversionException.java
new file mode 100644
index 0000000..9ef964d
--- /dev/null
+++ b/java/util/UnknownFormatConversionException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when an unknown conversion is given.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to
+ * any method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class UnknownFormatConversionException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 19060418L;
+
+    private String s;
+
+    /**
+     * Constructs an instance of this class with the unknown conversion.
+     *
+     * @param  s
+     *         Unknown conversion
+     */
+    public UnknownFormatConversionException(String s) {
+        if (s == null)
+            throw new NullPointerException();
+        this.s = s;
+    }
+
+    /**
+     * Returns the unknown conversion.
+     *
+     * @return  The unknown conversion.
+     */
+    public String getConversion() {
+        return s;
+    }
+
+    // javadoc inherited from Throwable.java
+    public String getMessage() {
+        return String.format("Conversion = '%s'", s);
+    }
+}
diff --git a/java/util/UnknownFormatFlagsException.java b/java/util/UnknownFormatFlagsException.java
new file mode 100644
index 0000000..764fe6d
--- /dev/null
+++ b/java/util/UnknownFormatFlagsException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when an unknown flag is given.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class UnknownFormatFlagsException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 19370506L;
+
+    private String flags;
+
+    /**
+     * Constructs an instance of this class with the specified flags.
+     *
+     * @param  f
+     *         The set of format flags which contain an unknown flag
+     */
+    public UnknownFormatFlagsException(String f) {
+        if (f == null)
+            throw new NullPointerException();
+        this.flags = f;
+    }
+
+    /**
+     * Returns the set of flags which contains an unknown flag.
+     *
+     * @return  The flags
+     */
+    public String getFlags() {
+        return flags;
+    }
+
+    // javadoc inherited from Throwable.java
+    public String getMessage() {
+        return "Flags = " + flags;
+    }
+}
diff --git a/java/util/Vector.annotated.java b/java/util/Vector.annotated.java
new file mode 100644
index 0000000..09bb48c
--- /dev/null
+++ b/java/util/Vector.annotated.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Vector<E> extends java.util.AbstractList<E> implements java.util.List<E>, java.util.RandomAccess, java.lang.Cloneable, java.io.Serializable {
+
+public Vector(int initialCapacity, int capacityIncrement) { throw new RuntimeException("Stub!"); }
+
+public Vector(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+public Vector() { throw new RuntimeException("Stub!"); }
+
+public Vector(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized void copyInto([email protected] Object @libcore.util.NonNull [] anArray) { throw new RuntimeException("Stub!"); }
+
+public synchronized void trimToSize() { throw new RuntimeException("Stub!"); }
+
+public synchronized void ensureCapacity(int minCapacity) { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSize(int newSize) { throw new RuntimeException("Stub!"); }
+
+public synchronized int capacity() { throw new RuntimeException("Stub!"); }
+
+public synchronized int size() { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Enumeration<@libcore.util.NullFromTypeParam E> elements() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public synchronized int indexOf(@libcore.util.Nullable java.lang.Object o, int index) { throw new RuntimeException("Stub!"); }
+
+public synchronized int lastIndexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public synchronized int lastIndexOf(@libcore.util.Nullable java.lang.Object o, int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E elementAt(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E firstElement() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E lastElement() { throw new RuntimeException("Stub!"); }
+
+public synchronized void setElementAt(@libcore.util.NullFromTypeParam E obj, int index) { throw new RuntimeException("Stub!"); }
+
+public synchronized void removeElementAt(int index) { throw new RuntimeException("Stub!"); }
+
+public synchronized void insertElementAt(@libcore.util.NullFromTypeParam E obj, int index) { throw new RuntimeException("Stub!"); }
+
+public synchronized void addElement(@libcore.util.NullFromTypeParam E obj) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean removeElement(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public synchronized void removeAllElements() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public synchronized [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+public synchronized <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E get(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public synchronized int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+protected synchronized void removeRange(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
+public synchronized void forEach(@libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NullFromTypeParam E> action) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean removeIf(@libcore.util.NonNull java.util.function.Predicate<? super @libcore.util.NullFromTypeParam E> filter) { throw new RuntimeException("Stub!"); }
+
+public synchronized void replaceAll(@libcore.util.NonNull java.util.function.UnaryOperator<@libcore.util.NullFromTypeParam E> operator) { throw new RuntimeException("Stub!"); }
+
+public synchronized void sort(@libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
+protected int capacityIncrement;
+
+protected int elementCount;
+
+protected [email protected] Object @libcore.util.NonNull [] elementData;
+}
diff --git a/java/util/Vector.java b/java/util/Vector.java
new file mode 100644
index 0000000..f184437
--- /dev/null
+++ b/java/util/Vector.java
@@ -0,0 +1,1448 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+/**
+ * The {@code Vector} class implements a growable array of
+ * objects. Like an array, it contains components that can be
+ * accessed using an integer index. However, the size of a
+ * {@code Vector} can grow or shrink as needed to accommodate
+ * adding and removing items after the {@code Vector} has been created.
+ *
+ * <p>Each vector tries to optimize storage management by maintaining a
+ * {@code capacity} and a {@code capacityIncrement}. The
+ * {@code capacity} is always at least as large as the vector
+ * size; it is usually larger because as components are added to the
+ * vector, the vector's storage increases in chunks the size of
+ * {@code capacityIncrement}. An application can increase the
+ * capacity of a vector before inserting a large number of
+ * components; this reduces the amount of incremental reallocation.
+ *
+ * <p><a name="fail-fast">
+ * The iterators returned by this class's {@link #iterator() iterator} and
+ * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em></a>:
+ * if the vector is structurally modified at any time after the iterator is
+ * created, in any way except through the iterator's own
+ * {@link ListIterator#remove() remove} or
+ * {@link ListIterator#add(Object) 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
+ * time in the future.  The {@link Enumeration Enumerations} returned by
+ * the {@link #elements() elements} method are <em>not</em> fail-fast.
+ *
+ * <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 {@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>
+ *
+ * <p>As of the Java 2 platform v1.2, this class was retrofitted to
+ * implement the {@link List} interface, making it a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.  Unlike the new collection
+ * implementations, {@code Vector} is synchronized.  If a thread-safe
+ * implementation is not needed, it is recommended to use {@link
+ * ArrayList} in place of {@code Vector}.
+ *
+ * @author  Lee Boynton
+ * @author  Jonathan Payne
+ * @see Collection
+ * @see LinkedList
+ * @since   JDK1.0
+ */
+public class Vector<E>
+    extends AbstractList<E>
+    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
+{
+    /**
+     * The array buffer into which the components of the vector are
+     * stored. The capacity of the vector is the length of this array buffer,
+     * and is at least large enough to contain all the vector's elements.
+     *
+     * <p>Any array elements following the last element in the Vector are null.
+     *
+     * @serial
+     */
+    protected Object[] elementData;
+
+    /**
+     * The number of valid components in this {@code Vector} object.
+     * Components {@code elementData[0]} through
+     * {@code elementData[elementCount-1]} are the actual items.
+     *
+     * @serial
+     */
+    protected int elementCount;
+
+    /**
+     * The amount by which the capacity of the vector is automatically
+     * incremented when its size becomes greater than its capacity.  If
+     * the capacity increment is less than or equal to zero, the capacity
+     * of the vector is doubled each time it needs to grow.
+     *
+     * @serial
+     */
+    protected int capacityIncrement;
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = -2767605614048989439L;
+
+    /**
+     * Constructs an empty vector with the specified initial capacity and
+     * capacity increment.
+     *
+     * @param   initialCapacity     the initial capacity of the vector
+     * @param   capacityIncrement   the amount by which the capacity is
+     *                              increased when the vector overflows
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    public Vector(int initialCapacity, int capacityIncrement) {
+        super();
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Capacity: "+
+                                               initialCapacity);
+        this.elementData = new Object[initialCapacity];
+        this.capacityIncrement = capacityIncrement;
+    }
+
+    /**
+     * Constructs an empty vector with the specified initial capacity and
+     * with its capacity increment equal to zero.
+     *
+     * @param   initialCapacity   the initial capacity of the vector
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    public Vector(int initialCapacity) {
+        this(initialCapacity, 0);
+    }
+
+    /**
+     * Constructs an empty vector so that its internal data array
+     * has size {@code 10} and its standard capacity increment is
+     * zero.
+     */
+    public Vector() {
+        this(10);
+    }
+
+    /**
+     * Constructs a vector containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param c the collection whose elements are to be placed into this
+     *       vector
+     * @throws NullPointerException if the specified collection is null
+     * @since   1.2
+     */
+    public Vector(Collection<? extends E> c) {
+        elementData = c.toArray();
+        elementCount = elementData.length;
+        // c.toArray might (incorrectly) not return Object[] (see 6260652)
+        if (elementData.getClass() != Object[].class)
+            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
+    }
+
+    /**
+     * Copies the components of this vector into the specified array.
+     * The item at index {@code k} in this vector is copied into
+     * component {@code k} of {@code anArray}.
+     *
+     * @param  anArray the array into which the components get copied
+     * @throws NullPointerException if the given array is null
+     * @throws IndexOutOfBoundsException if the specified array is not
+     *         large enough to hold all the components of this vector
+     * @throws ArrayStoreException if a component of this vector is not of
+     *         a runtime type that can be stored in the specified array
+     * @see #toArray(Object[])
+     */
+    public synchronized void copyInto(Object[] anArray) {
+        System.arraycopy(elementData, 0, anArray, 0, elementCount);
+    }
+
+    /**
+     * Trims the capacity of this vector to be the vector's current
+     * size. If the capacity of this vector is larger than its current
+     * size, then the capacity is changed to equal the size by replacing
+     * its internal data array, kept in the field {@code elementData},
+     * with a smaller one. An application can use this operation to
+     * minimize the storage of a vector.
+     */
+    public synchronized void trimToSize() {
+        modCount++;
+        int oldCapacity = elementData.length;
+        if (elementCount < oldCapacity) {
+            elementData = Arrays.copyOf(elementData, elementCount);
+        }
+    }
+
+    /**
+     * Increases the capacity of this vector, if necessary, to ensure
+     * that it can hold at least the number of components specified by
+     * the minimum capacity argument.
+     *
+     * <p>If the current capacity of this vector is less than
+     * {@code minCapacity}, then its capacity is increased by replacing its
+     * internal data array, kept in the field {@code elementData}, with a
+     * larger one.  The size of the new data array will be the old size plus
+     * {@code capacityIncrement}, unless the value of
+     * {@code capacityIncrement} is less than or equal to zero, in which case
+     * the new capacity will be twice the old capacity; but if this new size
+     * is still smaller than {@code minCapacity}, then the new capacity will
+     * be {@code minCapacity}.
+     *
+     * @param minCapacity the desired minimum capacity
+     */
+    public synchronized void ensureCapacity(int minCapacity) {
+        if (minCapacity > 0) {
+            modCount++;
+            ensureCapacityHelper(minCapacity);
+        }
+    }
+
+    /**
+     * This implements the unsynchronized semantics of ensureCapacity.
+     * Synchronized methods in this class can internally call this
+     * method for ensuring capacity without incurring the cost of an
+     * extra synchronization.
+     *
+     * @see #ensureCapacity(int)
+     */
+    private void ensureCapacityHelper(int minCapacity) {
+        // overflow-conscious code
+        if (minCapacity - elementData.length > 0)
+            grow(minCapacity);
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    private void grow(int minCapacity) {
+        // overflow-conscious code
+        int oldCapacity = elementData.length;
+        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
+                                         capacityIncrement : oldCapacity);
+        if (newCapacity - minCapacity < 0)
+            newCapacity = minCapacity;
+        if (newCapacity - MAX_ARRAY_SIZE > 0)
+            newCapacity = hugeCapacity(minCapacity);
+        elementData = Arrays.copyOf(elementData, newCapacity);
+    }
+
+    private static int hugeCapacity(int minCapacity) {
+        if (minCapacity < 0) // overflow
+            throw new OutOfMemoryError();
+        return (minCapacity > MAX_ARRAY_SIZE) ?
+            Integer.MAX_VALUE :
+            MAX_ARRAY_SIZE;
+    }
+
+    /**
+     * Sets the size of this vector. If the new size is greater than the
+     * current size, new {@code null} items are added to the end of
+     * the vector. If the new size is less than the current size, all
+     * components at index {@code newSize} and greater are discarded.
+     *
+     * @param  newSize   the new size of this vector
+     * @throws ArrayIndexOutOfBoundsException if the new size is negative
+     */
+    public synchronized void setSize(int newSize) {
+        modCount++;
+        if (newSize > elementCount) {
+            ensureCapacityHelper(newSize);
+        } else {
+            for (int i = newSize ; i < elementCount ; i++) {
+                elementData[i] = null;
+            }
+        }
+        elementCount = newSize;
+    }
+
+    /**
+     * Returns the current capacity of this vector.
+     *
+     * @return  the current capacity (the length of its internal
+     *          data array, kept in the field {@code elementData}
+     *          of this vector)
+     */
+    public synchronized int capacity() {
+        return elementData.length;
+    }
+
+    /**
+     * Returns the number of components in this vector.
+     *
+     * @return  the number of components in this vector
+     */
+    public synchronized int size() {
+        return elementCount;
+    }
+
+    /**
+     * Tests if this vector has no components.
+     *
+     * @return  {@code true} if and only if this vector has
+     *          no components, that is, its size is zero;
+     *          {@code false} otherwise.
+     */
+    public synchronized boolean isEmpty() {
+        return elementCount == 0;
+    }
+
+    /**
+     * Returns an enumeration of the components of this vector. The
+     * returned {@code Enumeration} object will generate all items in
+     * this vector. The first item generated is the item at index {@code 0},
+     * then the item at index {@code 1}, and so on.
+     *
+     * @return  an enumeration of the components of this vector
+     * @see     Iterator
+     */
+    public Enumeration<E> elements() {
+        return new Enumeration<E>() {
+            int count = 0;
+
+            public boolean hasMoreElements() {
+                return count < elementCount;
+            }
+
+            public E nextElement() {
+                synchronized (Vector.this) {
+                    if (count < elementCount) {
+                        return elementData(count++);
+                    }
+                }
+                throw new NoSuchElementException("Vector Enumeration");
+            }
+        };
+    }
+
+    /**
+     * Returns {@code true} if this vector contains the specified element.
+     * More formally, returns {@code true} if and only if this vector
+     * 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 vector is to be tested
+     * @return {@code true} if this vector contains the specified element
+     */
+    public boolean contains(Object o) {
+        return indexOf(o, 0) >= 0;
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element
+     * in this vector, or -1 if this vector does not contain the element.
+     * 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.
+     *
+     * @param o element to search for
+     * @return the index of the first occurrence of the specified element in
+     *         this vector, or -1 if this vector does not contain the element
+     */
+    public int indexOf(Object o) {
+        return indexOf(o, 0);
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element in
+     * this vector, searching forwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the lowest index {@code i} such that
+     * <tt>(i&nbsp;&gt;=&nbsp;index&nbsp;&amp;&amp;&nbsp;(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i))))</tt>,
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @param index index to start searching from
+     * @return the index of the first occurrence of the element in
+     *         this vector at position {@code index} or later in the vector;
+     *         {@code -1} if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @see     Object#equals(Object)
+     */
+    public synchronized int indexOf(Object o, int index) {
+        if (o == null) {
+            for (int i = index ; i < elementCount ; i++)
+                if (elementData[i]==null)
+                    return i;
+        } else {
+            for (int i = index ; i < elementCount ; i++)
+                if (o.equals(elementData[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element
+     * in this vector, or -1 if this vector does not contain the element.
+     * 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.
+     *
+     * @param o element to search for
+     * @return the index of the last occurrence of the specified element in
+     *         this vector, or -1 if this vector does not contain the element
+     */
+    public synchronized int lastIndexOf(Object o) {
+        return lastIndexOf(o, elementCount-1);
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element in
+     * this vector, searching backwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the highest index {@code i} such that
+     * <tt>(i&nbsp;&lt;=&nbsp;index&nbsp;&amp;&amp;&nbsp;(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i))))</tt>,
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @param index index to start searching backwards from
+     * @return the index of the last occurrence of the element at position
+     *         less than or equal to {@code index} in this vector;
+     *         -1 if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is greater
+     *         than or equal to the current size of this vector
+     */
+    public synchronized int lastIndexOf(Object o, int index) {
+        if (index >= elementCount)
+            throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
+
+        if (o == null) {
+            for (int i = index; i >= 0; i--)
+                if (elementData[i]==null)
+                    return i;
+        } else {
+            for (int i = index; i >= 0; i--)
+                if (o.equals(elementData[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the component at the specified index.
+     *
+     * <p>This method is identical in functionality to the {@link #get(int)}
+     * method (which is part of the {@link List} interface).
+     *
+     * @param      index   an index into this vector
+     * @return     the component at the specified index
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    public synchronized E elementAt(int index) {
+        if (index >= elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
+        }
+
+        return elementData(index);
+    }
+
+    /**
+     * Returns the first component (the item at index {@code 0}) of
+     * this vector.
+     *
+     * @return     the first component of this vector
+     * @throws NoSuchElementException if this vector has no components
+     */
+    public synchronized E firstElement() {
+        if (elementCount == 0) {
+            throw new NoSuchElementException();
+        }
+        return elementData(0);
+    }
+
+    /**
+     * Returns the last component of the vector.
+     *
+     * @return  the last component of the vector, i.e., the component at index
+     *          <code>size()&nbsp;-&nbsp;1</code>.
+     * @throws NoSuchElementException if this vector is empty
+     */
+    public synchronized E lastElement() {
+        if (elementCount == 0) {
+            throw new NoSuchElementException();
+        }
+        return elementData(elementCount - 1);
+    }
+
+    /**
+     * Sets the component at the specified {@code index} of this
+     * vector to be the specified object. The previous component at that
+     * position is discarded.
+     *
+     * <p>The index must be a value greater than or equal to {@code 0}
+     * and less than the current size of the vector.
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #set(int, Object) set(int, E)}
+     * method (which is part of the {@link List} interface). Note that the
+     * {@code set} method reverses the order of the parameters, to more closely
+     * match array usage.  Note also that the {@code set} method returns the
+     * old value that was stored at the specified position.
+     *
+     * @param      obj     what the component is to be set to
+     * @param      index   the specified index
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    public synchronized void setElementAt(E obj, int index) {
+        if (index >= elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index + " >= " +
+                                                     elementCount);
+        }
+        elementData[index] = obj;
+    }
+
+    /**
+     * Deletes the component at the specified index. Each component in
+     * this vector with an index greater or equal to the specified
+     * {@code index} is shifted downward to have an index one
+     * smaller than the value it had previously. The size of this vector
+     * is decreased by {@code 1}.
+     *
+     * <p>The index must be a value greater than or equal to {@code 0}
+     * and less than the current size of the vector.
+     *
+     * <p>This method is identical in functionality to the {@link #remove(int)}
+     * method (which is part of the {@link List} interface).  Note that the
+     * {@code remove} method returns the old value that was stored at the
+     * specified position.
+     *
+     * @param      index   the index of the object to remove
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    public synchronized void removeElementAt(int index) {
+        modCount++;
+        if (index >= elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index + " >= " +
+                                                     elementCount);
+        }
+        else if (index < 0) {
+            throw new ArrayIndexOutOfBoundsException(index);
+        }
+        int j = elementCount - index - 1;
+        if (j > 0) {
+            System.arraycopy(elementData, index + 1, elementData, index, j);
+        }
+        elementCount--;
+        elementData[elementCount] = null; /* to let gc do its work */
+    }
+
+    /**
+     * Inserts the specified object as a component in this vector at the
+     * specified {@code index}. Each component in this vector with
+     * an index greater or equal to the specified {@code index} is
+     * shifted upward to have an index one greater than the value it had
+     * previously.
+     *
+     * <p>The index must be a value greater than or equal to {@code 0}
+     * and less than or equal to the current size of the vector. (If the
+     * index is equal to the current size of the vector, the new element
+     * is appended to the Vector.)
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #add(int, Object) add(int, E)}
+     * method (which is part of the {@link List} interface).  Note that the
+     * {@code add} method reverses the order of the parameters, to more closely
+     * match array usage.
+     *
+     * @param      obj     the component to insert
+     * @param      index   where to insert the new component
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    public synchronized void insertElementAt(E obj, int index) {
+        modCount++;
+        if (index > elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index
+                                                     + " > " + elementCount);
+        }
+        ensureCapacityHelper(elementCount + 1);
+        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
+        elementData[index] = obj;
+        elementCount++;
+    }
+
+    /**
+     * Adds the specified component to the end of this vector,
+     * increasing its size by one. The capacity of this vector is
+     * increased if its size becomes greater than its capacity.
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #add(Object) add(E)}
+     * method (which is part of the {@link List} interface).
+     *
+     * @param   obj   the component to be added
+     */
+    public synchronized void addElement(E obj) {
+        modCount++;
+        ensureCapacityHelper(elementCount + 1);
+        elementData[elementCount++] = obj;
+    }
+
+    /**
+     * Removes the first (lowest-indexed) occurrence of the argument
+     * from this vector. If the object is found in this vector, each
+     * component in the vector with an index greater or equal to the
+     * object's index is shifted downward to have an index one smaller
+     * than the value it had previously.
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #remove(Object)} method (which is part of the
+     * {@link List} interface).
+     *
+     * @param   obj   the component to be removed
+     * @return  {@code true} if the argument was a component of this
+     *          vector; {@code false} otherwise.
+     */
+    public synchronized boolean removeElement(Object obj) {
+        modCount++;
+        int i = indexOf(obj);
+        if (i >= 0) {
+            removeElementAt(i);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Removes all components from this vector and sets its size to zero.
+     *
+     * <p>This method is identical in functionality to the {@link #clear}
+     * method (which is part of the {@link List} interface).
+     */
+    public synchronized void removeAllElements() {
+        modCount++;
+        // Let gc do its work
+        for (int i = 0; i < elementCount; i++)
+            elementData[i] = null;
+
+        elementCount = 0;
+    }
+
+    /**
+     * Returns a clone of this vector. The copy will contain a
+     * reference to a clone of the internal data array, not a reference
+     * to the original internal data array of this {@code Vector} object.
+     *
+     * @return  a clone of this vector
+     */
+    public synchronized Object clone() {
+        try {
+            @SuppressWarnings("unchecked")
+                Vector<E> v = (Vector<E>) super.clone();
+            v.elementData = Arrays.copyOf(elementData, elementCount);
+            v.modCount = 0;
+            return v;
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this Vector
+     * in the correct order.
+     *
+     * @since 1.2
+     */
+    public synchronized Object[] toArray() {
+        return Arrays.copyOf(elementData, elementCount);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this Vector in the
+     * correct order; the runtime type of the returned array is that of the
+     * specified array.  If the Vector fits in the specified array, it is
+     * returned therein.  Otherwise, a new array is allocated with the runtime
+     * type of the specified array and the size of this Vector.
+     *
+     * <p>If the Vector fits in the specified array with room to spare
+     * (i.e., the array has more elements than the Vector),
+     * the element in the array immediately following the end of the
+     * Vector is set to null.  (This is useful in determining the length
+     * of the Vector <em>only</em> if the caller knows that the Vector
+     * does not contain any null elements.)
+     *
+     * @param a the array into which the elements of the Vector are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of the Vector
+     * @throws ArrayStoreException if the runtime type of a is not a supertype
+     * of the runtime type of every element in this Vector
+     * @throws NullPointerException if the given array is null
+     * @since 1.2
+     */
+    @SuppressWarnings("unchecked")
+    public synchronized <T> T[] toArray(T[] a) {
+        if (a.length < elementCount)
+            return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());
+
+        System.arraycopy(elementData, 0, a, 0, elementCount);
+
+        if (a.length > elementCount)
+            a[elementCount] = null;
+
+        return a;
+    }
+
+    // Positional Access Operations
+
+    @SuppressWarnings("unchecked")
+    E elementData(int index) {
+        return (E) elementData[index];
+    }
+
+    /**
+     * Returns the element at the specified position in this Vector.
+     *
+     * @param index index of the element to return
+     * @return object at the specified index
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *            ({@code index < 0 || index >= size()})
+     * @since 1.2
+     */
+    public synchronized E get(int index) {
+        if (index >= elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+
+        return elementData(index);
+    }
+
+    /**
+     * Replaces the element at the specified position in this Vector with the
+     * specified element.
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     * @since 1.2
+     */
+    public synchronized E set(int index, E element) {
+        if (index >= elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+
+        E oldValue = elementData(index);
+        elementData[index] = element;
+        return oldValue;
+    }
+
+    /**
+     * Appends the specified element to the end of this Vector.
+     *
+     * @param e element to be appended to this Vector
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @since 1.2
+     */
+    public synchronized boolean add(E e) {
+        modCount++;
+        ensureCapacityHelper(elementCount + 1);
+        elementData[elementCount++] = e;
+        return true;
+    }
+
+    /**
+     * Removes the first occurrence of the specified element in this Vector
+     * If the Vector does not contain the element, it is unchanged.  More
+     * formally, removes the element with the lowest index i such that
+     * {@code (o==null ? get(i)==null : o.equals(get(i)))} (if such
+     * an element exists).
+     *
+     * @param o element to be removed from this Vector, if present
+     * @return true if the Vector contained the specified element
+     * @since 1.2
+     */
+    public boolean remove(Object o) {
+        return removeElement(o);
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this Vector.
+     * Shifts the element currently at that position (if any) and any
+     * subsequent elements to the right (adds one to their indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     * @since 1.2
+     */
+    public void add(int index, E element) {
+        insertElementAt(element, index);
+    }
+
+    /**
+     * Removes the element at the specified position in this Vector.
+     * Shifts any subsequent elements to the left (subtracts one from their
+     * indices).  Returns the element that was removed from the Vector.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     * @param index the index of the element to be removed
+     * @return element that was removed
+     * @since 1.2
+     */
+    public synchronized E remove(int index) {
+        modCount++;
+        if (index >= elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+        E oldValue = elementData(index);
+
+        int numMoved = elementCount - index - 1;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index+1, elementData, index,
+                             numMoved);
+        elementData[--elementCount] = null; // Let gc do its work
+
+        return oldValue;
+    }
+
+    /**
+     * Removes all of the elements from this Vector.  The Vector will
+     * be empty after this call returns (unless it throws an exception).
+     *
+     * @since 1.2
+     */
+    public void clear() {
+        removeAllElements();
+    }
+
+    // Bulk Operations
+
+    /**
+     * Returns true if this Vector contains all of the elements in the
+     * specified Collection.
+     *
+     * @param   c a collection whose elements will be tested for containment
+     *          in this Vector
+     * @return true if this Vector contains all of the elements in the
+     *         specified collection
+     * @throws NullPointerException if the specified collection is null
+     */
+    public synchronized boolean containsAll(Collection<?> c) {
+        return super.containsAll(c);
+    }
+
+    /**
+     * Appends all of the elements in the specified Collection to the end of
+     * this Vector, in the order that they are returned by the specified
+     * Collection's Iterator.  The behavior of this operation is undefined if
+     * the specified Collection is modified while the operation is in progress.
+     * (This implies that the behavior of this call is undefined if the
+     * specified Collection is this Vector, and this Vector is nonempty.)
+     *
+     * @param c elements to be inserted into this Vector
+     * @return {@code true} if this Vector changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     * @since 1.2
+     */
+    public synchronized boolean addAll(Collection<? extends E> c) {
+        modCount++;
+        Object[] a = c.toArray();
+        int numNew = a.length;
+        ensureCapacityHelper(elementCount + numNew);
+        System.arraycopy(a, 0, elementData, elementCount, numNew);
+        elementCount += numNew;
+        return numNew != 0;
+    }
+
+    /**
+     * Removes from this Vector all of its elements that are contained in the
+     * specified Collection.
+     *
+     * @param c a collection of elements to be removed from the Vector
+     * @return true if this Vector changed as a result of the call
+     * @throws ClassCastException if the types of one or more elements
+     *         in this vector are incompatible with the specified
+     *         collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this vector contains one or more null
+     *         elements and the specified collection does not support null
+     *         elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @since 1.2
+     */
+    public synchronized boolean removeAll(Collection<?> c) {
+        return super.removeAll(c);
+    }
+
+    /**
+     * Retains only the elements in this Vector that are contained in the
+     * specified Collection.  In other words, removes from this Vector all
+     * of its elements that are not contained in the specified Collection.
+     *
+     * @param c a collection of elements to be retained in this Vector
+     *          (all other elements are removed)
+     * @return true if this Vector changed as a result of the call
+     * @throws ClassCastException if the types of one or more elements
+     *         in this vector are incompatible with the specified
+     *         collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this vector contains one or more null
+     *         elements and the specified collection does not support null
+     *         elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @since 1.2
+     */
+    public synchronized boolean retainAll(Collection<?> c) {
+        return super.retainAll(c);
+    }
+
+    /**
+     * Inserts all of the elements in the specified Collection into this
+     * Vector at the specified position.  Shifts the element currently at
+     * that position (if any) and any subsequent elements to the right
+     * (increases their indices).  The new elements will appear in the Vector
+     * in the order that they are returned by the specified Collection's
+     * iterator.
+     *
+     * @param index index at which to insert the first element from the
+     *              specified collection
+     * @param c elements to be inserted into this Vector
+     * @return {@code true} if this Vector changed as a result of the call
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     * @throws NullPointerException if the specified collection is null
+     * @since 1.2
+     */
+    public synchronized boolean addAll(int index, Collection<? extends E> c) {
+        modCount++;
+        if (index < 0 || index > elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+
+        Object[] a = c.toArray();
+        int numNew = a.length;
+        ensureCapacityHelper(elementCount + numNew);
+
+        int numMoved = elementCount - index;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index, elementData, index + numNew,
+                             numMoved);
+
+        System.arraycopy(a, 0, elementData, index, numNew);
+        elementCount += numNew;
+        return numNew != 0;
+    }
+
+    /**
+     * Compares the specified Object with this Vector for equality.  Returns
+     * true if and only if the specified Object is also a List, both Lists
+     * have the same size, and all corresponding pairs of elements in the two
+     * Lists are <em>equal</em>.  (Two elements {@code e1} and
+     * {@code e2} are <em>equal</em> if {@code (e1==null ? e2==null :
+     * e1.equals(e2))}.)  In other words, two Lists are defined to be
+     * equal if they contain the same elements in the same order.
+     *
+     * @param o the Object to be compared for equality with this Vector
+     * @return true if the specified Object is equal to this Vector
+     */
+    public synchronized boolean equals(Object o) {
+        return super.equals(o);
+    }
+
+    /**
+     * Returns the hash code value for this Vector.
+     */
+    public synchronized int hashCode() {
+        return super.hashCode();
+    }
+
+    /**
+     * Returns a string representation of this Vector, containing
+     * the String representation of each element.
+     */
+    public synchronized String toString() {
+        return super.toString();
+    }
+
+    /**
+     * Returns a view of the portion of this List between fromIndex,
+     * inclusive, and toIndex, exclusive.  (If fromIndex and toIndex are
+     * equal, the returned List is empty.)  The returned List is backed by this
+     * List, so changes in the returned List are reflected in this List, and
+     * vice-versa.  The returned List supports all of the optional List
+     * operations supported by this List.
+     *
+     * <p>This method eliminates the need for explicit range operations (of
+     * the sort that commonly exist for arrays).  Any operation that expects
+     * a List can be used as a range operation by operating on a subList view
+     * instead of a whole List.  For example, the following idiom
+     * removes a range of elements from a List:
+     * <pre>
+     *      list.subList(from, to).clear();
+     * </pre>
+     * Similar idioms may be constructed for indexOf and lastIndexOf,
+     * and all of the algorithms in the Collections class can be applied to
+     * a subList.
+     *
+     * <p>The semantics of the List returned by this method become undefined if
+     * the backing list (i.e., this List) is <i>structurally modified</i> in
+     * any way other than via the returned List.  (Structural modifications are
+     * those that change the size of the List, or otherwise perturb it in such
+     * a fashion that iterations in progress may yield incorrect results.)
+     *
+     * @param fromIndex low endpoint (inclusive) of the subList
+     * @param toIndex high endpoint (exclusive) of the subList
+     * @return a view of the specified range within this List
+     * @throws IndexOutOfBoundsException if an endpoint index value is out of range
+     *         {@code (fromIndex < 0 || toIndex > size)}
+     * @throws IllegalArgumentException if the endpoint indices are out of order
+     *         {@code (fromIndex > toIndex)}
+     */
+    public synchronized List<E> subList(int fromIndex, int toIndex) {
+        return Collections.synchronizedList(super.subList(fromIndex, toIndex),
+                                            this);
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     */
+    protected synchronized void removeRange(int fromIndex, int toIndex) {
+        modCount++;
+        int numMoved = elementCount - toIndex;
+        System.arraycopy(elementData, toIndex, elementData, fromIndex,
+                         numMoved);
+
+        // Let gc do its work
+        int newElementCount = elementCount - (toIndex-fromIndex);
+        while (elementCount != newElementCount)
+            elementData[--elementCount] = null;
+    }
+
+    /**
+     * Save the state of the {@code Vector} instance to a stream (that
+     * is, serialize it).
+     * This method performs synchronization to ensure the consistency
+     * of the serialized data.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+            throws java.io.IOException {
+        final java.io.ObjectOutputStream.PutField fields = s.putFields();
+        final Object[] data;
+        synchronized (this) {
+            fields.put("capacityIncrement", capacityIncrement);
+            fields.put("elementCount", elementCount);
+            data = elementData.clone();
+        }
+        fields.put("elementData", data);
+        s.writeFields();
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence), starting at the specified position in the list.
+     * The specified index indicates the first element that would be
+     * returned by an initial call to {@link ListIterator#next next}.
+     * An initial call to {@link ListIterator#previous previous} would
+     * return the element with the specified index minus one.
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public synchronized ListIterator<E> listIterator(int index) {
+        if (index < 0 || index > elementCount)
+            throw new IndexOutOfBoundsException("Index: "+index);
+        return new ListItr(index);
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @see #listIterator(int)
+     */
+    public synchronized ListIterator<E> listIterator() {
+        return new ListItr(0);
+    }
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public synchronized Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * An optimized version of AbstractList.Itr
+     */
+    private class Itr implements Iterator<E> {
+        // Android-added: Change CME behavior: Use added limit field, not elementCount.
+        // http://b/27430229 AOSP commit 6e5b758a4438d2c154dd11a5c04d14a5d2fc907c
+        //
+        // The "limit" of this iterator. This is the size of the list at the time the
+        // iterator was created. Adding & removing elements will invalidate the iteration
+        // anyway (and cause next() to throw) so saving this value will guarantee that the
+        // value of hasNext() remains stable and won't flap between true and false when elements
+        // are added and removed from the list.
+        protected int limit = Vector.this.elementCount;
+
+        int cursor;       // index of next element to return
+        int lastRet = -1; // index of last element returned; -1 if no such
+        int expectedModCount = modCount;
+
+        public boolean hasNext() {
+            // Android-changed: Change CME behavior: Use added limit field, not elementCount.
+            // return cursor != elementCount;
+            return cursor < limit;
+        }
+
+        public E next() {
+            synchronized (Vector.this) {
+                checkForComodification();
+                int i = cursor;
+                // Android-changed: Change CME behavior: Use added limit field, not elementCount.
+                // if (i >= elementCount)
+                if (i >= limit)
+                    throw new NoSuchElementException();
+                cursor = i + 1;
+                return elementData(lastRet = i);
+            }
+        }
+
+        public void remove() {
+            if (lastRet == -1)
+                throw new IllegalStateException();
+            synchronized (Vector.this) {
+                checkForComodification();
+                Vector.this.remove(lastRet);
+                expectedModCount = modCount;
+                // Android-added: Change CME behavior: Use added limit field, not elementCount.
+                limit--;
+            }
+            cursor = lastRet;
+            lastRet = -1;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            synchronized (Vector.this) {
+                // Android-changed: Change CME behavior: Use added limit field, not elementCount.
+                // final int size = elementCount;
+                final int size = limit;
+                int i = cursor;
+                if (i >= size) {
+                    return;
+                }
+        @SuppressWarnings("unchecked")
+                final E[] elementData = (E[]) Vector.this.elementData;
+                if (i >= elementData.length) {
+                    throw new ConcurrentModificationException();
+                }
+                while (i != size && modCount == expectedModCount) {
+                    action.accept(elementData[i++]);
+                }
+                // update once at end of iteration to reduce heap write traffic
+                cursor = i;
+                lastRet = i - 1;
+                checkForComodification();
+            }
+        }
+
+        final void checkForComodification() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * An optimized version of AbstractList.ListItr
+     */
+    final class ListItr extends Itr implements ListIterator<E> {
+        ListItr(int index) {
+            super();
+            cursor = index;
+        }
+
+        public boolean hasPrevious() {
+            return cursor != 0;
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor - 1;
+        }
+
+        public E previous() {
+            synchronized (Vector.this) {
+                checkForComodification();
+                int i = cursor - 1;
+                if (i < 0)
+                    throw new NoSuchElementException();
+                cursor = i;
+                return elementData(lastRet = i);
+            }
+        }
+
+        public void set(E e) {
+            if (lastRet == -1)
+                throw new IllegalStateException();
+            synchronized (Vector.this) {
+                checkForComodification();
+                Vector.this.set(lastRet, e);
+            }
+        }
+
+        public void add(E e) {
+            int i = cursor;
+            synchronized (Vector.this) {
+                checkForComodification();
+                Vector.this.add(i, e);
+                expectedModCount = modCount;
+                // Android-added: Change CME behavior: Use added limit field, not elementCount.
+                limit++;
+            }
+            cursor = i + 1;
+            lastRet = -1;
+        }
+    }
+
+    @Override
+    public synchronized void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final int expectedModCount = modCount;
+        @SuppressWarnings("unchecked")
+        final E[] elementData = (E[]) this.elementData;
+        final int elementCount = this.elementCount;
+        for (int i=0; modCount == expectedModCount && i < elementCount; i++) {
+            action.accept(elementData[i]);
+        }
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public synchronized boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        // figure out which elements are to be removed
+        // any exception thrown from the filter predicate at this stage
+        // will leave the collection unmodified
+        int removeCount = 0;
+        final int size = elementCount;
+        final BitSet removeSet = new BitSet(size);
+        final int expectedModCount = modCount;
+        for (int i=0; modCount == expectedModCount && i < size; i++) {
+            @SuppressWarnings("unchecked")
+            final E element = (E) elementData[i];
+            if (filter.test(element)) {
+                removeSet.set(i);
+                removeCount++;
+            }
+        }
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+
+        // shift surviving elements left over the spaces left by removed elements
+        final boolean anyToRemove = removeCount > 0;
+        if (anyToRemove) {
+            final int newSize = size - removeCount;
+            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
+                i = removeSet.nextClearBit(i);
+                elementData[j] = elementData[i];
+            }
+            for (int k=newSize; k < size; k++) {
+                elementData[k] = null;  // Let gc do its work
+            }
+            elementCount = newSize;
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+            modCount++;
+        }
+
+        return anyToRemove;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public synchronized void replaceAll(UnaryOperator<E> operator) {
+        Objects.requireNonNull(operator);
+        final int expectedModCount = modCount;
+        final int size = elementCount;
+        for (int i=0; modCount == expectedModCount && i < size; i++) {
+            elementData[i] = operator.apply((E) elementData[i]);
+        }
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+        modCount++;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized void sort(Comparator<? super E> c) {
+        final int expectedModCount = modCount;
+        Arrays.sort((E[]) elementData, 0, elementCount, c);
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+        modCount++;
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new VectorSpliterator<>(this, null, 0, -1, 0);
+    }
+
+    /** Similar to ArrayList Spliterator */
+    static final class VectorSpliterator<E> implements Spliterator<E> {
+        private final Vector<E> list;
+        private Object[] array;
+        private int index; // current index, modified on advance/split
+        private int fence; // -1 until used; then one past last index
+        private int expectedModCount; // initialized when fence set
+
+        /** Create new spliterator covering the given  range */
+        VectorSpliterator(Vector<E> list, Object[] array, int origin, int fence,
+                          int expectedModCount) {
+            this.list = list;
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.expectedModCount = expectedModCount;
+        }
+
+        private int getFence() { // initialize on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                synchronized(list) {
+                    array = list.elementData;
+                    expectedModCount = list.modCount;
+                    hi = fence = list.elementCount;
+                }
+            }
+            return hi;
+        }
+
+        public Spliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new VectorSpliterator<E>(list, array, lo, index = mid,
+                                         expectedModCount);
+        }
+
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super E> action) {
+            int i;
+            if (action == null)
+                throw new NullPointerException();
+            if (getFence() > (i = index)) {
+                index = i + 1;
+                action.accept((E)array[i]);
+                if (list.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                return true;
+            }
+            return false;
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            int i, hi; // hoist accesses and checks from loop
+            Vector<E> lst; Object[] a;
+            if (action == null)
+                throw new NullPointerException();
+            if ((lst = list) != null) {
+                if ((hi = fence) < 0) {
+                    synchronized(lst) {
+                        expectedModCount = lst.modCount;
+                        a = array = lst.elementData;
+                        hi = fence = lst.elementCount;
+                    }
+                }
+                else
+                    a = array;
+                if (a != null && (i = index) >= 0 && (index = hi) <= a.length) {
+                    while (i < hi)
+                        action.accept((E) a[i++]);
+                    if (lst.modCount == expectedModCount)
+                        return;
+                }
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public long estimateSize() {
+            return (long) (getFence() - index);
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+    }
+}
diff --git a/java/util/WeakHashMap.annotated.java b/java/util/WeakHashMap.annotated.java
new file mode 100644
index 0000000..83ae1cb
--- /dev/null
+++ b/java/util/WeakHashMap.annotated.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.lang.ref.WeakReference;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class WeakHashMap<K, V> extends java.util.AbstractMap<K,V> implements java.util.Map<K,V> {
+
+public WeakHashMap(int initialCapacity, float loadFactor) { throw new RuntimeException("Stub!"); }
+
+public WeakHashMap(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+public WeakHashMap() { throw new RuntimeException("Stub!"); }
+
+public WeakHashMap(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
[email protected] public V get(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public boolean containsKey(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
[email protected] public V put(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public V remove(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public boolean containsValue(@libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet() { throw new RuntimeException("Stub!"); }
+
+public void forEach(@libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V> action) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(@libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V,? extends @libcore.util.NullFromTypeParam V> function) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/WeakHashMap.java b/java/util/WeakHashMap.java
new file mode 100644
index 0000000..7352391
--- /dev/null
+++ b/java/util/WeakHashMap.java
@@ -0,0 +1,1339 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
+
+/**
+ * Hash table based implementation of the <tt>Map</tt> interface, with
+ * <em>weak keys</em>.
+ * An entry in a <tt>WeakHashMap</tt> will automatically be removed when
+ * its key is no longer in ordinary use.  More precisely, the presence of a
+ * mapping for a given key will not prevent the key from being discarded by the
+ * garbage collector, that is, made finalizable, finalized, and then reclaimed.
+ * When a key has been discarded its entry is effectively removed from the map,
+ * so this class behaves somewhat differently from other <tt>Map</tt>
+ * implementations.
+ *
+ * <p> Both null values and the null key are supported. This class has
+ * performance characteristics similar to those of the <tt>HashMap</tt>
+ * class, and has the same efficiency parameters of <em>initial capacity</em>
+ * and <em>load factor</em>.
+ *
+ * <p> Like most collection classes, this class is not synchronized.
+ * A synchronized <tt>WeakHashMap</tt> may be constructed using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.
+ *
+ * <p> This class is intended primarily for use with key objects whose
+ * <tt>equals</tt> methods test for object identity using the
+ * <tt>==</tt> operator.  Once such a key is discarded it can never be
+ * recreated, so it is impossible to do a lookup of that key in a
+ * <tt>WeakHashMap</tt> at some later time and be surprised that its entry
+ * has been removed.  This class will work perfectly well with key objects
+ * whose <tt>equals</tt> methods are not based upon object identity, such
+ * as <tt>String</tt> instances.  With such recreatable key objects,
+ * however, the automatic removal of <tt>WeakHashMap</tt> entries whose
+ * keys have been discarded may prove to be confusing.
+ *
+ * <p> The behavior of the <tt>WeakHashMap</tt> class depends in part upon
+ * the actions of the garbage collector, so several familiar (though not
+ * required) <tt>Map</tt> invariants do not hold for this class.  Because
+ * the garbage collector may discard keys at any time, a
+ * <tt>WeakHashMap</tt> may behave as though an unknown thread is silently
+ * removing entries.  In particular, even if you synchronize on a
+ * <tt>WeakHashMap</tt> instance and invoke none of its mutator methods, it
+ * is possible for the <tt>size</tt> method to return smaller values over
+ * time, for the <tt>isEmpty</tt> method to return <tt>false</tt> and
+ * then <tt>true</tt>, for the <tt>containsKey</tt> method to return
+ * <tt>true</tt> and later <tt>false</tt> for a given key, for the
+ * <tt>get</tt> method to return a value for a given key but later return
+ * <tt>null</tt>, for the <tt>put</tt> method to return
+ * <tt>null</tt> and the <tt>remove</tt> method to return
+ * <tt>false</tt> for a key that previously appeared to be in the map, and
+ * for successive examinations of the key set, the value collection, and
+ * the entry set to yield successively smaller numbers of elements.
+ *
+ * <p> Each key object in a <tt>WeakHashMap</tt> is stored indirectly as
+ * the referent of a weak reference.  Therefore a key will automatically be
+ * removed only after the weak references to it, both inside and outside of the
+ * map, have been cleared by the garbage collector.
+ *
+ * <p> <strong>Implementation note:</strong> The value objects in a
+ * <tt>WeakHashMap</tt> are held by ordinary strong references.  Thus care
+ * should be taken to ensure that value objects do not strongly refer to their
+ * own keys, either directly or indirectly, since that will prevent the keys
+ * from being discarded.  Note that a value object may refer indirectly to its
+ * key via the <tt>WeakHashMap</tt> itself; that is, a value object may
+ * strongly refer to some other key object whose associated value object, in
+ * turn, strongly refers to the key of the first value object.  If the values
+ * in the map do not rely on the map holding strong references to them, one way
+ * to deal with this is to wrap values themselves within
+ * <tt>WeakReferences</tt> before
+ * inserting, as in: <tt>m.put(key, new WeakReference(value))</tt>,
+ * and then unwrapping upon each <tt>get</tt>.
+ *
+ * <p>The iterators returned by the <tt>iterator</tt> method of the collections
+ * returned by all of this class's "collection view methods" are
+ * <i>fail-fast</i>: if the map is structurally modified at any time after the
+ * iterator is created, in any way except through the iterator's own
+ * <tt>remove</tt> method, 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 time in the future.
+ *
+ * <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.
+ * 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>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author      Doug Lea
+ * @author      Josh Bloch
+ * @author      Mark Reinhold
+ * @since       1.2
+ * @see         java.util.HashMap
+ * @see         java.lang.ref.WeakReference
+ */
+public class WeakHashMap<K,V>
+    extends AbstractMap<K,V>
+    implements Map<K,V> {
+
+    /**
+     * The default initial capacity -- MUST be a power of two.
+     */
+    private static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<30.
+     */
+    private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The load factor used when none specified in constructor.
+     */
+    private static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+    /**
+     * The table, resized as necessary. Length MUST Always be a power of two.
+     */
+    Entry<K,V>[] table;
+
+    /**
+     * The number of key-value mappings contained in this weak hash map.
+     */
+    private int size;
+
+    /**
+     * The next size value at which to resize (capacity * load factor).
+     */
+    private int threshold;
+
+    /**
+     * The load factor for the hash table.
+     */
+    private final float loadFactor;
+
+    /**
+     * Reference queue for cleared WeakEntries
+     */
+    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
+
+    /**
+     * The number of times this WeakHashMap has been structurally modified.
+     * Structural modifications are those that change the number of
+     * mappings in the map or otherwise modify its internal structure
+     * (e.g., rehash).  This field is used to make iterators on
+     * Collection-views of the map fail-fast.
+     *
+     * @see ConcurrentModificationException
+     */
+    int modCount;
+
+    @SuppressWarnings("unchecked")
+    private Entry<K,V>[] newTable(int n) {
+        return (Entry<K,V>[]) new Entry<?,?>[n];
+    }
+
+    /**
+     * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial
+     * capacity and the given load factor.
+     *
+     * @param  initialCapacity The initial capacity of the <tt>WeakHashMap</tt>
+     * @param  loadFactor      The load factor of the <tt>WeakHashMap</tt>
+     * @throws IllegalArgumentException if the initial capacity is negative,
+     *         or if the load factor is nonpositive.
+     */
+    public WeakHashMap(int initialCapacity, float loadFactor) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Initial Capacity: "+
+                                               initialCapacity);
+        if (initialCapacity > MAXIMUM_CAPACITY)
+            initialCapacity = MAXIMUM_CAPACITY;
+
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal Load factor: "+
+                                               loadFactor);
+        int capacity = 1;
+        while (capacity < initialCapacity)
+            capacity <<= 1;
+        table = newTable(capacity);
+        this.loadFactor = loadFactor;
+        threshold = (int)(capacity * loadFactor);
+    }
+
+    /**
+     * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param  initialCapacity The initial capacity of the <tt>WeakHashMap</tt>
+     * @throws IllegalArgumentException if the initial capacity is negative
+     */
+    public WeakHashMap(int initialCapacity) {
+        this(initialCapacity, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs a new, empty <tt>WeakHashMap</tt> with the default initial
+     * capacity (16) and load factor (0.75).
+     */
+    public WeakHashMap() {
+        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs a new <tt>WeakHashMap</tt> with the same mappings as the
+     * specified map.  The <tt>WeakHashMap</tt> is created with the default
+     * load factor (0.75) and an initial capacity sufficient to hold the
+     * mappings in the specified map.
+     *
+     * @param   m the map whose mappings are to be placed in this map
+     * @throws  NullPointerException if the specified map is null
+     * @since   1.3
+     */
+    public WeakHashMap(Map<? extends K, ? extends V> m) {
+        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
+                DEFAULT_INITIAL_CAPACITY),
+             DEFAULT_LOAD_FACTOR);
+        putAll(m);
+    }
+
+    // internal utilities
+
+    /**
+     * Value representing null keys inside tables.
+     */
+    private static final Object NULL_KEY = new Object();
+
+    /**
+     * Use NULL_KEY for key if it is null.
+     */
+    private static Object maskNull(Object key) {
+        return (key == null) ? NULL_KEY : key;
+    }
+
+    /**
+     * Returns internal representation of null key back to caller as null.
+     */
+    static Object unmaskNull(Object key) {
+        return (key == NULL_KEY) ? null : key;
+    }
+
+    /**
+     * Checks for equality of non-null reference x and possibly-null y.  By
+     * default uses Object.equals.
+     */
+    private static boolean eq(Object x, Object y) {
+        return x == y || x.equals(y);
+    }
+
+    /**
+     * Retrieve object hash code and applies a supplemental hash function to the
+     * result hash, which defends against poor quality hash functions.  This is
+     * critical because HashMap uses power-of-two length hash tables, that
+     * otherwise encounter collisions for hashCodes that do not differ
+     * in lower bits.
+     */
+    final int hash(Object k) {
+        int h = k.hashCode();
+
+        // This function ensures that hashCodes that differ only by
+        // constant multiples at each bit position have a bounded
+        // number of collisions (approximately 8 at default load factor).
+        h ^= (h >>> 20) ^ (h >>> 12);
+        return h ^ (h >>> 7) ^ (h >>> 4);
+    }
+
+    /**
+     * Returns index for hash code h.
+     */
+    private static int indexFor(int h, int length) {
+        return h & (length-1);
+    }
+
+    /**
+     * Expunges stale entries from the table.
+     */
+    private void expungeStaleEntries() {
+        for (Object x; (x = queue.poll()) != null; ) {
+            synchronized (queue) {
+                @SuppressWarnings("unchecked")
+                    Entry<K,V> e = (Entry<K,V>) x;
+                int i = indexFor(e.hash, table.length);
+
+                Entry<K,V> prev = table[i];
+                Entry<K,V> p = prev;
+                while (p != null) {
+                    Entry<K,V> next = p.next;
+                    if (p == e) {
+                        if (prev == e)
+                            table[i] = next;
+                        else
+                            prev.next = next;
+                        // Must not null out e.next;
+                        // stale entries may be in use by a HashIterator
+                        e.value = null; // Help GC
+                        size--;
+                        break;
+                    }
+                    prev = p;
+                    p = next;
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the table after first expunging stale entries.
+     */
+    private Entry<K,V>[] getTable() {
+        expungeStaleEntries();
+        return table;
+    }
+
+    /**
+     * Returns the number of key-value mappings in this map.
+     * This result is a snapshot, and may not reflect unprocessed
+     * entries that will be removed before next attempted access
+     * because they are no longer referenced.
+     */
+    public int size() {
+        if (size == 0)
+            return 0;
+        expungeStaleEntries();
+        return size;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains no key-value mappings.
+     * This result is a snapshot, and may not reflect unprocessed
+     * entries that will be removed before next attempted access
+     * because they are no longer referenced.
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
+     * key.equals(k))}, then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} 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 {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @see #put(Object, Object)
+     */
+    public V get(Object key) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int index = indexFor(h, tab.length);
+        Entry<K,V> e = tab[index];
+        while (e != null) {
+            if (e.hash == h && eq(k, e.get()))
+                return e.value;
+            e = e.next;
+        }
+        return null;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains a mapping for the
+     * specified key.
+     *
+     * @param  key   The key whose presence in this map is to be tested
+     * @return <tt>true</tt> if there is a mapping for <tt>key</tt>;
+     *         <tt>false</tt> otherwise
+     */
+    public boolean containsKey(Object key) {
+        return getEntry(key) != null;
+    }
+
+    /**
+     * Returns the entry associated with the specified key in this map.
+     * Returns null if the map contains no mapping for this key.
+     */
+    Entry<K,V> getEntry(Object key) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int index = indexFor(h, tab.length);
+        Entry<K,V> e = tab[index];
+        while (e != null && !(e.hash == h && eq(k, e.get())))
+            e = e.next;
+        return e;
+    }
+
+    /**
+     * 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 the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
+     *         (A <tt>null</tt> return can also indicate that the map
+     *         previously associated <tt>null</tt> with <tt>key</tt>.)
+     */
+    public V put(K key, V value) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int i = indexFor(h, tab.length);
+
+        for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
+            if (h == e.hash && eq(k, e.get())) {
+                V oldValue = e.value;
+                if (value != oldValue)
+                    e.value = value;
+                return oldValue;
+            }
+        }
+
+        modCount++;
+        Entry<K,V> e = tab[i];
+        tab[i] = new Entry<>(k, value, queue, h, e);
+        if (++size >= threshold)
+            resize(tab.length * 2);
+        return null;
+    }
+
+    /**
+     * Rehashes the contents of this map into a new array with a
+     * larger capacity.  This method is called automatically when the
+     * number of keys in this map reaches its threshold.
+     *
+     * If current capacity is MAXIMUM_CAPACITY, this method does not
+     * resize the map, but sets threshold to Integer.MAX_VALUE.
+     * This has the effect of preventing future calls.
+     *
+     * @param newCapacity the new capacity, MUST be a power of two;
+     *        must be greater than current capacity unless current
+     *        capacity is MAXIMUM_CAPACITY (in which case value
+     *        is irrelevant).
+     */
+    void resize(int newCapacity) {
+        Entry<K,V>[] oldTable = getTable();
+        int oldCapacity = oldTable.length;
+        if (oldCapacity == MAXIMUM_CAPACITY) {
+            threshold = Integer.MAX_VALUE;
+            return;
+        }
+
+        Entry<K,V>[] newTable = newTable(newCapacity);
+        transfer(oldTable, newTable);
+        table = newTable;
+
+        /*
+         * If ignoring null elements and processing ref queue caused massive
+         * shrinkage, then restore old table.  This should be rare, but avoids
+         * unbounded expansion of garbage-filled tables.
+         */
+        if (size >= threshold / 2) {
+            threshold = (int)(newCapacity * loadFactor);
+        } else {
+            expungeStaleEntries();
+            transfer(newTable, oldTable);
+            table = oldTable;
+        }
+    }
+
+    /** Transfers all entries from src to dest tables */
+    private void transfer(Entry<K,V>[] src, Entry<K,V>[] dest) {
+        for (int j = 0; j < src.length; ++j) {
+            Entry<K,V> e = src[j];
+            src[j] = null;
+            while (e != null) {
+                Entry<K,V> next = e.next;
+                Object key = e.get();
+                if (key == null) {
+                    e.next = null;  // Help GC
+                    e.value = null; //  "   "
+                    size--;
+                } else {
+                    int i = indexFor(e.hash, dest.length);
+                    e.next = dest[i];
+                    dest[i] = e;
+                }
+                e = next;
+            }
+        }
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for any
+     * of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map.
+     * @throws  NullPointerException if the specified map is null.
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        int numKeysToBeAdded = m.size();
+        if (numKeysToBeAdded == 0)
+            return;
+
+        /*
+         * Expand the map if the map if the number of mappings to be added
+         * is greater than or equal to threshold.  This is conservative; the
+         * obvious condition is (m.size() + size) >= threshold, but this
+         * condition could result in a map with twice the appropriate capacity,
+         * if the keys to be added overlap with the keys already in this map.
+         * By using the conservative calculation, we subject ourself
+         * to at most one extra resize.
+         */
+        if (numKeysToBeAdded > threshold) {
+            int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
+            if (targetCapacity > MAXIMUM_CAPACITY)
+                targetCapacity = MAXIMUM_CAPACITY;
+            int newCapacity = table.length;
+            while (newCapacity < targetCapacity)
+                newCapacity <<= 1;
+            if (newCapacity > table.length)
+                resize(newCapacity);
+        }
+
+        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * Removes the mapping for a key from this weak hash map if it is present.
+     * More formally, if this map contains a mapping from key <tt>k</tt> to
+     * value <tt>v</tt> such that <code>(key==null ?  k==null :
+     * key.equals(k))</code>, that mapping is removed.  (The map can contain
+     * at most one such mapping.)
+     *
+     * <p>Returns the value to which this map previously associated the key,
+     * or <tt>null</tt> if the map contained no mapping for the key.  A
+     * return value of <tt>null</tt> does not <i>necessarily</i> indicate
+     * that the map contained no mapping for the key; it's also possible
+     * that the map explicitly mapped the key to <tt>null</tt>.
+     *
+     * <p>The map will not contain a mapping for the specified key once the
+     * call returns.
+     *
+     * @param key key whose mapping is to be removed from the map
+     * @return the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>
+     */
+    public V remove(Object key) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int i = indexFor(h, tab.length);
+        Entry<K,V> prev = tab[i];
+        Entry<K,V> e = prev;
+
+        while (e != null) {
+            Entry<K,V> next = e.next;
+            if (h == e.hash && eq(k, e.get())) {
+                modCount++;
+                size--;
+                if (prev == e)
+                    tab[i] = next;
+                else
+                    prev.next = next;
+                return e.value;
+            }
+            prev = e;
+            e = next;
+        }
+
+        return null;
+    }
+
+    /** Special version of remove needed by Entry set */
+    boolean removeMapping(Object o) {
+        if (!(o instanceof Map.Entry))
+            return false;
+        Entry<K,V>[] tab = getTable();
+        Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+        Object k = maskNull(entry.getKey());
+        int h = hash(k);
+        int i = indexFor(h, tab.length);
+        Entry<K,V> prev = tab[i];
+        Entry<K,V> e = prev;
+
+        while (e != null) {
+            Entry<K,V> next = e.next;
+            if (h == e.hash && e.equals(entry)) {
+                modCount++;
+                size--;
+                if (prev == e)
+                    tab[i] = next;
+                else
+                    prev.next = next;
+                return true;
+            }
+            prev = e;
+            e = next;
+        }
+
+        return false;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        // clear out ref queue. We don't need to expunge entries
+        // since table is getting cleared.
+        while (queue.poll() != null)
+            ;
+
+        modCount++;
+        Arrays.fill(table, null);
+        size = 0;
+
+        // Allocation of array may have caused GC, which may have caused
+        // additional entries to go stale.  Removing these entries from the
+        // reference queue will make them eligible for reclamation.
+        while (queue.poll() != 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) {
+        if (value==null)
+            return containsNullValue();
+
+        Entry<K,V>[] tab = getTable();
+        for (int i = tab.length; i-- > 0;)
+            for (Entry<K,V> e = tab[i]; e != null; e = e.next)
+                if (value.equals(e.value))
+                    return true;
+        return false;
+    }
+
+    /**
+     * Special-case code for containsValue with null argument
+     */
+    private boolean containsNullValue() {
+        Entry<K,V>[] tab = getTable();
+        for (int i = tab.length; i-- > 0;)
+            for (Entry<K,V> e = tab[i]; e != null; e = e.next)
+                if (e.value==null)
+                    return true;
+        return false;
+    }
+
+    /**
+     * The entries in this hash table extend WeakReference, using its main ref
+     * field as the key.
+     */
+    private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
+        V value;
+        final int hash;
+        Entry<K,V> next;
+
+        /**
+         * Creates new entry.
+         */
+        Entry(Object key, V value,
+              ReferenceQueue<Object> queue,
+              int hash, Entry<K,V> next) {
+            super(key, queue);
+            this.value = value;
+            this.hash  = hash;
+            this.next  = next;
+        }
+
+        @SuppressWarnings("unchecked")
+        public K getKey() {
+            return (K) WeakHashMap.unmaskNull(get());
+        }
+
+        public V getValue() {
+            return value;
+        }
+
+        public V setValue(V newValue) {
+            V oldValue = value;
+            value = newValue;
+            return oldValue;
+        }
+
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            K k1 = getKey();
+            Object k2 = e.getKey();
+            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
+                V v1 = getValue();
+                Object v2 = e.getValue();
+                if (v1 == v2 || (v1 != null && v1.equals(v2)))
+                    return true;
+            }
+            return false;
+        }
+
+        public int hashCode() {
+            K k = getKey();
+            V v = getValue();
+            return Objects.hashCode(k) ^ Objects.hashCode(v);
+        }
+
+        public String toString() {
+            return getKey() + "=" + getValue();
+        }
+    }
+
+    private abstract class HashIterator<T> implements Iterator<T> {
+        private int index;
+        private Entry<K,V> entry;
+        private Entry<K,V> lastReturned;
+        private int expectedModCount = modCount;
+
+        /**
+         * Strong reference needed to avoid disappearance of key
+         * between hasNext and next
+         */
+        private Object nextKey;
+
+        /**
+         * Strong reference needed to avoid disappearance of key
+         * between nextEntry() and any use of the entry
+         */
+        private Object currentKey;
+
+        HashIterator() {
+            index = isEmpty() ? 0 : table.length;
+        }
+
+        public boolean hasNext() {
+            Entry<K,V>[] t = table;
+
+            while (nextKey == null) {
+                Entry<K,V> e = entry;
+                int i = index;
+                while (e == null && i > 0)
+                    e = t[--i];
+                entry = e;
+                index = i;
+                if (e == null) {
+                    currentKey = null;
+                    return false;
+                }
+                nextKey = e.get(); // hold on to key in strong ref
+                if (nextKey == null)
+                    entry = entry.next;
+            }
+            return true;
+        }
+
+        /** The common parts of next() across different types of iterators */
+        protected Entry<K,V> nextEntry() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (nextKey == null && !hasNext())
+                throw new NoSuchElementException();
+
+            lastReturned = entry;
+            entry = entry.next;
+            currentKey = nextKey;
+            nextKey = null;
+            return lastReturned;
+        }
+
+        public void remove() {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            WeakHashMap.this.remove(currentKey);
+            expectedModCount = modCount;
+            lastReturned = null;
+            currentKey = null;
+        }
+
+    }
+
+    private class ValueIterator extends HashIterator<V> {
+        public V next() {
+            return nextEntry().value;
+        }
+    }
+
+    private class KeyIterator extends HashIterator<K> {
+        public K next() {
+            return nextEntry().getKey();
+        }
+    }
+
+    private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
+        public Map.Entry<K,V> next() {
+            return nextEntry();
+        }
+    }
+
+    // Views
+
+    private transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+     * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
+     * operations.
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return new KeyIterator();
+        }
+
+        public int size() {
+            return WeakHashMap.this.size();
+        }
+
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+
+        public boolean remove(Object o) {
+            if (containsKey(o)) {
+                WeakHashMap.this.remove(o);
+                return true;
+            }
+            else
+                return false;
+        }
+
+        public void clear() {
+            WeakHashMap.this.clear();
+        }
+
+        public Spliterator<K> spliterator() {
+            return new KeySpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own <tt>remove</tt> operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
+     * support the <tt>add</tt> or <tt>addAll</tt> operations.
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    private class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator();
+        }
+
+        public int size() {
+            return WeakHashMap.this.size();
+        }
+
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+
+        public void clear() {
+            WeakHashMap.this.clear();
+        }
+
+        public Spliterator<V> spliterator() {
+            return new ValueSpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation, or through the
+     * <tt>setValue</tt> operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
+     * <tt>clear</tt> operations.  It does not support the
+     * <tt>add</tt> or <tt>addAll</tt> operations.
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es = entrySet;
+        return es != null ? es : (entrySet = new EntrySet());
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            Entry<K,V> candidate = getEntry(e.getKey());
+            return candidate != null && candidate.equals(e);
+        }
+
+        public boolean remove(Object o) {
+            return removeMapping(o);
+        }
+
+        public int size() {
+            return WeakHashMap.this.size();
+        }
+
+        public void clear() {
+            WeakHashMap.this.clear();
+        }
+
+        private List<Map.Entry<K,V>> deepCopy() {
+            List<Map.Entry<K,V>> list = new ArrayList<>(size());
+            for (Map.Entry<K,V> e : this)
+                list.add(new AbstractMap.SimpleEntry<>(e));
+            return list;
+        }
+
+        public Object[] toArray() {
+            return deepCopy().toArray();
+        }
+
+        public <T> T[] toArray(T[] a) {
+            return deepCopy().toArray(a);
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+
+        Entry<K, V>[] tab = getTable();
+        for (Entry<K, V> entry : tab) {
+            while (entry != null) {
+                Object key = entry.get();
+                if (key != null) {
+                    action.accept((K)WeakHashMap.unmaskNull(key), entry.value);
+                }
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        int expectedModCount = modCount;
+
+        Entry<K, V>[] tab = getTable();;
+        for (Entry<K, V> entry : tab) {
+            while (entry != null) {
+                Object key = entry.get();
+                if (key != null) {
+                    entry.value = function.apply((K)WeakHashMap.unmaskNull(key), entry.value);
+                }
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    /**
+     * Similar form as other hash Spliterators, but skips dead
+     * elements.
+     */
+    static class WeakHashMapSpliterator<K,V> {
+        final WeakHashMap<K,V> map;
+        WeakHashMap.Entry<K,V> current; // current node
+        int index;             // current index, modified on advance/split
+        int fence;             // -1 until first use; then one past last index
+        int est;               // size estimate
+        int expectedModCount;  // for comodification checks
+
+        WeakHashMapSpliterator(WeakHashMap<K,V> m, int origin,
+                               int fence, int est,
+                               int expectedModCount) {
+            this.map = m;
+            this.index = origin;
+            this.fence = fence;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getFence() { // initialize fence and size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                WeakHashMap<K,V> m = map;
+                est = m.size();
+                expectedModCount = m.modCount;
+                hi = fence = m.table.length;
+            }
+            return hi;
+        }
+
+        public final long estimateSize() {
+            getFence(); // force init
+            return (long) est;
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends WeakHashMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                        expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap<K,V> m = map;
+            WeakHashMap.Entry<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        Object x = p.get();
+                        p = p.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept(k);
+                        }
+                    }
+                } while (p != null || i < hi);
+            }
+            if (m.modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap.Entry<K,V>[] tab = map.table;
+            if (tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Object x = current.get();
+                        current = current.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept(k);
+                            if (map.modCount != expectedModCount)
+                                throw new ConcurrentModificationException();
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+        extends WeakHashMapSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap<K,V> m = map;
+            WeakHashMap.Entry<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        Object x = p.get();
+                        V v = p.value;
+                        p = p.next;
+                        if (x != null)
+                            action.accept(v);
+                    }
+                } while (p != null || i < hi);
+            }
+            if (m.modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap.Entry<K,V>[] tab = map.table;
+            if (tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Object x = current.get();
+                        V v = current.value;
+                        current = current.next;
+                        if (x != null) {
+                            action.accept(v);
+                            if (map.modCount != expectedModCount)
+                                throw new ConcurrentModificationException();
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return 0;
+        }
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends WeakHashMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new EntrySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap<K,V> m = map;
+            WeakHashMap.Entry<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        Object x = p.get();
+                        V v = p.value;
+                        p = p.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept
+                                (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+                        }
+                    }
+                } while (p != null || i < hi);
+            }
+            if (m.modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap.Entry<K,V>[] tab = map.table;
+            if (tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Object x = current.get();
+                        V v = current.value;
+                        current = current.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept
+                                (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+                            if (map.modCount != expectedModCount)
+                                throw new ConcurrentModificationException();
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT;
+        }
+    }
+
+}
diff --git a/java/util/XMLUtils.java b/java/util/XMLUtils.java
new file mode 100644
index 0000000..8f061e5
--- /dev/null
+++ b/java/util/XMLUtils.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+import org.w3c.dom.*;
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.stream.*;
+
+/**
+ * A class used to aid in Properties load and save in XML. Keeping this
+ * code outside of Properties helps reduce the number of classes loaded
+ * when Properties is loaded.
+ *
+ * @author  Michael McCloskey
+ * @since   1.3
+ */
+class XMLUtils {
+
+    // XML loading and saving methods for Properties
+
+    // The required DTD URI for exported properties
+    private static final String PROPS_DTD_URI =
+    "http://java.sun.com/dtd/properties.dtd";
+
+    private static final String PROPS_DTD =
+    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+    "<!-- DTD for properties -->"                +
+    "<!ELEMENT properties ( comment?, entry* ) >"+
+    "<!ATTLIST properties"                       +
+        " version CDATA #FIXED \"1.0\">"         +
+    "<!ELEMENT comment (#PCDATA) >"              +
+    "<!ELEMENT entry (#PCDATA) >"                +
+    "<!ATTLIST entry "                           +
+        " key CDATA #REQUIRED>";
+
+    /**
+     * Version number for the format of exported properties files.
+     */
+    private static final String EXTERNAL_XML_VERSION = "1.0";
+
+    static void load(Properties props, InputStream in)
+        throws IOException, InvalidPropertiesFormatException
+    {
+        Document doc = null;
+        try {
+            doc = getLoadingDoc(in);
+        } catch (SAXException saxe) {
+            throw new InvalidPropertiesFormatException(saxe);
+        }
+        Element propertiesElement = doc.getDocumentElement();
+        String xmlVersion = propertiesElement.getAttribute("version");
+        if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0)
+            throw new InvalidPropertiesFormatException(
+                "Exported Properties file format version " + xmlVersion +
+                " is not supported. This java installation can read" +
+                " versions " + EXTERNAL_XML_VERSION + " or older. You" +
+                " may need to install a newer version of JDK.");
+        importProperties(props, propertiesElement);
+    }
+
+    static Document getLoadingDoc(InputStream in)
+        throws SAXException, IOException
+    {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setIgnoringElementContentWhitespace(true);
+        // Android-changed: We don't currently have a validating document builder.
+        // Revert this if the situation changes.
+        //
+        // dbf.setValidating(true);
+        dbf.setCoalescing(true);
+        dbf.setIgnoringComments(true);
+        try {
+            DocumentBuilder db = dbf.newDocumentBuilder();
+            db.setEntityResolver(new Resolver());
+            db.setErrorHandler(new EH());
+            InputSource is = new InputSource(in);
+            return db.parse(is);
+        } catch (ParserConfigurationException x) {
+            throw new Error(x);
+        }
+    }
+
+    static void importProperties(Properties props, Element propertiesElement) {
+        NodeList entries = propertiesElement.getChildNodes();
+        int numEntries = entries.getLength();
+        int start = numEntries > 0 &&
+            entries.item(0).getNodeName().equals("comment") ? 1 : 0;
+        for (int i=start; i<numEntries; i++) {
+            // Android-changed: Exclude CDATA nodes and the like.
+            if (!(entries.item(i) instanceof Element)) {
+                continue;
+            }
+            Element entry = (Element)entries.item(i);
+            if (entry.hasAttribute("key")) {
+                Node n = entry.getFirstChild();
+                String val = (n == null) ? "" : n.getNodeValue();
+                props.setProperty(entry.getAttribute("key"), val);
+            }
+        }
+    }
+
+    static void save(Properties props, OutputStream os, String comment,
+                     String encoding)
+        throws IOException
+    {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        DocumentBuilder db = null;
+        try {
+            db = dbf.newDocumentBuilder();
+        } catch (ParserConfigurationException pce) {
+            assert(false);
+        }
+        Document doc = db.newDocument();
+        Element properties =  (Element)
+            doc.appendChild(doc.createElement("properties"));
+
+        if (comment != null) {
+            Element comments = (Element)properties.appendChild(
+                doc.createElement("comment"));
+            comments.appendChild(doc.createTextNode(comment));
+        }
+
+        synchronized (props) {
+            for (String key : props.stringPropertyNames()) {
+                Element entry = (Element)properties.appendChild(
+                    doc.createElement("entry"));
+                entry.setAttribute("key", key);
+                entry.appendChild(doc.createTextNode(props.getProperty(key)));
+            }
+        }
+        emitDocument(doc, os, encoding);
+    }
+
+    static void emitDocument(Document doc, OutputStream os, String encoding)
+        throws IOException
+    {
+        TransformerFactory tf = TransformerFactory.newInstance();
+        Transformer t = null;
+        try {
+            t = tf.newTransformer();
+            t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, PROPS_DTD_URI);
+            t.setOutputProperty(OutputKeys.INDENT, "yes");
+            t.setOutputProperty(OutputKeys.METHOD, "xml");
+            t.setOutputProperty(OutputKeys.ENCODING, encoding);
+        } catch (TransformerConfigurationException tce) {
+            assert(false);
+        }
+        DOMSource doms = new DOMSource(doc);
+        StreamResult sr = new StreamResult(os);
+        try {
+            t.transform(doms, sr);
+        } catch (TransformerException te) {
+            IOException ioe = new IOException();
+            ioe.initCause(te);
+            throw ioe;
+        }
+    }
+
+    private static class Resolver implements EntityResolver {
+        public InputSource resolveEntity(String pid, String sid)
+            throws SAXException
+        {
+            if (sid.equals(PROPS_DTD_URI)) {
+                InputSource is;
+                is = new InputSource(new StringReader(PROPS_DTD));
+                is.setSystemId(PROPS_DTD_URI);
+                return is;
+            }
+            throw new SAXException("Invalid system identifier: " + sid);
+        }
+    }
+
+    private static class EH implements ErrorHandler {
+        public void error(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void fatalError(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void warning(SAXParseException x) throws SAXException {
+            throw x;
+        }
+    }
+
+}
diff --git a/java/util/concurrent/AbstractExecutorService.java b/java/util/concurrent/AbstractExecutorService.java
new file mode 100644
index 0000000..e4d2235
--- /dev/null
+++ b/java/util/concurrent/AbstractExecutorService.java
@@ -0,0 +1,312 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Provides default implementations of {@link ExecutorService}
+ * execution methods. This class implements the {@code submit},
+ * {@code invokeAny} and {@code invokeAll} methods using a
+ * {@link RunnableFuture} returned by {@code newTaskFor}, which defaults
+ * to the {@link FutureTask} class provided in this package.  For example,
+ * the implementation of {@code submit(Runnable)} creates an
+ * associated {@code RunnableFuture} that is executed and
+ * returned. Subclasses may override the {@code newTaskFor} methods
+ * to return {@code RunnableFuture} implementations other than
+ * {@code FutureTask}.
+ *
+ * <p><b>Extension example</b>. Here is a sketch of a class
+ * that customizes {@link ThreadPoolExecutor} to use
+ * a {@code CustomTask} class instead of the default {@code FutureTask}:
+ * <pre> {@code
+ * public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
+ *
+ *   static class CustomTask<V> implements RunnableFuture<V> {...}
+ *
+ *   protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) {
+ *       return new CustomTask<V>(c);
+ *   }
+ *   protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) {
+ *       return new CustomTask<V>(r, v);
+ *   }
+ *   // ... add constructors, etc.
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public abstract class AbstractExecutorService implements ExecutorService {
+
+    /**
+     * Returns a {@code RunnableFuture} for the given runnable and default
+     * value.
+     *
+     * @param runnable the runnable task being wrapped
+     * @param value the default value for the returned future
+     * @param <T> the type of the given value
+     * @return a {@code RunnableFuture} which, when run, will run the
+     * underlying runnable and which, as a {@code Future}, will yield
+     * the given value as its result and provide for cancellation of
+     * the underlying task
+     * @since 1.6
+     */
+    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
+        return new FutureTask<T>(runnable, value);
+    }
+
+    /**
+     * Returns a {@code RunnableFuture} for the given callable task.
+     *
+     * @param callable the callable task being wrapped
+     * @param <T> the type of the callable's result
+     * @return a {@code RunnableFuture} which, when run, will call the
+     * underlying callable and which, as a {@code Future}, will yield
+     * the callable's result as its result and provide for
+     * cancellation of the underlying task
+     * @since 1.6
+     */
+    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
+        return new FutureTask<T>(callable);
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public Future<?> submit(Runnable task) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<Void> ftask = newTaskFor(task, null);
+        execute(ftask);
+        return ftask;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Runnable task, T result) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<T> ftask = newTaskFor(task, result);
+        execute(ftask);
+        return ftask;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Callable<T> task) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<T> ftask = newTaskFor(task);
+        execute(ftask);
+        return ftask;
+    }
+
+    /**
+     * the main mechanics of invokeAny.
+     */
+    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
+                              boolean timed, long nanos)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        if (tasks == null)
+            throw new NullPointerException();
+        int ntasks = tasks.size();
+        if (ntasks == 0)
+            throw new IllegalArgumentException();
+        ArrayList<Future<T>> futures = new ArrayList<>(ntasks);
+        ExecutorCompletionService<T> ecs =
+            new ExecutorCompletionService<T>(this);
+
+        // For efficiency, especially in executors with limited
+        // parallelism, check to see if previously submitted tasks are
+        // done before submitting more of them. This interleaving
+        // plus the exception mechanics account for messiness of main
+        // loop.
+
+        try {
+            // Record exceptions so that if we fail to obtain any
+            // result, we can throw the last exception we got.
+            ExecutionException ee = null;
+            final long deadline = timed ? System.nanoTime() + nanos : 0L;
+            Iterator<? extends Callable<T>> it = tasks.iterator();
+
+            // Start one task for sure; the rest incrementally
+            futures.add(ecs.submit(it.next()));
+            --ntasks;
+            int active = 1;
+
+            for (;;) {
+                Future<T> f = ecs.poll();
+                if (f == null) {
+                    if (ntasks > 0) {
+                        --ntasks;
+                        futures.add(ecs.submit(it.next()));
+                        ++active;
+                    }
+                    else if (active == 0)
+                        break;
+                    else if (timed) {
+                        f = ecs.poll(nanos, NANOSECONDS);
+                        if (f == null)
+                            throw new TimeoutException();
+                        nanos = deadline - System.nanoTime();
+                    }
+                    else
+                        f = ecs.take();
+                }
+                if (f != null) {
+                    --active;
+                    try {
+                        return f.get();
+                    } catch (ExecutionException eex) {
+                        ee = eex;
+                    } catch (RuntimeException rex) {
+                        ee = new ExecutionException(rex);
+                    }
+                }
+            }
+
+            if (ee == null)
+                ee = new ExecutionException();
+            throw ee;
+
+        } finally {
+            cancelAll(futures);
+        }
+    }
+
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException, ExecutionException {
+        try {
+            return doInvokeAny(tasks, false, 0);
+        } catch (TimeoutException cannotHappen) {
+            assert false;
+            return null;
+        }
+    }
+
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+                           long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        return doInvokeAny(tasks, true, unit.toNanos(timeout));
+    }
+
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException {
+        if (tasks == null)
+            throw new NullPointerException();
+        ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+        try {
+            for (Callable<T> t : tasks) {
+                RunnableFuture<T> f = newTaskFor(t);
+                futures.add(f);
+                execute(f);
+            }
+            for (int i = 0, size = futures.size(); i < size; i++) {
+                Future<T> f = futures.get(i);
+                if (!f.isDone()) {
+                    try { f.get(); }
+                    catch (CancellationException ignore) {}
+                    catch (ExecutionException ignore) {}
+                }
+            }
+            return futures;
+        } catch (Throwable t) {
+            cancelAll(futures);
+            throw t;
+        }
+    }
+
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
+                                         long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (tasks == null)
+            throw new NullPointerException();
+        final long nanos = unit.toNanos(timeout);
+        final long deadline = System.nanoTime() + nanos;
+        ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+        int j = 0;
+        timedOut: try {
+            for (Callable<T> t : tasks)
+                futures.add(newTaskFor(t));
+
+            final int size = futures.size();
+
+            // Interleave time checks and calls to execute in case
+            // executor doesn't have any/much parallelism.
+            for (int i = 0; i < size; i++) {
+                if (((i == 0) ? nanos : deadline - System.nanoTime()) <= 0L)
+                    break timedOut;
+                execute((Runnable)futures.get(i));
+            }
+
+            for (; j < size; j++) {
+                Future<T> f = futures.get(j);
+                if (!f.isDone()) {
+                    try { f.get(deadline - System.nanoTime(), NANOSECONDS); }
+                    catch (CancellationException ignore) {}
+                    catch (ExecutionException ignore) {}
+                    catch (TimeoutException timedOut) {
+                        break timedOut;
+                    }
+                }
+            }
+            return futures;
+        } catch (Throwable t) {
+            cancelAll(futures);
+            throw t;
+        }
+        // Timed out before all the tasks could be completed; cancel remaining
+        cancelAll(futures, j);
+        return futures;
+    }
+
+    private static <T> void cancelAll(ArrayList<Future<T>> futures) {
+        cancelAll(futures, 0);
+    }
+
+    /** Cancels all futures with index at least j. */
+    private static <T> void cancelAll(ArrayList<Future<T>> futures, int j) {
+        for (int size = futures.size(); j < size; j++)
+            futures.get(j).cancel(true);
+    }
+}
diff --git a/java/util/concurrent/ArrayBlockingQueue.java b/java/util/concurrent/ArrayBlockingQueue.java
new file mode 100644
index 0000000..96a60b3
--- /dev/null
+++ b/java/util/concurrent/ArrayBlockingQueue.java
@@ -0,0 +1,1369 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.ref.WeakReference;
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A bounded {@linkplain BlockingQueue blocking queue} backed by an
+ * array.  This queue orders elements FIFO (first-in-first-out).  The
+ * <em>head</em> of the queue is that element that has been on the
+ * queue the longest time.  The <em>tail</em> of the queue is that
+ * element that has been on the queue the shortest time. New elements
+ * are inserted at the tail of the queue, and the queue retrieval
+ * operations obtain elements at the head of the queue.
+ *
+ * <p>This is a classic &quot;bounded buffer&quot;, in which a
+ * fixed-sized array holds elements inserted by producers and
+ * extracted by consumers.  Once created, the capacity cannot be
+ * changed.  Attempts to {@code put} an element into a full queue
+ * will result in the operation blocking; attempts to {@code take} an
+ * element from an empty queue will similarly block.
+ *
+ * <p>This class supports an optional fairness policy for ordering
+ * waiting producer and consumer threads.  By default, this ordering
+ * is not guaranteed. However, a queue constructed with fairness set
+ * to {@code true} grants threads access in FIFO order. Fairness
+ * generally decreases throughput but reduces variability and avoids
+ * starvation.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class ArrayBlockingQueue<E> extends AbstractQueue<E>
+        implements BlockingQueue<E>, java.io.Serializable {
+
+    /**
+     * Serialization ID. This class relies on default serialization
+     * even for the items array, which is default-serialized, even if
+     * it is empty. Otherwise it could not be declared final, which is
+     * necessary here.
+     */
+    private static final long serialVersionUID = -817911632652898426L;
+
+    /** The queued items */
+    final Object[] items;
+
+    /** items index for next take, poll, peek or remove */
+    int takeIndex;
+
+    /** items index for next put, offer, or add */
+    int putIndex;
+
+    /** Number of elements in the queue */
+    int count;
+
+    /*
+     * Concurrency control uses the classic two-condition algorithm
+     * found in any textbook.
+     */
+
+    /** Main lock guarding all access */
+    final ReentrantLock lock;
+
+    /** Condition for waiting takes */
+    private final Condition notEmpty;
+
+    /** Condition for waiting puts */
+    private final Condition notFull;
+
+    /**
+     * Shared state for currently active iterators, or null if there
+     * are known not to be any.  Allows queue operations to update
+     * iterator state.
+     */
+    transient Itrs itrs;
+
+    // Internal helper methods
+
+    /**
+     * Circularly decrements array index i.
+     */
+    final int dec(int i) {
+        return ((i == 0) ? items.length : i) - 1;
+    }
+
+    /**
+     * Returns item at index i.
+     */
+    @SuppressWarnings("unchecked")
+    final E itemAt(int i) {
+        return (E) items[i];
+    }
+
+    /**
+     * Inserts element at current put position, advances, and signals.
+     * Call only when holding lock.
+     */
+    private void enqueue(E x) {
+        // assert lock.getHoldCount() == 1;
+        // assert items[putIndex] == null;
+        final Object[] items = this.items;
+        items[putIndex] = x;
+        if (++putIndex == items.length) putIndex = 0;
+        count++;
+        notEmpty.signal();
+    }
+
+    /**
+     * Extracts element at current take position, advances, and signals.
+     * Call only when holding lock.
+     */
+    private E dequeue() {
+        // assert lock.getHoldCount() == 1;
+        // assert items[takeIndex] != null;
+        final Object[] items = this.items;
+        @SuppressWarnings("unchecked")
+        E x = (E) items[takeIndex];
+        items[takeIndex] = null;
+        if (++takeIndex == items.length) takeIndex = 0;
+        count--;
+        if (itrs != null)
+            itrs.elementDequeued();
+        notFull.signal();
+        return x;
+    }
+
+    /**
+     * Deletes item at array index removeIndex.
+     * Utility for remove(Object) and iterator.remove.
+     * Call only when holding lock.
+     */
+    void removeAt(final int removeIndex) {
+        // assert lock.getHoldCount() == 1;
+        // assert items[removeIndex] != null;
+        // assert removeIndex >= 0 && removeIndex < items.length;
+        final Object[] items = this.items;
+        if (removeIndex == takeIndex) {
+            // removing front item; just advance
+            items[takeIndex] = null;
+            if (++takeIndex == items.length) takeIndex = 0;
+            count--;
+            if (itrs != null)
+                itrs.elementDequeued();
+        } else {
+            // an "interior" remove
+
+            // slide over all others up through putIndex.
+            for (int i = removeIndex, putIndex = this.putIndex;;) {
+                int pred = i;
+                if (++i == items.length) i = 0;
+                if (i == putIndex) {
+                    items[pred] = null;
+                    this.putIndex = pred;
+                    break;
+                }
+                items[pred] = items[i];
+            }
+            count--;
+            if (itrs != null)
+                itrs.removedAt(removeIndex);
+        }
+        notFull.signal();
+    }
+
+    /**
+     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
+     * capacity and default access policy.
+     *
+     * @param capacity the capacity of this queue
+     * @throws IllegalArgumentException if {@code capacity < 1}
+     */
+    public ArrayBlockingQueue(int capacity) {
+        this(capacity, false);
+    }
+
+    /**
+     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
+     * capacity and the specified access policy.
+     *
+     * @param capacity the capacity of this queue
+     * @param fair if {@code true} then queue accesses for threads blocked
+     *        on insertion or removal, are processed in FIFO order;
+     *        if {@code false} the access order is unspecified.
+     * @throws IllegalArgumentException if {@code capacity < 1}
+     */
+    public ArrayBlockingQueue(int capacity, boolean fair) {
+        if (capacity <= 0)
+            throw new IllegalArgumentException();
+        this.items = new Object[capacity];
+        lock = new ReentrantLock(fair);
+        notEmpty = lock.newCondition();
+        notFull =  lock.newCondition();
+    }
+
+    /**
+     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
+     * capacity, the specified access policy and initially containing the
+     * elements of the given collection,
+     * added in traversal order of the collection's iterator.
+     *
+     * @param capacity the capacity of this queue
+     * @param fair if {@code true} then queue accesses for threads blocked
+     *        on insertion or removal, are processed in FIFO order;
+     *        if {@code false} the access order is unspecified.
+     * @param c the collection of elements to initially contain
+     * @throws IllegalArgumentException if {@code capacity} is less than
+     *         {@code c.size()}, or less than 1.
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public ArrayBlockingQueue(int capacity, boolean fair,
+                              Collection<? extends E> c) {
+        this(capacity, fair);
+
+        final ReentrantLock lock = this.lock;
+        lock.lock(); // Lock only for visibility, not mutual exclusion
+        try {
+            int i = 0;
+            try {
+                for (E e : c)
+                    items[i++] = Objects.requireNonNull(e);
+            } catch (ArrayIndexOutOfBoundsException ex) {
+                throw new IllegalArgumentException();
+            }
+            count = i;
+            putIndex = (i == capacity) ? 0 : i;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue if it is
+     * possible to do so immediately without exceeding the queue's capacity,
+     * returning {@code true} upon success and throwing an
+     * {@code IllegalStateException} if this queue is full.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if this queue is full
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return super.add(e);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue if it is
+     * possible to do so immediately without exceeding the queue's capacity,
+     * returning {@code true} upon success and {@code false} if this queue
+     * is full.  This method is generally preferable to method {@link #add},
+     * which can fail to insert an element only by throwing an exception.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        Objects.requireNonNull(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count == items.length)
+                return false;
+            else {
+                enqueue(e);
+                return true;
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting
+     * for space to become available if the queue is full.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        Objects.requireNonNull(e);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == items.length)
+                notFull.await();
+            enqueue(e);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting
+     * up to the specified wait time for space to become available if
+     * the queue is full.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+
+        Objects.requireNonNull(e);
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == items.length) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            enqueue(e);
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E poll() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (count == 0) ? null : dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E take() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == 0)
+                notEmpty.await();
+            return dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == 0) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            return dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E peek() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return itemAt(takeIndex); // null when queue is empty
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // this doc comment is overridden to remove the reference to collections
+    // greater in size than Integer.MAX_VALUE
+    /**
+     * Returns the number of elements in this queue.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // this doc comment is a modified copy of the inherited doc comment,
+    // without the reference to unlimited queues.
+    /**
+     * Returns the number of additional elements that this queue can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking. This is always equal to the initial capacity of this queue
+     * less the current {@code size} of this queue.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     */
+    public int remainingCapacity() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return items.length - count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.
+     * Returns {@code true} if this queue contained the specified element
+     * (or equivalently, if this queue changed as a result of the call).
+     *
+     * <p>Removal of interior elements in circular array based queues
+     * is an intrinsically slow and disruptive operation, so should
+     * be undertaken only in exceptional circumstances, ideally
+     * only when the queue is known not to be accessible by other
+     * threads.
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count > 0) {
+                final Object[] items = this.items;
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    if (o.equals(items[i])) {
+                        removeAt(i);
+                        return true;
+                    }
+                    if (++i == items.length) i = 0;
+                } while (i != putIndex);
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count > 0) {
+                final Object[] items = this.items;
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    if (o.equals(items[i]))
+                        return true;
+                    if (++i == items.length) i = 0;
+                } while (i != putIndex);
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] items = this.items;
+            final int end = takeIndex + count;
+            final Object[] a = Arrays.copyOfRange(items, takeIndex, end);
+            if (end != putIndex)
+                System.arraycopy(items, 0, a, items.length - takeIndex, putIndex);
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] items = this.items;
+            final int count = this.count;
+            final int firstLeg = Math.min(items.length - takeIndex, count);
+            if (a.length < count) {
+                a = (T[]) Arrays.copyOfRange(items, takeIndex, takeIndex + count,
+                                             a.getClass());
+            } else {
+                System.arraycopy(items, takeIndex, a, 0, firstLeg);
+                if (a.length > count)
+                    a[count] = null;
+            }
+            if (firstLeg < count)
+                System.arraycopy(items, 0, a, firstLeg, putIndex);
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * Atomically removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int k = count;
+            if (k > 0) {
+                final Object[] items = this.items;
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    items[i] = null;
+                    if (++i == items.length) i = 0;
+                } while (i != putIndex);
+                takeIndex = putIndex;
+                count = 0;
+                if (itrs != null)
+                    itrs.queueIsEmpty();
+                for (; k > 0 && lock.hasWaiters(notFull); k--)
+                    notFull.signal();
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        Objects.requireNonNull(c);
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final Object[] items = this.items;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = Math.min(maxElements, count);
+            int take = takeIndex;
+            int i = 0;
+            try {
+                while (i < n) {
+                    @SuppressWarnings("unchecked")
+                    E x = (E) items[take];
+                    c.add(x);
+                    items[take] = null;
+                    if (++take == items.length) take = 0;
+                    i++;
+                }
+                return n;
+            } finally {
+                // Restore invariants even if c.add() threw
+                if (i > 0) {
+                    count -= i;
+                    takeIndex = take;
+                    if (itrs != null) {
+                        if (count == 0)
+                            itrs.queueIsEmpty();
+                        else if (i > take)
+                            itrs.takeIndexWrapped();
+                    }
+                    for (; i > 0 && lock.hasWaiters(notFull); i--)
+                        notFull.signal();
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * Shared data between iterators and their queue, allowing queue
+     * modifications to update iterators when elements are removed.
+     *
+     * This adds a lot of complexity for the sake of correctly
+     * handling some uncommon operations, but the combination of
+     * circular-arrays and supporting interior removes (i.e., those
+     * not at head) would cause iterators to sometimes lose their
+     * places and/or (re)report elements they shouldn't.  To avoid
+     * this, when a queue has one or more iterators, it keeps iterator
+     * state consistent by:
+     *
+     * (1) keeping track of the number of "cycles", that is, the
+     *     number of times takeIndex has wrapped around to 0.
+     * (2) notifying all iterators via the callback removedAt whenever
+     *     an interior element is removed (and thus other elements may
+     *     be shifted).
+     *
+     * These suffice to eliminate iterator inconsistencies, but
+     * unfortunately add the secondary responsibility of maintaining
+     * the list of iterators.  We track all active iterators in a
+     * simple linked list (accessed only when the queue's lock is
+     * held) of weak references to Itr.  The list is cleaned up using
+     * 3 different mechanisms:
+     *
+     * (1) Whenever a new iterator is created, do some O(1) checking for
+     *     stale list elements.
+     *
+     * (2) Whenever takeIndex wraps around to 0, check for iterators
+     *     that have been unused for more than one wrap-around cycle.
+     *
+     * (3) Whenever the queue becomes empty, all iterators are notified
+     *     and this entire data structure is discarded.
+     *
+     * So in addition to the removedAt callback that is necessary for
+     * correctness, iterators have the shutdown and takeIndexWrapped
+     * callbacks that help remove stale iterators from the list.
+     *
+     * Whenever a list element is examined, it is expunged if either
+     * the GC has determined that the iterator is discarded, or if the
+     * iterator reports that it is "detached" (does not need any
+     * further state updates).  Overhead is maximal when takeIndex
+     * never advances, iterators are discarded before they are
+     * exhausted, and all removals are interior removes, in which case
+     * all stale iterators are discovered by the GC.  But even in this
+     * case we don't increase the amortized complexity.
+     *
+     * Care must be taken to keep list sweeping methods from
+     * reentrantly invoking another such method, causing subtle
+     * corruption bugs.
+     */
+    class Itrs {
+
+        /**
+         * Node in a linked list of weak iterator references.
+         */
+        private class Node extends WeakReference<Itr> {
+            Node next;
+
+            Node(Itr iterator, Node next) {
+                super(iterator);
+                this.next = next;
+            }
+        }
+
+        /** Incremented whenever takeIndex wraps around to 0 */
+        int cycles;
+
+        /** Linked list of weak iterator references */
+        private Node head;
+
+        /** Used to expunge stale iterators */
+        private Node sweeper;
+
+        private static final int SHORT_SWEEP_PROBES = 4;
+        private static final int LONG_SWEEP_PROBES = 16;
+
+        Itrs(Itr initial) {
+            register(initial);
+        }
+
+        /**
+         * Sweeps itrs, looking for and expunging stale iterators.
+         * If at least one was found, tries harder to find more.
+         * Called only from iterating thread.
+         *
+         * @param tryHarder whether to start in try-harder mode, because
+         * there is known to be at least one iterator to collect
+         */
+        void doSomeSweeping(boolean tryHarder) {
+            // assert lock.getHoldCount() == 1;
+            // assert head != null;
+            int probes = tryHarder ? LONG_SWEEP_PROBES : SHORT_SWEEP_PROBES;
+            Node o, p;
+            final Node sweeper = this.sweeper;
+            boolean passedGo;   // to limit search to one full sweep
+
+            if (sweeper == null) {
+                o = null;
+                p = head;
+                passedGo = true;
+            } else {
+                o = sweeper;
+                p = o.next;
+                passedGo = false;
+            }
+
+            for (; probes > 0; probes--) {
+                if (p == null) {
+                    if (passedGo)
+                        break;
+                    o = null;
+                    p = head;
+                    passedGo = true;
+                }
+                final Itr it = p.get();
+                final Node next = p.next;
+                if (it == null || it.isDetached()) {
+                    // found a discarded/exhausted iterator
+                    probes = LONG_SWEEP_PROBES; // "try harder"
+                    // unlink p
+                    p.clear();
+                    p.next = null;
+                    if (o == null) {
+                        head = next;
+                        if (next == null) {
+                            // We've run out of iterators to track; retire
+                            itrs = null;
+                            return;
+                        }
+                    }
+                    else
+                        o.next = next;
+                } else {
+                    o = p;
+                }
+                p = next;
+            }
+
+            this.sweeper = (p == null) ? null : o;
+        }
+
+        /**
+         * Adds a new iterator to the linked list of tracked iterators.
+         */
+        void register(Itr itr) {
+            // assert lock.getHoldCount() == 1;
+            head = new Node(itr, head);
+        }
+
+        /**
+         * Called whenever takeIndex wraps around to 0.
+         *
+         * Notifies all iterators, and expunges any that are now stale.
+         */
+        void takeIndexWrapped() {
+            // assert lock.getHoldCount() == 1;
+            cycles++;
+            for (Node o = null, p = head; p != null;) {
+                final Itr it = p.get();
+                final Node next = p.next;
+                if (it == null || it.takeIndexWrapped()) {
+                    // unlink p
+                    // assert it == null || it.isDetached();
+                    p.clear();
+                    p.next = null;
+                    if (o == null)
+                        head = next;
+                    else
+                        o.next = next;
+                } else {
+                    o = p;
+                }
+                p = next;
+            }
+            if (head == null)   // no more iterators to track
+                itrs = null;
+        }
+
+        /**
+         * Called whenever an interior remove (not at takeIndex) occurred.
+         *
+         * Notifies all iterators, and expunges any that are now stale.
+         */
+        void removedAt(int removedIndex) {
+            for (Node o = null, p = head; p != null;) {
+                final Itr it = p.get();
+                final Node next = p.next;
+                if (it == null || it.removedAt(removedIndex)) {
+                    // unlink p
+                    // assert it == null || it.isDetached();
+                    p.clear();
+                    p.next = null;
+                    if (o == null)
+                        head = next;
+                    else
+                        o.next = next;
+                } else {
+                    o = p;
+                }
+                p = next;
+            }
+            if (head == null)   // no more iterators to track
+                itrs = null;
+        }
+
+        /**
+         * Called whenever the queue becomes empty.
+         *
+         * Notifies all active iterators that the queue is empty,
+         * clears all weak refs, and unlinks the itrs datastructure.
+         */
+        void queueIsEmpty() {
+            // assert lock.getHoldCount() == 1;
+            for (Node p = head; p != null; p = p.next) {
+                Itr it = p.get();
+                if (it != null) {
+                    p.clear();
+                    it.shutdown();
+                }
+            }
+            head = null;
+            itrs = null;
+        }
+
+        /**
+         * Called whenever an element has been dequeued (at takeIndex).
+         */
+        void elementDequeued() {
+            // assert lock.getHoldCount() == 1;
+            if (count == 0)
+                queueIsEmpty();
+            else if (takeIndex == 0)
+                takeIndexWrapped();
+        }
+    }
+
+    /**
+     * Iterator for ArrayBlockingQueue.
+     *
+     * To maintain weak consistency with respect to puts and takes, we
+     * read ahead one slot, so as to not report hasNext true but then
+     * not have an element to return.
+     *
+     * We switch into "detached" mode (allowing prompt unlinking from
+     * itrs without help from the GC) when all indices are negative, or
+     * when hasNext returns false for the first time.  This allows the
+     * iterator to track concurrent updates completely accurately,
+     * except for the corner case of the user calling Iterator.remove()
+     * after hasNext() returned false.  Even in this case, we ensure
+     * that we don't remove the wrong element by keeping track of the
+     * expected element to remove, in lastItem.  Yes, we may fail to
+     * remove lastItem from the queue if it moved due to an interleaved
+     * interior remove while in detached mode.
+     */
+    private class Itr implements Iterator<E> {
+        /** Index to look for new nextItem; NONE at end */
+        private int cursor;
+
+        /** Element to be returned by next call to next(); null if none */
+        private E nextItem;
+
+        /** Index of nextItem; NONE if none, REMOVED if removed elsewhere */
+        private int nextIndex;
+
+        /** Last element returned; null if none or not detached. */
+        private E lastItem;
+
+        /** Index of lastItem, NONE if none, REMOVED if removed elsewhere */
+        private int lastRet;
+
+        /** Previous value of takeIndex, or DETACHED when detached */
+        private int prevTakeIndex;
+
+        /** Previous value of iters.cycles */
+        private int prevCycles;
+
+        /** Special index value indicating "not available" or "undefined" */
+        private static final int NONE = -1;
+
+        /**
+         * Special index value indicating "removed elsewhere", that is,
+         * removed by some operation other than a call to this.remove().
+         */
+        private static final int REMOVED = -2;
+
+        /** Special value for prevTakeIndex indicating "detached mode" */
+        private static final int DETACHED = -3;
+
+        Itr() {
+            // assert lock.getHoldCount() == 0;
+            lastRet = NONE;
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                if (count == 0) {
+                    // assert itrs == null;
+                    cursor = NONE;
+                    nextIndex = NONE;
+                    prevTakeIndex = DETACHED;
+                } else {
+                    final int takeIndex = ArrayBlockingQueue.this.takeIndex;
+                    prevTakeIndex = takeIndex;
+                    nextItem = itemAt(nextIndex = takeIndex);
+                    cursor = incCursor(takeIndex);
+                    if (itrs == null) {
+                        itrs = new Itrs(this);
+                    } else {
+                        itrs.register(this); // in this order
+                        itrs.doSomeSweeping(false);
+                    }
+                    prevCycles = itrs.cycles;
+                    // assert takeIndex >= 0;
+                    // assert prevTakeIndex == takeIndex;
+                    // assert nextIndex >= 0;
+                    // assert nextItem != null;
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        boolean isDetached() {
+            // assert lock.getHoldCount() == 1;
+            return prevTakeIndex < 0;
+        }
+
+        private int incCursor(int index) {
+            // assert lock.getHoldCount() == 1;
+            if (++index == items.length) index = 0;
+            if (index == putIndex) index = NONE;
+            return index;
+        }
+
+        /**
+         * Returns true if index is invalidated by the given number of
+         * dequeues, starting from prevTakeIndex.
+         */
+        private boolean invalidated(int index, int prevTakeIndex,
+                                    long dequeues, int length) {
+            if (index < 0)
+                return false;
+            int distance = index - prevTakeIndex;
+            if (distance < 0)
+                distance += length;
+            return dequeues > distance;
+        }
+
+        /**
+         * Adjusts indices to incorporate all dequeues since the last
+         * operation on this iterator.  Call only from iterating thread.
+         */
+        private void incorporateDequeues() {
+            // assert lock.getHoldCount() == 1;
+            // assert itrs != null;
+            // assert !isDetached();
+            // assert count > 0;
+
+            final int cycles = itrs.cycles;
+            final int takeIndex = ArrayBlockingQueue.this.takeIndex;
+            final int prevCycles = this.prevCycles;
+            final int prevTakeIndex = this.prevTakeIndex;
+
+            if (cycles != prevCycles || takeIndex != prevTakeIndex) {
+                final int len = items.length;
+                // how far takeIndex has advanced since the previous
+                // operation of this iterator
+                long dequeues = (cycles - prevCycles) * len
+                    + (takeIndex - prevTakeIndex);
+
+                // Check indices for invalidation
+                if (invalidated(lastRet, prevTakeIndex, dequeues, len))
+                    lastRet = REMOVED;
+                if (invalidated(nextIndex, prevTakeIndex, dequeues, len))
+                    nextIndex = REMOVED;
+                if (invalidated(cursor, prevTakeIndex, dequeues, len))
+                    cursor = takeIndex;
+
+                if (cursor < 0 && nextIndex < 0 && lastRet < 0)
+                    detach();
+                else {
+                    this.prevCycles = cycles;
+                    this.prevTakeIndex = takeIndex;
+                }
+            }
+        }
+
+        /**
+         * Called when itrs should stop tracking this iterator, either
+         * because there are no more indices to update (cursor < 0 &&
+         * nextIndex < 0 && lastRet < 0) or as a special exception, when
+         * lastRet >= 0, because hasNext() is about to return false for the
+         * first time.  Call only from iterating thread.
+         */
+        private void detach() {
+            // Switch to detached mode
+            // assert lock.getHoldCount() == 1;
+            // assert cursor == NONE;
+            // assert nextIndex < 0;
+            // assert lastRet < 0 || nextItem == null;
+            // assert lastRet < 0 ^ lastItem != null;
+            if (prevTakeIndex >= 0) {
+                // assert itrs != null;
+                prevTakeIndex = DETACHED;
+                // try to unlink from itrs (but not too hard)
+                itrs.doSomeSweeping(true);
+            }
+        }
+
+        /**
+         * For performance reasons, we would like not to acquire a lock in
+         * hasNext in the common case.  To allow for this, we only access
+         * fields (i.e. nextItem) that are not modified by update operations
+         * triggered by queue modifications.
+         */
+        public boolean hasNext() {
+            // assert lock.getHoldCount() == 0;
+            if (nextItem != null)
+                return true;
+            noNext();
+            return false;
+        }
+
+        private void noNext() {
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                // assert cursor == NONE;
+                // assert nextIndex == NONE;
+                if (!isDetached()) {
+                    // assert lastRet >= 0;
+                    incorporateDequeues(); // might update lastRet
+                    if (lastRet >= 0) {
+                        lastItem = itemAt(lastRet);
+                        // assert lastItem != null;
+                        detach();
+                    }
+                }
+                // assert isDetached();
+                // assert lastRet < 0 ^ lastItem != null;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public E next() {
+            // assert lock.getHoldCount() == 0;
+            final E x = nextItem;
+            if (x == null)
+                throw new NoSuchElementException();
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                if (!isDetached())
+                    incorporateDequeues();
+                // assert nextIndex != NONE;
+                // assert lastItem == null;
+                lastRet = nextIndex;
+                final int cursor = this.cursor;
+                if (cursor >= 0) {
+                    nextItem = itemAt(nextIndex = cursor);
+                    // assert nextItem != null;
+                    this.cursor = incCursor(cursor);
+                } else {
+                    nextIndex = NONE;
+                    nextItem = null;
+                }
+            } finally {
+                lock.unlock();
+            }
+            return x;
+        }
+
+        public void remove() {
+            // assert lock.getHoldCount() == 0;
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                if (!isDetached())
+                    incorporateDequeues(); // might update lastRet or detach
+                final int lastRet = this.lastRet;
+                this.lastRet = NONE;
+                if (lastRet >= 0) {
+                    if (!isDetached())
+                        removeAt(lastRet);
+                    else {
+                        final E lastItem = this.lastItem;
+                        // assert lastItem != null;
+                        this.lastItem = null;
+                        if (itemAt(lastRet) == lastItem)
+                            removeAt(lastRet);
+                    }
+                } else if (lastRet == NONE)
+                    throw new IllegalStateException();
+                // else lastRet == REMOVED and the last returned element was
+                // previously asynchronously removed via an operation other
+                // than this.remove(), so nothing to do.
+
+                if (cursor < 0 && nextIndex < 0)
+                    detach();
+            } finally {
+                lock.unlock();
+                // assert lastRet == NONE;
+                // assert lastItem == null;
+            }
+        }
+
+        /**
+         * Called to notify the iterator that the queue is empty, or that it
+         * has fallen hopelessly behind, so that it should abandon any
+         * further iteration, except possibly to return one more element
+         * from next(), as promised by returning true from hasNext().
+         */
+        void shutdown() {
+            // assert lock.getHoldCount() == 1;
+            cursor = NONE;
+            if (nextIndex >= 0)
+                nextIndex = REMOVED;
+            if (lastRet >= 0) {
+                lastRet = REMOVED;
+                lastItem = null;
+            }
+            prevTakeIndex = DETACHED;
+            // Don't set nextItem to null because we must continue to be
+            // able to return it on next().
+            //
+            // Caller will unlink from itrs when convenient.
+        }
+
+        private int distance(int index, int prevTakeIndex, int length) {
+            int distance = index - prevTakeIndex;
+            if (distance < 0)
+                distance += length;
+            return distance;
+        }
+
+        /**
+         * Called whenever an interior remove (not at takeIndex) occurred.
+         *
+         * @return true if this iterator should be unlinked from itrs
+         */
+        boolean removedAt(int removedIndex) {
+            // assert lock.getHoldCount() == 1;
+            if (isDetached())
+                return true;
+
+            final int takeIndex = ArrayBlockingQueue.this.takeIndex;
+            final int prevTakeIndex = this.prevTakeIndex;
+            final int len = items.length;
+            // distance from prevTakeIndex to removedIndex
+            final int removedDistance =
+                len * (itrs.cycles - this.prevCycles
+                       + ((removedIndex < takeIndex) ? 1 : 0))
+                + (removedIndex - prevTakeIndex);
+            // assert itrs.cycles - this.prevCycles >= 0;
+            // assert itrs.cycles - this.prevCycles <= 1;
+            // assert removedDistance > 0;
+            // assert removedIndex != takeIndex;
+            int cursor = this.cursor;
+            if (cursor >= 0) {
+                int x = distance(cursor, prevTakeIndex, len);
+                if (x == removedDistance) {
+                    if (cursor == putIndex)
+                        this.cursor = cursor = NONE;
+                }
+                else if (x > removedDistance) {
+                    // assert cursor != prevTakeIndex;
+                    this.cursor = cursor = dec(cursor);
+                }
+            }
+            int lastRet = this.lastRet;
+            if (lastRet >= 0) {
+                int x = distance(lastRet, prevTakeIndex, len);
+                if (x == removedDistance)
+                    this.lastRet = lastRet = REMOVED;
+                else if (x > removedDistance)
+                    this.lastRet = lastRet = dec(lastRet);
+            }
+            int nextIndex = this.nextIndex;
+            if (nextIndex >= 0) {
+                int x = distance(nextIndex, prevTakeIndex, len);
+                if (x == removedDistance)
+                    this.nextIndex = nextIndex = REMOVED;
+                else if (x > removedDistance)
+                    this.nextIndex = nextIndex = dec(nextIndex);
+            }
+            if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
+                this.prevTakeIndex = DETACHED;
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Called whenever takeIndex wraps around to zero.
+         *
+         * @return true if this iterator should be unlinked from itrs
+         */
+        boolean takeIndexWrapped() {
+            // assert lock.getHoldCount() == 1;
+            if (isDetached())
+                return true;
+            if (itrs.cycles - prevCycles > 1) {
+                // All the elements that existed at the time of the last
+                // operation are gone, so abandon further iteration.
+                shutdown();
+                return true;
+            }
+            return false;
+        }
+
+//         /** Uncomment for debugging. */
+//         public String toString() {
+//             return ("cursor=" + cursor + " " +
+//                     "nextIndex=" + nextIndex + " " +
+//                     "lastRet=" + lastRet + " " +
+//                     "nextItem=" + nextItem + " " +
+//                     "lastItem=" + lastItem + " " +
+//                     "prevCycles=" + prevCycles + " " +
+//                     "prevTakeIndex=" + prevTakeIndex + " " +
+//                     "size()=" + size() + " " +
+//                     "remainingCapacity()=" + remainingCapacity());
+//         }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator
+            (this, (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT));
+    }
+
+}
diff --git a/java/util/concurrent/BlockingDeque.java b/java/util/concurrent/BlockingDeque.java
new file mode 100644
index 0000000..290fee1
--- /dev/null
+++ b/java/util/concurrent/BlockingDeque.java
@@ -0,0 +1,658 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+// BEGIN android-note
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
+/**
+ * A {@link Deque} that additionally supports blocking operations that wait
+ * for the deque to become non-empty when retrieving an element, and wait for
+ * space to become available in the deque when storing an element.
+ *
+ * <p>{@code BlockingDeque} methods come in four forms, with different ways
+ * of handling operations that cannot be satisfied immediately, but may be
+ * satisfied at some point in the future:
+ * one throws an exception, the second returns a special value (either
+ * {@code null} or {@code false}, depending on the operation), the third
+ * blocks the current thread indefinitely until the operation can succeed,
+ * and the fourth blocks for only a given maximum time limit before giving
+ * up.  These methods are summarized in the following table:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of BlockingDeque methods</caption>
+ *  <tr>
+ *    <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *    <td ALIGN=CENTER><em>Blocks</em></td>
+ *    <td ALIGN=CENTER><em>Times out</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link #addFirst addFirst(e)}</td>
+ *    <td>{@link #offerFirst(Object) offerFirst(e)}</td>
+ *    <td>{@link #putFirst putFirst(e)}</td>
+ *    <td>{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link #removeFirst removeFirst()}</td>
+ *    <td>{@link #pollFirst pollFirst()}</td>
+ *    <td>{@link #takeFirst takeFirst()}</td>
+ *    <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link #getFirst getFirst()}</td>
+ *    <td>{@link #peekFirst peekFirst()}</td>
+ *    <td><em>not applicable</em></td>
+ *    <td><em>not applicable</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td ALIGN=CENTER COLSPAN = 5> <b>Last Element (Tail)</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *    <td ALIGN=CENTER><em>Blocks</em></td>
+ *    <td ALIGN=CENTER><em>Times out</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link #addLast addLast(e)}</td>
+ *    <td>{@link #offerLast(Object) offerLast(e)}</td>
+ *    <td>{@link #putLast putLast(e)}</td>
+ *    <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link #removeLast() removeLast()}</td>
+ *    <td>{@link #pollLast() pollLast()}</td>
+ *    <td>{@link #takeLast takeLast()}</td>
+ *    <td>{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link #getLast getLast()}</td>
+ *    <td>{@link #peekLast peekLast()}</td>
+ *    <td><em>not applicable</em></td>
+ *    <td><em>not applicable</em></td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Like any {@link BlockingQueue}, a {@code BlockingDeque} is thread safe,
+ * does not permit null elements, and may (or may not) be
+ * capacity-constrained.
+ *
+ * <p>A {@code BlockingDeque} implementation may be used directly as a FIFO
+ * {@code BlockingQueue}. The methods inherited from the
+ * {@code BlockingQueue} interface are precisely equivalent to
+ * {@code BlockingDeque} methods as indicated in the following table:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Comparison of BlockingQueue and BlockingDeque methods</caption>
+ *  <tr>
+ *    <td ALIGN=CENTER> <b>{@code BlockingQueue} Method</b></td>
+ *    <td ALIGN=CENTER> <b>Equivalent {@code BlockingDeque} Method</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #add(Object) add(e)}</td>
+ *    <td>{@link #addLast(Object) addLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #offer(Object) offer(e)}</td>
+ *    <td>{@link #offerLast(Object) offerLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #put(Object) put(e)}</td>
+ *    <td>{@link #putLast(Object) putLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
+ *    <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>Remove</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #remove() remove()}</td>
+ *    <td>{@link #removeFirst() removeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #poll() poll()}</td>
+ *    <td>{@link #pollFirst() pollFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #take() take()}</td>
+ *    <td>{@link #takeFirst() takeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
+ *    <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>Examine</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #element() element()}</td>
+ *    <td>{@link #getFirst() getFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #peek() peek()}</td>
+ *    <td>{@link #peekFirst() peekFirst()}</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code BlockingDeque}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code BlockingDeque} in another thread.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ * @param <E> the type of elements held in this deque
+ */
+public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
+    /*
+     * We have "diamond" multiple interface inheritance here, and that
+     * introduces ambiguities.  Methods might end up with different
+     * specs depending on the branch chosen by javadoc.  Thus a lot of
+     * methods specs here are copied from superinterfaces.
+     */
+
+    /**
+     * Inserts the specified element at the front of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use {@link #offerFirst(Object) offerFirst}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    void addFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use {@link #offerLast(Object) offerLast}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    void addLast(E e);
+
+    /**
+     * Inserts the specified element at the front of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * returning {@code true} upon success and {@code false} if no space is
+     * currently available.
+     * When using a capacity-restricted deque, this method is generally
+     * preferable to the {@link #addFirst(Object) addFirst} method, which can
+     * fail to insert an element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    boolean offerFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * returning {@code true} upon success and {@code false} if no space is
+     * currently available.
+     * When using a capacity-restricted deque, this method is generally
+     * preferable to the {@link #addLast(Object) addLast} method, which can
+     * fail to insert an element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    boolean offerLast(E e);
+
+    /**
+     * Inserts the specified element at the front of this deque,
+     * waiting if necessary for space to become available.
+     *
+     * @param e the element to add
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void putFirst(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element at the end of this deque,
+     * waiting if necessary for space to become available.
+     *
+     * @param e the element to add
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void putLast(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element at the front of this deque,
+     * waiting up to the specified wait time if necessary for space to
+     * become available.
+     *
+     * @param e the element to add
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before space is available
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerFirst(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Inserts the specified element at the end of this deque,
+     * waiting up to the specified wait time if necessary for space to
+     * become available.
+     *
+     * @param e the element to add
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before space is available
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerLast(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the first element of this deque, waiting
+     * if necessary until an element becomes available.
+     *
+     * @return the head of this deque
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E takeFirst() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the last element of this deque, waiting
+     * if necessary until an element becomes available.
+     *
+     * @return the tail of this deque
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E takeLast() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the first element of this deque, waiting
+     * up to the specified wait time if necessary for an element to
+     * become available.
+     *
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the head of this deque, or {@code null} if the specified
+     *         waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E pollFirst(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the last element of this deque, waiting
+     * up to the specified wait time if necessary for an element to
+     * become available.
+     *
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the tail of this deque, or {@code null} if the specified
+     *         waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E pollLast(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if an element was removed as a result of this call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean removeFirstOccurrence(Object o);
+
+    /**
+     * Removes the last occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if an element was removed as a result of this call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean removeLastOccurrence(Object o);
+
+    // *** BlockingQueue methods ***
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     * When using a capacity-restricted deque, it is generally preferable to
+     * use {@link #offer(Object) offer}.
+     *
+     * <p>This method is equivalent to {@link #addLast(Object) addLast}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean add(E e);
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and {@code false} if no space is currently
+     * available.  When using a capacity-restricted deque, this method is
+     * generally preferable to the {@link #add} method, which can fail to
+     * insert an element only by throwing an exception.
+     *
+     * <p>This method is equivalent to {@link #offerLast(Object) offerLast}.
+     *
+     * @param e the element to add
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offer(E e);
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque), waiting if necessary for
+     * space to become available.
+     *
+     * <p>This method is equivalent to {@link #putLast(Object) putLast}.
+     *
+     * @param e the element to add
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void put(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque), waiting up to the
+     * specified wait time if necessary for space to become available.
+     *
+     * <p>This method is equivalent to
+     * {@link #offerLast(Object,long,TimeUnit) offerLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque).
+     * This method differs from {@link #poll poll} only in that it
+     * throws an exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E remove();
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), or returns
+     * {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #pollFirst()}.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E poll();
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), waiting if
+     * necessary until an element becomes available.
+     *
+     * <p>This method is equivalent to {@link #takeFirst() takeFirst}.
+     *
+     * @return the head of this deque
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E take() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), waiting up to the
+     * specified wait time if necessary for an element to become available.
+     *
+     * <p>This method is equivalent to
+     * {@link #pollFirst(long,TimeUnit) pollFirst}.
+     *
+     * @return the head of this deque, or {@code null} if the
+     *         specified waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E poll(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque).
+     * This method differs from {@link #peek peek} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst() getFirst}.
+     *
+     * @return the head of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E element();
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque), or
+     * returns {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #peekFirst() peekFirst}.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E peek();
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to
+     * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean remove(Object o);
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this deque
+     * @return {@code true} if this deque contains the specified element
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    int size();
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    Iterator<E> iterator();
+
+    // *** Stack methods ***
+
+    /**
+     * Pushes an element onto the stack represented by this deque (in other
+     * words, at the head of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     *
+     * <p>This method is equivalent to {@link #addFirst(Object) addFirst}.
+     *
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    void push(E e);
+}
diff --git a/java/util/concurrent/BlockingQueue.java b/java/util/concurrent/BlockingQueue.java
new file mode 100644
index 0000000..6f01b77
--- /dev/null
+++ b/java/util/concurrent/BlockingQueue.java
@@ -0,0 +1,377 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+import java.util.Queue;
+
+// BEGIN android-note
+// removed link to collections framework docs from header
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
+/**
+ * A {@link java.util.Queue} that additionally supports operations
+ * that wait for the queue to become non-empty when retrieving an
+ * element, and wait for space to become available in the queue when
+ * storing an element.
+ *
+ * <p>{@code BlockingQueue} methods come in four forms, with different ways
+ * of handling operations that cannot be satisfied immediately, but may be
+ * satisfied at some point in the future:
+ * one throws an exception, the second returns a special value (either
+ * {@code null} or {@code false}, depending on the operation), the third
+ * blocks the current thread indefinitely until the operation can succeed,
+ * and the fourth blocks for only a given maximum time limit before giving
+ * up.  These methods are summarized in the following table:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of BlockingQueue methods</caption>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *    <td ALIGN=CENTER><em>Blocks</em></td>
+ *    <td ALIGN=CENTER><em>Times out</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link #add add(e)}</td>
+ *    <td>{@link #offer offer(e)}</td>
+ *    <td>{@link #put put(e)}</td>
+ *    <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link #remove remove()}</td>
+ *    <td>{@link #poll poll()}</td>
+ *    <td>{@link #take take()}</td>
+ *    <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link #element element()}</td>
+ *    <td>{@link #peek peek()}</td>
+ *    <td><em>not applicable</em></td>
+ *    <td><em>not applicable</em></td>
+ *  </tr>
+ * </table>
+ *
+ * <p>A {@code BlockingQueue} does not accept {@code null} elements.
+ * Implementations throw {@code NullPointerException} on attempts
+ * to {@code add}, {@code put} or {@code offer} a {@code null}.  A
+ * {@code null} is used as a sentinel value to indicate failure of
+ * {@code poll} operations.
+ *
+ * <p>A {@code BlockingQueue} may be capacity bounded. At any given
+ * time it may have a {@code remainingCapacity} beyond which no
+ * additional elements can be {@code put} without blocking.
+ * A {@code BlockingQueue} without any intrinsic capacity constraints always
+ * reports a remaining capacity of {@code Integer.MAX_VALUE}.
+ *
+ * <p>{@code BlockingQueue} implementations are designed to be used
+ * primarily for producer-consumer queues, but additionally support
+ * the {@link java.util.Collection} interface.  So, for example, it is
+ * possible to remove an arbitrary element from a queue using
+ * {@code remove(x)}. However, such operations are in general
+ * <em>not</em> performed very efficiently, and are intended for only
+ * occasional use, such as when a queued message is cancelled.
+ *
+ * <p>{@code BlockingQueue} implementations are thread-safe.  All
+ * queuing methods achieve their effects atomically using internal
+ * locks or other forms of concurrency control. However, the
+ * <em>bulk</em> Collection operations {@code addAll},
+ * {@code containsAll}, {@code retainAll} and {@code removeAll} are
+ * <em>not</em> necessarily performed atomically unless specified
+ * otherwise in an implementation. So it is possible, for example, for
+ * {@code addAll(c)} to fail (throwing an exception) after adding
+ * only some of the elements in {@code c}.
+ *
+ * <p>A {@code BlockingQueue} does <em>not</em> intrinsically support
+ * any kind of &quot;close&quot; or &quot;shutdown&quot; operation to
+ * indicate that no more items will be added.  The needs and usage of
+ * such features tend to be implementation-dependent. For example, a
+ * common tactic is for producers to insert special
+ * <em>end-of-stream</em> or <em>poison</em> objects, that are
+ * interpreted accordingly when taken by consumers.
+ *
+ * <p>
+ * Usage example, based on a typical producer-consumer scenario.
+ * Note that a {@code BlockingQueue} can safely be used with multiple
+ * producers and multiple consumers.
+ * <pre> {@code
+ * class Producer implements Runnable {
+ *   private final BlockingQueue queue;
+ *   Producer(BlockingQueue q) { queue = q; }
+ *   public void run() {
+ *     try {
+ *       while (true) { queue.put(produce()); }
+ *     } catch (InterruptedException ex) { ... handle ...}
+ *   }
+ *   Object produce() { ... }
+ * }
+ *
+ * class Consumer implements Runnable {
+ *   private final BlockingQueue queue;
+ *   Consumer(BlockingQueue q) { queue = q; }
+ *   public void run() {
+ *     try {
+ *       while (true) { consume(queue.take()); }
+ *     } catch (InterruptedException ex) { ... handle ...}
+ *   }
+ *   void consume(Object x) { ... }
+ * }
+ *
+ * class Setup {
+ *   void main() {
+ *     BlockingQueue q = new SomeQueueImplementation();
+ *     Producer p = new Producer(q);
+ *     Consumer c1 = new Consumer(q);
+ *     Consumer c2 = new Consumer(q);
+ *     new Thread(p).start();
+ *     new Thread(c1).start();
+ *     new Thread(c2).start();
+ *   }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code BlockingQueue}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code BlockingQueue} in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public interface BlockingQueue<E> extends Queue<E> {
+    /**
+     * Inserts the specified element into this queue if it is possible to do
+     * so immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     * When using a capacity-restricted queue, it is generally preferable to
+     * use {@link #offer(Object) offer}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean add(E e);
+
+    /**
+     * Inserts the specified element into this queue if it is possible to do
+     * so immediately without violating capacity restrictions, returning
+     * {@code true} upon success and {@code false} if no space is currently
+     * available.  When using a capacity-restricted queue, this method is
+     * generally preferable to {@link #add}, which can fail to insert an
+     * element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this queue, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean offer(E e);
+
+    /**
+     * Inserts the specified element into this queue, waiting if necessary
+     * for space to become available.
+     *
+     * @param e the element to add
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    void put(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element into this queue, waiting up to the
+     * specified wait time if necessary for space to become available.
+     *
+     * @param e the element to add
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before space is available
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * until an element becomes available.
+     *
+     * @return the head of this queue
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E take() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of this queue, waiting up to the
+     * specified wait time if necessary for an element to become available.
+     *
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the head of this queue, or {@code null} if the
+     *         specified waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E poll(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Returns the number of additional elements that this queue can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking, or {@code Integer.MAX_VALUE} if there is no intrinsic
+     * limit.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     *
+     * @return the remaining capacity
+     */
+    int remainingCapacity();
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.
+     * Returns {@code true} if this queue contained the specified element
+     * (or equivalently, if this queue changed as a result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this queue
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean remove(Object o);
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this queue
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Removes all available elements from this queue and adds them
+     * to the given collection.  This operation may be more
+     * efficient than repeatedly polling this queue.  A failure
+     * encountered while attempting to add elements to
+     * collection {@code c} may result in elements being in neither,
+     * either or both collections when the associated exception is
+     * thrown.  Attempts to drain a queue to itself result in
+     * {@code IllegalArgumentException}. Further, the behavior of
+     * this operation is undefined if the specified collection is
+     * modified while the operation is in progress.
+     *
+     * @param c the collection to transfer elements into
+     * @return the number of elements transferred
+     * @throws UnsupportedOperationException if addition of elements
+     *         is not supported by the specified collection
+     * @throws ClassCastException if the class of an element of this queue
+     *         prevents it from being added to the specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @throws IllegalArgumentException if the specified collection is this
+     *         queue, or some property of an element of this queue prevents
+     *         it from being added to the specified collection
+     */
+    int drainTo(Collection<? super E> c);
+
+    /**
+     * Removes at most the given number of available elements from
+     * this queue and adds them to the given collection.  A failure
+     * encountered while attempting to add elements to
+     * collection {@code c} may result in elements being in neither,
+     * either or both collections when the associated exception is
+     * thrown.  Attempts to drain a queue to itself result in
+     * {@code IllegalArgumentException}. Further, the behavior of
+     * this operation is undefined if the specified collection is
+     * modified while the operation is in progress.
+     *
+     * @param c the collection to transfer elements into
+     * @param maxElements the maximum number of elements to transfer
+     * @return the number of elements transferred
+     * @throws UnsupportedOperationException if addition of elements
+     *         is not supported by the specified collection
+     * @throws ClassCastException if the class of an element of this queue
+     *         prevents it from being added to the specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @throws IllegalArgumentException if the specified collection is this
+     *         queue, or some property of an element of this queue prevents
+     *         it from being added to the specified collection
+     */
+    int drainTo(Collection<? super E> c, int maxElements);
+}
diff --git a/java/util/concurrent/BrokenBarrierException.java b/java/util/concurrent/BrokenBarrierException.java
new file mode 100644
index 0000000..11f126e
--- /dev/null
+++ b/java/util/concurrent/BrokenBarrierException.java
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when a thread tries to wait upon a barrier that is
+ * in a broken state, or which enters the broken state while the thread
+ * is waiting.
+ *
+ * @see CyclicBarrier
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class BrokenBarrierException extends Exception {
+    private static final long serialVersionUID = 7117394618823254244L;
+
+    /**
+     * Constructs a {@code BrokenBarrierException} with no specified detail
+     * message.
+     */
+    public BrokenBarrierException() {}
+
+    /**
+     * Constructs a {@code BrokenBarrierException} with the specified
+     * detail message.
+     *
+     * @param message the detail message
+     */
+    public BrokenBarrierException(String message) {
+        super(message);
+    }
+}
diff --git a/java/util/concurrent/Callable.java b/java/util/concurrent/Callable.java
new file mode 100644
index 0000000..04bc607
--- /dev/null
+++ b/java/util/concurrent/Callable.java
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A task that returns a result and may throw an exception.
+ * Implementors define a single method with no arguments called
+ * {@code call}.
+ *
+ * <p>The {@code Callable} interface is similar to {@link
+ * java.lang.Runnable}, in that both are designed for classes whose
+ * instances are potentially executed by another thread.  A
+ * {@code Runnable}, however, does not return a result and cannot
+ * throw a checked exception.
+ *
+ * <p>The {@link Executors} class contains utility methods to
+ * convert from other common forms to {@code Callable} classes.
+ *
+ * @see Executor
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> the result type of method {@code call}
+ */
+@FunctionalInterface
+public interface Callable<V> {
+    /**
+     * Computes a result, or throws an exception if unable to do so.
+     *
+     * @return computed result
+     * @throws Exception if unable to compute a result
+     */
+    V call() throws Exception;
+}
diff --git a/java/util/concurrent/CancellationException.java b/java/util/concurrent/CancellationException.java
new file mode 100644
index 0000000..bd35173
--- /dev/null
+++ b/java/util/concurrent/CancellationException.java
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception indicating that the result of a value-producing task,
+ * such as a {@link FutureTask}, cannot be retrieved because the task
+ * was cancelled.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class CancellationException extends IllegalStateException {
+    private static final long serialVersionUID = -9202173006928992231L;
+
+    /**
+     * Constructs a {@code CancellationException} with no detail message.
+     */
+    public CancellationException() {}
+
+    /**
+     * Constructs a {@code CancellationException} with the specified detail
+     * message.
+     *
+     * @param message the detail message
+     */
+    public CancellationException(String message) {
+        super(message);
+    }
+}
diff --git a/java/util/concurrent/CompletableFuture.annotated.java b/java/util/concurrent/CompletableFuture.annotated.java
new file mode 100644
index 0000000..5ac5a83
--- /dev/null
+++ b/java/util/concurrent/CompletableFuture.annotated.java
@@ -0,0 +1,195 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+
+package java.util.concurrent;
+
+import java.util.function.Supplier;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class CompletableFuture<T> implements java.util.concurrent.Future<T>, java.util.concurrent.CompletionStage<T> {
+
+public CompletableFuture() { throw new RuntimeException("Stub!"); }
+
+public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U> supplier) { throw new RuntimeException("Stub!"); }
+
+public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U> supplier, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable runnable) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable runnable, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U value) { throw new RuntimeException("Stub!"); }
+
+public boolean isDone() { throw new RuntimeException("Stub!"); }
+
+public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException { throw new RuntimeException("Stub!"); }
+
+public T get(long timeout, java.util.concurrent.TimeUnit unit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException { throw new RuntimeException("Stub!"); }
+
+public T join() { throw new RuntimeException("Stub!"); }
+
+public T getNow(T valueIfAbsent) { throw new RuntimeException("Stub!"); }
+
+public boolean complete(T value) { throw new RuntimeException("Stub!"); }
+
+public boolean completeExceptionally(java.lang.Throwable ex) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T,? extends U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T,? extends U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T,? extends U> fn, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T> action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiFunction<? super T,? super U,? extends V> fn) { throw new RuntimeException("Stub!"); }
+
+public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiFunction<? super T,? super U,? extends V> fn) { throw new RuntimeException("Stub!"); }
+
+public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiFunction<? super T,? super U,? extends V> fn, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiConsumer<? super T,? super U> action) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiConsumer<? super T,? super U> action) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiConsumer<? super T,? super U> action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Function<? super T,U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Function<? super T,U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Function<? super T,U> fn, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Consumer<? super T> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Consumer<? super T> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Consumer<? super T> action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>> fn, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> whenComplete(java.util.function.BiConsumer<? super T,? super java.lang.Throwable> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T,? super java.lang.Throwable> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T,? super java.lang.Throwable> action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U> fn, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> toCompletableFuture() { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable,? extends T> fn) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>... cfs) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>... cfs) { throw new RuntimeException("Stub!"); }
+
+public boolean cancel(boolean mayInterruptIfRunning) { throw new RuntimeException("Stub!"); }
+
+public boolean isCancelled() { throw new RuntimeException("Stub!"); }
+
+public boolean isCompletedExceptionally() { throw new RuntimeException("Stub!"); }
+
+public void obtrudeValue(T value) { throw new RuntimeException("Stub!"); }
+
+public void obtrudeException(java.lang.Throwable ex) { throw new RuntimeException("Stub!"); }
+
+public int getNumberOfDependents() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> newIncompleteFuture() { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.Executor defaultExecutor() { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> copy() { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletionStage<T> minimalCompletionStage() { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> completeAsync(java.util.function.Supplier<? extends T> supplier, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> completeAsync(java.util.function.Supplier<? extends T> supplier) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> orTimeout(long timeout, java.util.concurrent.TimeUnit unit) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public java.util.concurrent.CompletableFuture<T> completeOnTimeout(T value, long timeout, java.util.concurrent.TimeUnit unit) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.Executor delayedExecutor(long delay, java.util.concurrent.TimeUnit unit, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.Executor delayedExecutor(long delay, java.util.concurrent.TimeUnit unit) { throw new RuntimeException("Stub!"); }
+
+public static <U> java.util.concurrent.CompletionStage<U> completedStage(U value) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static <U> java.util.concurrent.CompletableFuture<U> failedFuture(java.lang.Throwable ex) { throw new RuntimeException("Stub!"); }
+
+public static <U> java.util.concurrent.CompletionStage<U> failedStage(java.lang.Throwable ex) { throw new RuntimeException("Stub!"); }
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static interface AsynchronousCompletionTask {
+}
+
+}
diff --git a/java/util/concurrent/CompletableFuture.java b/java/util/concurrent/CompletableFuture.java
new file mode 100644
index 0000000..976bfe4
--- /dev/null
+++ b/java/util/concurrent/CompletableFuture.java
@@ -0,0 +1,2788 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.locks.LockSupport;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+// Android-note: Class javadoc changed to remove references to hidden OpenJDK 9 methods.
+
+/**
+ * A {@link Future} that may be explicitly completed (setting its
+ * value and status), and may be used as a {@link CompletionStage},
+ * supporting dependent functions and actions that trigger upon its
+ * completion.
+ *
+ * <p>When two or more threads attempt to
+ * {@link #complete complete},
+ * {@link #completeExceptionally completeExceptionally}, or
+ * {@link #cancel cancel}
+ * a CompletableFuture, only one of them succeeds.
+ *
+ * <p>In addition to these and related methods for directly
+ * manipulating status and results, CompletableFuture implements
+ * interface {@link CompletionStage} with the following policies: <ul>
+ *
+ * <li>Actions supplied for dependent completions of
+ * <em>non-async</em> methods may be performed by the thread that
+ * completes the current CompletableFuture, or by any other caller of
+ * a completion method.
+ *
+ * <li>All <em>async</em> methods without an explicit Executor
+ * argument are performed using the {@link ForkJoinPool#commonPool()}
+ * (unless it does not support a parallelism level of at least two, in
+ * which case, a new Thread is created to run each task).
+ * To simplify monitoring, debugging,
+ * and tracking, all generated asynchronous tasks are instances of the
+ * marker interface {@link AsynchronousCompletionTask}.  Operations
+ * with time-delays can use adapter methods defined in this class, for
+ * example: {@code supplyAsync(supplier, delayedExecutor(timeout,
+ * timeUnit))}.  To support methods with delays and timeouts, this
+ * class maintains at most one daemon thread for triggering and
+ * cancelling actions, not for running them.
+ *
+ * <li>All CompletionStage methods are implemented independently of
+ * other public methods, so the behavior of one method is not impacted
+ * by overrides of others in subclasses.
+ *
+ * </ul>
+ *
+ * <p>CompletableFuture also implements {@link Future} with the following
+ * policies: <ul>
+ *
+ * <li>Since (unlike {@link FutureTask}) this class has no direct
+ * control over the computation that causes it to be completed,
+ * cancellation is treated as just another form of exceptional
+ * completion.  Method {@link #cancel cancel} has the same effect as
+ * {@code completeExceptionally(new CancellationException())}. Method
+ * {@link #isCompletedExceptionally} can be used to determine if a
+ * CompletableFuture completed in any exceptional fashion.
+ *
+ * <li>In case of exceptional completion with a CompletionException,
+ * methods {@link #get()} and {@link #get(long, TimeUnit)} throw an
+ * {@link ExecutionException} with the same cause as held in the
+ * corresponding CompletionException.  To simplify usage in most
+ * contexts, this class also defines methods {@link #join()} and
+ * {@link #getNow} that instead throw the CompletionException directly
+ * in these cases.
+ * </ul>
+ *
+ * <p>Arguments used to pass a completion result (that is, for
+ * parameters of type {@code T}) for methods accepting them may be
+ * null, but passing a null value for any other parameter will result
+ * in a {@link NullPointerException} being thrown.
+ *
+ * @author Doug Lea
+ * @since 1.8
+ * @param <T> The result type returned by this future's {@code join}
+ * and {@code get} methods
+ */
+public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
+
+    /*
+     * Overview:
+     *
+     * A CompletableFuture may have dependent completion actions,
+     * collected in a linked stack. It atomically completes by CASing
+     * a result field, and then pops off and runs those actions. This
+     * applies across normal vs exceptional outcomes, sync vs async
+     * actions, binary triggers, and various forms of completions.
+     *
+     * Non-nullness of field result (set via CAS) indicates done.  An
+     * AltResult is used to box null as a result, as well as to hold
+     * exceptions.  Using a single field makes completion simple to
+     * detect and trigger.  Encoding and decoding is straightforward
+     * but adds to the sprawl of trapping and associating exceptions
+     * with targets.  Minor simplifications rely on (static) NIL (to
+     * box null results) being the only AltResult with a null
+     * exception field, so we don't usually need explicit comparisons.
+     * Even though some of the generics casts are unchecked (see
+     * SuppressWarnings annotations), they are placed to be
+     * appropriate even if checked.
+     *
+     * Dependent actions are represented by Completion objects linked
+     * as Treiber stacks headed by field "stack". There are Completion
+     * classes for each kind of action, grouped into single-input
+     * (UniCompletion), two-input (BiCompletion), projected
+     * (BiCompletions using either (not both) of two inputs), shared
+     * (CoCompletion, used by the second of two sources), zero-input
+     * source actions, and Signallers that unblock waiters. Class
+     * Completion extends ForkJoinTask to enable async execution
+     * (adding no space overhead because we exploit its "tag" methods
+     * to maintain claims). It is also declared as Runnable to allow
+     * usage with arbitrary executors.
+     *
+     * Support for each kind of CompletionStage relies on a separate
+     * class, along with two CompletableFuture methods:
+     *
+     * * A Completion class with name X corresponding to function,
+     *   prefaced with "Uni", "Bi", or "Or". Each class contains
+     *   fields for source(s), actions, and dependent. They are
+     *   boringly similar, differing from others only with respect to
+     *   underlying functional forms. We do this so that users don't
+     *   encounter layers of adapters in common usages.
+     *
+     * * Boolean CompletableFuture method x(...) (for example
+     *   uniApply) takes all of the arguments needed to check that an
+     *   action is triggerable, and then either runs the action or
+     *   arranges its async execution by executing its Completion
+     *   argument, if present. The method returns true if known to be
+     *   complete.
+     *
+     * * Completion method tryFire(int mode) invokes the associated x
+     *   method with its held arguments, and on success cleans up.
+     *   The mode argument allows tryFire to be called twice (SYNC,
+     *   then ASYNC); the first to screen and trap exceptions while
+     *   arranging to execute, and the second when called from a
+     *   task. (A few classes are not used async so take slightly
+     *   different forms.)  The claim() callback suppresses function
+     *   invocation if already claimed by another thread.
+     *
+     * * CompletableFuture method xStage(...) is called from a public
+     *   stage method of CompletableFuture x. It screens user
+     *   arguments and invokes and/or creates the stage object.  If
+     *   not async and x is already complete, the action is run
+     *   immediately.  Otherwise a Completion c is created, pushed to
+     *   x's stack (unless done), and started or triggered via
+     *   c.tryFire.  This also covers races possible if x completes
+     *   while pushing.  Classes with two inputs (for example BiApply)
+     *   deal with races across both while pushing actions.  The
+     *   second completion is a CoCompletion pointing to the first,
+     *   shared so that at most one performs the action.  The
+     *   multiple-arity methods allOf and anyOf do this pairwise to
+     *   form trees of completions.
+     *
+     * Note that the generic type parameters of methods vary according
+     * to whether "this" is a source, dependent, or completion.
+     *
+     * Method postComplete is called upon completion unless the target
+     * is guaranteed not to be observable (i.e., not yet returned or
+     * linked). Multiple threads can call postComplete, which
+     * atomically pops each dependent action, and tries to trigger it
+     * via method tryFire, in NESTED mode.  Triggering can propagate
+     * recursively, so NESTED mode returns its completed dependent (if
+     * one exists) for further processing by its caller (see method
+     * postFire).
+     *
+     * Blocking methods get() and join() rely on Signaller Completions
+     * that wake up waiting threads.  The mechanics are similar to
+     * Treiber stack wait-nodes used in FutureTask, Phaser, and
+     * SynchronousQueue. See their internal documentation for
+     * algorithmic details.
+     *
+     * Without precautions, CompletableFutures would be prone to
+     * garbage accumulation as chains of Completions build up, each
+     * pointing back to its sources. So we null out fields as soon as
+     * possible.  The screening checks needed anyway harmlessly ignore
+     * null arguments that may have been obtained during races with
+     * threads nulling out fields.  We also try to unlink fired
+     * Completions from stacks that might never be popped (see method
+     * postFire).  Completion fields need not be declared as final or
+     * volatile because they are only visible to other threads upon
+     * safe publication.
+     */
+
+    volatile Object result;       // Either the result or boxed AltResult
+    volatile Completion stack;    // Top of Treiber stack of dependent actions
+
+    final boolean internalComplete(Object r) { // CAS from null to r
+        return U.compareAndSwapObject(this, RESULT, null, r);
+    }
+
+    final boolean casStack(Completion cmp, Completion val) {
+        return U.compareAndSwapObject(this, STACK, cmp, val);
+    }
+
+    /** Returns true if successfully pushed c onto stack. */
+    final boolean tryPushStack(Completion c) {
+        Completion h = stack;
+        lazySetNext(c, h);
+        return U.compareAndSwapObject(this, STACK, h, c);
+    }
+
+    /** Unconditionally pushes c onto stack, retrying if necessary. */
+    final void pushStack(Completion c) {
+        do {} while (!tryPushStack(c));
+    }
+
+    /* ------------- Encoding and decoding outcomes -------------- */
+
+    static final class AltResult { // See above
+        final Throwable ex;        // null only for NIL
+        AltResult(Throwable x) { this.ex = x; }
+    }
+
+    /** The encoding of the null value. */
+    static final AltResult NIL = new AltResult(null);
+
+    /** Completes with the null value, unless already completed. */
+    final boolean completeNull() {
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      NIL);
+    }
+
+    /** Returns the encoding of the given non-exceptional value. */
+    final Object encodeValue(T t) {
+        return (t == null) ? NIL : t;
+    }
+
+    /** Completes with a non-exceptional result, unless already completed. */
+    final boolean completeValue(T t) {
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      (t == null) ? NIL : t);
+    }
+
+    /**
+     * Returns the encoding of the given (non-null) exception as a
+     * wrapped CompletionException unless it is one already.
+     */
+    static AltResult encodeThrowable(Throwable x) {
+        return new AltResult((x instanceof CompletionException) ? x :
+                             new CompletionException(x));
+    }
+
+    /** Completes with an exceptional result, unless already completed. */
+    final boolean completeThrowable(Throwable x) {
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      encodeThrowable(x));
+    }
+
+    /**
+     * Returns the encoding of the given (non-null) exception as a
+     * wrapped CompletionException unless it is one already.  May
+     * return the given Object r (which must have been the result of a
+     * source future) if it is equivalent, i.e. if this is a simple
+     * relay of an existing CompletionException.
+     */
+    static Object encodeThrowable(Throwable x, Object r) {
+        if (!(x instanceof CompletionException))
+            x = new CompletionException(x);
+        else if (r instanceof AltResult && x == ((AltResult)r).ex)
+            return r;
+        return new AltResult(x);
+    }
+
+    /**
+     * Completes with the given (non-null) exceptional result as a
+     * wrapped CompletionException unless it is one already, unless
+     * already completed.  May complete with the given Object r
+     * (which must have been the result of a source future) if it is
+     * equivalent, i.e. if this is a simple propagation of an
+     * existing CompletionException.
+     */
+    final boolean completeThrowable(Throwable x, Object r) {
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      encodeThrowable(x, r));
+    }
+
+    /**
+     * Returns the encoding of the given arguments: if the exception
+     * is non-null, encodes as AltResult.  Otherwise uses the given
+     * value, boxed as NIL if null.
+     */
+    Object encodeOutcome(T t, Throwable x) {
+        return (x == null) ? (t == null) ? NIL : t : encodeThrowable(x);
+    }
+
+    /**
+     * Returns the encoding of a copied outcome; if exceptional,
+     * rewraps as a CompletionException, else returns argument.
+     */
+    static Object encodeRelay(Object r) {
+        Throwable x;
+        return (((r instanceof AltResult) &&
+                 (x = ((AltResult)r).ex) != null &&
+                 !(x instanceof CompletionException)) ?
+                new AltResult(new CompletionException(x)) : r);
+    }
+
+    /**
+     * Completes with r or a copy of r, unless already completed.
+     * If exceptional, r is first coerced to a CompletionException.
+     */
+    final boolean completeRelay(Object r) {
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      encodeRelay(r));
+    }
+
+    /**
+     * Reports result using Future.get conventions.
+     */
+    private static <T> T reportGet(Object r)
+        throws InterruptedException, ExecutionException {
+        if (r == null) // by convention below, null means interrupted
+            throw new InterruptedException();
+        if (r instanceof AltResult) {
+            Throwable x, cause;
+            if ((x = ((AltResult)r).ex) == null)
+                return null;
+            if (x instanceof CancellationException)
+                throw (CancellationException)x;
+            if ((x instanceof CompletionException) &&
+                (cause = x.getCause()) != null)
+                x = cause;
+            throw new ExecutionException(x);
+        }
+        @SuppressWarnings("unchecked") T t = (T) r;
+        return t;
+    }
+
+    /**
+     * Decodes outcome to return result or throw unchecked exception.
+     */
+    private static <T> T reportJoin(Object r) {
+        if (r instanceof AltResult) {
+            Throwable x;
+            if ((x = ((AltResult)r).ex) == null)
+                return null;
+            if (x instanceof CancellationException)
+                throw (CancellationException)x;
+            if (x instanceof CompletionException)
+                throw (CompletionException)x;
+            throw new CompletionException(x);
+        }
+        @SuppressWarnings("unchecked") T t = (T) r;
+        return t;
+    }
+
+    /* ------------- Async task preliminaries -------------- */
+
+    /**
+     * A marker interface identifying asynchronous tasks produced by
+     * {@code async} methods. This may be useful for monitoring,
+     * debugging, and tracking asynchronous activities.
+     *
+     * @since 1.8
+     */
+    public static interface AsynchronousCompletionTask {
+    }
+
+    private static final boolean USE_COMMON_POOL =
+        (ForkJoinPool.getCommonPoolParallelism() > 1);
+
+    /**
+     * Default executor -- ForkJoinPool.commonPool() unless it cannot
+     * support parallelism.
+     */
+    private static final Executor ASYNC_POOL = USE_COMMON_POOL ?
+        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
+
+    /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
+    static final class ThreadPerTaskExecutor implements Executor {
+        public void execute(Runnable r) { new Thread(r).start(); }
+    }
+
+    /**
+     * Null-checks user executor argument, and translates uses of
+     * commonPool to ASYNC_POOL in case parallelism disabled.
+     */
+    static Executor screenExecutor(Executor e) {
+        if (!USE_COMMON_POOL && e == ForkJoinPool.commonPool())
+            return ASYNC_POOL;
+        if (e == null) throw new NullPointerException();
+        return e;
+    }
+
+    // Modes for Completion.tryFire. Signedness matters.
+    static final int SYNC   =  0;
+    static final int ASYNC  =  1;
+    static final int NESTED = -1;
+
+    /**
+     * Spins before blocking in waitingGet
+     */
+    static final int SPINS = (Runtime.getRuntime().availableProcessors() > 1 ?
+                              1 << 8 : 0);
+
+    /* ------------- Base Completion classes and operations -------------- */
+
+    @SuppressWarnings("serial")
+    abstract static class Completion extends ForkJoinTask<Void>
+        implements Runnable, AsynchronousCompletionTask {
+        volatile Completion next;      // Treiber stack link
+
+        /**
+         * Performs completion action if triggered, returning a
+         * dependent that may need propagation, if one exists.
+         *
+         * @param mode SYNC, ASYNC, or NESTED
+         */
+        abstract CompletableFuture<?> tryFire(int mode);
+
+        /** Returns true if possibly still triggerable. Used by cleanStack. */
+        abstract boolean isLive();
+
+        public final void run()                { tryFire(ASYNC); }
+        public final boolean exec()            { tryFire(ASYNC); return false; }
+        public final Void getRawResult()       { return null; }
+        public final void setRawResult(Void v) {}
+    }
+
+    static void lazySetNext(Completion c, Completion next) {
+        U.putOrderedObject(c, NEXT, next);
+    }
+
+    /**
+     * Pops and tries to trigger all reachable dependents.  Call only
+     * when known to be done.
+     */
+    final void postComplete() {
+        /*
+         * On each step, variable f holds current dependents to pop
+         * and run.  It is extended along only one path at a time,
+         * pushing others to avoid unbounded recursion.
+         */
+        CompletableFuture<?> f = this; Completion h;
+        while ((h = f.stack) != null ||
+               (f != this && (h = (f = this).stack) != null)) {
+            CompletableFuture<?> d; Completion t;
+            if (f.casStack(h, t = h.next)) {
+                if (t != null) {
+                    if (f != this) {
+                        pushStack(h);
+                        continue;
+                    }
+                    h.next = null;    // detach
+                }
+                f = (d = h.tryFire(NESTED)) == null ? this : d;
+            }
+        }
+    }
+
+    /** Traverses stack and unlinks dead Completions. */
+    final void cleanStack() {
+        for (Completion p = null, q = stack; q != null;) {
+            Completion s = q.next;
+            if (q.isLive()) {
+                p = q;
+                q = s;
+            }
+            else if (p == null) {
+                casStack(q, s);
+                q = stack;
+            }
+            else {
+                p.next = s;
+                if (p.isLive())
+                    q = s;
+                else {
+                    p = null;  // restart
+                    q = stack;
+                }
+            }
+        }
+    }
+
+    /* ------------- One-input Completions -------------- */
+
+    /** A Completion with a source, dependent, and executor. */
+    @SuppressWarnings("serial")
+    abstract static class UniCompletion<T,V> extends Completion {
+        Executor executor;                 // executor to use (null if none)
+        CompletableFuture<V> dep;          // the dependent to complete
+        CompletableFuture<T> src;          // source for action
+
+        UniCompletion(Executor executor, CompletableFuture<V> dep,
+                      CompletableFuture<T> src) {
+            this.executor = executor; this.dep = dep; this.src = src;
+        }
+
+        /**
+         * Returns true if action can be run. Call only when known to
+         * be triggerable. Uses FJ tag bit to ensure that only one
+         * thread claims ownership.  If async, starts as task -- a
+         * later call to tryFire will run action.
+         */
+        final boolean claim() {
+            Executor e = executor;
+            if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
+                if (e == null)
+                    return true;
+                executor = null; // disable
+                e.execute(this);
+            }
+            return false;
+        }
+
+        final boolean isLive() { return dep != null; }
+    }
+
+    /** Pushes the given completion (if it exists) unless done. */
+    final void push(UniCompletion<?,?> c) {
+        if (c != null) {
+            while (result == null && !tryPushStack(c))
+                lazySetNext(c, null); // clear on failure
+        }
+    }
+
+    /**
+     * Post-processing by dependent after successful UniCompletion
+     * tryFire.  Tries to clean stack of source a, and then either runs
+     * postComplete or returns this to caller, depending on mode.
+     */
+    final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
+        if (a != null && a.stack != null) {
+            if (mode < 0 || a.result == null)
+                a.cleanStack();
+            else
+                a.postComplete();
+        }
+        if (result != null && stack != null) {
+            if (mode < 0)
+                return this;
+            else
+                postComplete();
+        }
+        return null;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniApply<T,V> extends UniCompletion<T,V> {
+        Function<? super T,? extends V> fn;
+        UniApply(Executor executor, CompletableFuture<V> dep,
+                 CompletableFuture<T> src,
+                 Function<? super T,? extends V> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniApply(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniApply(CompletableFuture<S> a,
+                               Function<? super S,? extends T> f,
+                               UniApply<S,T> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                completeValue(f.apply(s));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <V> CompletableFuture<V> uniApplyStage(
+        Executor e, Function<? super T,? extends V> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (e != null || !d.uniApply(this, f, null)) {
+            UniApply<T,V> c = new UniApply<T,V>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniAccept<T> extends UniCompletion<T,Void> {
+        Consumer<? super T> fn;
+        UniAccept(Executor executor, CompletableFuture<Void> dep,
+                  CompletableFuture<T> src, Consumer<? super T> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniAccept(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniAccept(CompletableFuture<S> a,
+                                Consumer<? super S> f, UniAccept<S> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                f.accept(s);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> uniAcceptStage(Executor e,
+                                                   Consumer<? super T> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.uniAccept(this, f, null)) {
+            UniAccept<T> c = new UniAccept<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniRun<T> extends UniCompletion<T,Void> {
+        Runnable fn;
+        UniRun(Executor executor, CompletableFuture<Void> dep,
+               CompletableFuture<T> src, Runnable fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniRun(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniRun(CompletableFuture<?> a, Runnable f, UniRun<?> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else
+                try {
+                    if (c != null && !c.claim())
+                        return false;
+                    f.run();
+                    completeNull();
+                } catch (Throwable ex) {
+                    completeThrowable(ex);
+                }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.uniRun(this, f, null)) {
+            UniRun<T> c = new UniRun<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniWhenComplete<T> extends UniCompletion<T,T> {
+        BiConsumer<? super T, ? super Throwable> fn;
+        UniWhenComplete(Executor executor, CompletableFuture<T> dep,
+                        CompletableFuture<T> src,
+                        BiConsumer<? super T, ? super Throwable> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<T> tryFire(int mode) {
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniWhenComplete(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniWhenComplete(CompletableFuture<T> a,
+                                  BiConsumer<? super T,? super Throwable> f,
+                                  UniWhenComplete<T> c) {
+        Object r; T t; Throwable x = null;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    x = ((AltResult)r).ex;
+                    t = null;
+                } else {
+                    @SuppressWarnings("unchecked") T tr = (T) r;
+                    t = tr;
+                }
+                f.accept(t, x);
+                if (x == null) {
+                    internalComplete(r);
+                    return true;
+                }
+            } catch (Throwable ex) {
+                if (x == null)
+                    x = ex;
+                else if (x != ex)
+                    x.addSuppressed(ex);
+            }
+            completeThrowable(x, r);
+        }
+        return true;
+    }
+
+    private CompletableFuture<T> uniWhenCompleteStage(
+        Executor e, BiConsumer<? super T, ? super Throwable> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<T> d = newIncompleteFuture();
+        if (e != null || !d.uniWhenComplete(this, f, null)) {
+            UniWhenComplete<T> c = new UniWhenComplete<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniHandle<T,V> extends UniCompletion<T,V> {
+        BiFunction<? super T, Throwable, ? extends V> fn;
+        UniHandle(Executor executor, CompletableFuture<V> dep,
+                  CompletableFuture<T> src,
+                  BiFunction<? super T, Throwable, ? extends V> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniHandle(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniHandle(CompletableFuture<S> a,
+                                BiFunction<? super S, Throwable, ? extends T> f,
+                                UniHandle<S,T> c) {
+        Object r; S s; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    x = ((AltResult)r).ex;
+                    s = null;
+                } else {
+                    x = null;
+                    @SuppressWarnings("unchecked") S ss = (S) r;
+                    s = ss;
+                }
+                completeValue(f.apply(s, x));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <V> CompletableFuture<V> uniHandleStage(
+        Executor e, BiFunction<? super T, Throwable, ? extends V> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (e != null || !d.uniHandle(this, f, null)) {
+            UniHandle<T,V> c = new UniHandle<T,V>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniExceptionally<T> extends UniCompletion<T,T> {
+        Function<? super Throwable, ? extends T> fn;
+        UniExceptionally(CompletableFuture<T> dep, CompletableFuture<T> src,
+                         Function<? super Throwable, ? extends T> fn) {
+            super(null, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<T> tryFire(int mode) { // never ASYNC
+            // assert mode != ASYNC;
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            if ((d = dep) == null || !d.uniExceptionally(a = src, fn, this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniExceptionally(CompletableFuture<T> a,
+                                   Function<? super Throwable, ? extends T> f,
+                                   UniExceptionally<T> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) {
+                    if (c != null && !c.claim())
+                        return false;
+                    completeValue(f.apply(x));
+                } else
+                    internalComplete(r);
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private CompletableFuture<T> uniExceptionallyStage(
+        Function<Throwable, ? extends T> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<T> d = newIncompleteFuture();
+        if (!d.uniExceptionally(this, f, null)) {
+            UniExceptionally<T> c = new UniExceptionally<T>(d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniRelay<T> extends UniCompletion<T,T> { // for Compose
+        UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) {
+            super(null, dep, src);
+        }
+        final CompletableFuture<T> tryFire(int mode) {
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            if ((d = dep) == null || !d.uniRelay(a = src))
+                return null;
+            src = null; dep = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniRelay(CompletableFuture<T> a) {
+        Object r;
+        if (a == null || (r = a.result) == null)
+            return false;
+        if (result == null) // no need to claim
+            completeRelay(r);
+        return true;
+    }
+
+    private CompletableFuture<T> uniCopyStage() {
+        Object r;
+        CompletableFuture<T> d = newIncompleteFuture();
+        if ((r = result) != null)
+            d.completeRelay(r);
+        else {
+            UniRelay<T> c = new UniRelay<T>(d, this);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    private MinimalStage<T> uniAsMinimalStage() {
+        Object r;
+        if ((r = result) != null)
+            return new MinimalStage<T>(encodeRelay(r));
+        MinimalStage<T> d = new MinimalStage<T>();
+        UniRelay<T> c = new UniRelay<T>(d, this);
+        push(c);
+        c.tryFire(SYNC);
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniCompose<T,V> extends UniCompletion<T,V> {
+        Function<? super T, ? extends CompletionStage<V>> fn;
+        UniCompose(Executor executor, CompletableFuture<V> dep,
+                   CompletableFuture<T> src,
+                   Function<? super T, ? extends CompletionStage<V>> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniCompose(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniCompose(
+        CompletableFuture<S> a,
+        Function<? super S, ? extends CompletionStage<T>> f,
+        UniCompose<S,T> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                CompletableFuture<T> g = f.apply(s).toCompletableFuture();
+                if (g.result == null || !uniRelay(g)) {
+                    UniRelay<T> copy = new UniRelay<T>(this, g);
+                    g.push(copy);
+                    copy.tryFire(SYNC);
+                    if (result == null)
+                        return false;
+                }
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <V> CompletableFuture<V> uniComposeStage(
+        Executor e, Function<? super T, ? extends CompletionStage<V>> f) {
+        if (f == null) throw new NullPointerException();
+        Object r, s; Throwable x;
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (e == null && (r = result) != null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    d.result = encodeThrowable(x, r);
+                    return d;
+                }
+                r = null;
+            }
+            try {
+                @SuppressWarnings("unchecked") T t = (T) r;
+                CompletableFuture<V> g = f.apply(t).toCompletableFuture();
+                if ((s = g.result) != null)
+                    d.completeRelay(s);
+                else {
+                    UniRelay<V> c = new UniRelay<V>(d, g);
+                    g.push(c);
+                    c.tryFire(SYNC);
+                }
+                return d;
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+                return d;
+            }
+        }
+        UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f);
+        push(c);
+        c.tryFire(SYNC);
+        return d;
+    }
+
+    /* ------------- Two-input Completions -------------- */
+
+    /** A Completion for an action with two sources */
+    @SuppressWarnings("serial")
+    abstract static class BiCompletion<T,U,V> extends UniCompletion<T,V> {
+        CompletableFuture<U> snd; // second source for action
+        BiCompletion(Executor executor, CompletableFuture<V> dep,
+                     CompletableFuture<T> src, CompletableFuture<U> snd) {
+            super(executor, dep, src); this.snd = snd;
+        }
+    }
+
+    /** A Completion delegating to a BiCompletion */
+    @SuppressWarnings("serial")
+    static final class CoCompletion extends Completion {
+        BiCompletion<?,?,?> base;
+        CoCompletion(BiCompletion<?,?,?> base) { this.base = base; }
+        final CompletableFuture<?> tryFire(int mode) {
+            BiCompletion<?,?,?> c; CompletableFuture<?> d;
+            if ((c = base) == null || (d = c.tryFire(mode)) == null)
+                return null;
+            base = null; // detach
+            return d;
+        }
+        final boolean isLive() {
+            BiCompletion<?,?,?> c;
+            return (c = base) != null && c.dep != null;
+        }
+    }
+
+    /** Pushes completion to this and b unless both done. */
+    final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+        if (c != null) {
+            Object r;
+            while ((r = result) == null && !tryPushStack(c))
+                lazySetNext(c, null); // clear on failure
+            if (b != null && b != this && b.result == null) {
+                Completion q = (r != null) ? c : new CoCompletion(c);
+                while (b.result == null && !b.tryPushStack(q))
+                    lazySetNext(q, null); // clear on failure
+            }
+        }
+    }
+
+    /** Post-processing after successful BiCompletion tryFire. */
+    final CompletableFuture<T> postFire(CompletableFuture<?> a,
+                                        CompletableFuture<?> b, int mode) {
+        if (b != null && b.stack != null) { // clean second source
+            if (mode < 0 || b.result == null)
+                b.cleanStack();
+            else
+                b.postComplete();
+        }
+        return postFire(a, mode);
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiApply<T,U,V> extends BiCompletion<T,U,V> {
+        BiFunction<? super T,? super U,? extends V> fn;
+        BiApply(Executor executor, CompletableFuture<V> dep,
+                CompletableFuture<T> src, CompletableFuture<U> snd,
+                BiFunction<? super T,? super U,? extends V> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.biApply(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S> boolean biApply(CompletableFuture<R> a,
+                                CompletableFuture<S> b,
+                                BiFunction<? super R,? super S,? extends T> f,
+                                BiApply<R,S,T> c) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            if (s instanceof AltResult) {
+                if ((x = ((AltResult)s).ex) != null) {
+                    completeThrowable(x, s);
+                    break tryComplete;
+                }
+                s = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                @SuppressWarnings("unchecked") S ss = (S) s;
+                completeValue(f.apply(rr, ss));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U,V> CompletableFuture<V> biApplyStage(
+        Executor e, CompletionStage<U> o,
+        BiFunction<? super T,? super U,? extends V> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (e != null || !d.biApply(this, b, f, null)) {
+            BiApply<T,U,V> c = new BiApply<T,U,V>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiAccept<T,U> extends BiCompletion<T,U,Void> {
+        BiConsumer<? super T,? super U> fn;
+        BiAccept(Executor executor, CompletableFuture<Void> dep,
+                 CompletableFuture<T> src, CompletableFuture<U> snd,
+                 BiConsumer<? super T,? super U> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.biAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S> boolean biAccept(CompletableFuture<R> a,
+                                 CompletableFuture<S> b,
+                                 BiConsumer<? super R,? super S> f,
+                                 BiAccept<R,S> c) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            if (s instanceof AltResult) {
+                if ((x = ((AltResult)s).ex) != null) {
+                    completeThrowable(x, s);
+                    break tryComplete;
+                }
+                s = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                @SuppressWarnings("unchecked") S ss = (S) s;
+                f.accept(rr, ss);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U> CompletableFuture<Void> biAcceptStage(
+        Executor e, CompletionStage<U> o,
+        BiConsumer<? super T,? super U> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.biAccept(this, b, f, null)) {
+            BiAccept<T,U> c = new BiAccept<T,U>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiRun<T,U> extends BiCompletion<T,U,Void> {
+        Runnable fn;
+        BiRun(Executor executor, CompletableFuture<Void> dep,
+              CompletableFuture<T> src,
+              CompletableFuture<U> snd,
+              Runnable fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.biRun(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final boolean biRun(CompletableFuture<?> a, CompletableFuture<?> b,
+                        Runnable f, BiRun<?,?> c) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
+        if (result == null) {
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+                completeThrowable(x, s);
+            else
+                try {
+                    if (c != null && !c.claim())
+                        return false;
+                    f.run();
+                    completeNull();
+                } catch (Throwable ex) {
+                    completeThrowable(ex);
+                }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o,
+                                               Runnable f) {
+        CompletableFuture<?> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.biRun(this, b, f, null)) {
+            BiRun<T,?> c = new BiRun<>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiRelay<T,U> extends BiCompletion<T,U,Void> { // for And
+        BiRelay(CompletableFuture<Void> dep,
+                CompletableFuture<T> src,
+                CompletableFuture<U> snd) {
+            super(null, dep, src, snd);
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null || !d.biRelay(a = src, b = snd))
+                return null;
+            src = null; snd = null; dep = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    boolean biRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null)
+            return false;
+        if (result == null) {
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+                completeThrowable(x, s);
+            else
+                completeNull();
+        }
+        return true;
+    }
+
+    /** Recursively constructs a tree of completions. */
+    static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs,
+                                           int lo, int hi) {
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        if (lo > hi) // empty
+            d.result = NIL;
+        else {
+            CompletableFuture<?> a, b;
+            int mid = (lo + hi) >>> 1;
+            if ((a = (lo == mid ? cfs[lo] :
+                      andTree(cfs, lo, mid))) == null ||
+                (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+                      andTree(cfs, mid+1, hi))) == null)
+                throw new NullPointerException();
+            if (!d.biRelay(a, b)) {
+                BiRelay<?,?> c = new BiRelay<>(d, a, b);
+                a.bipush(b, c);
+                c.tryFire(SYNC);
+            }
+        }
+        return d;
+    }
+
+    /* ------------- Projected (Ored) BiCompletions -------------- */
+
+    /** Pushes completion to this and b unless either done. */
+    final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+        if (c != null) {
+            while ((b == null || b.result == null) && result == null) {
+                if (tryPushStack(c)) {
+                    if (b != null && b != this && b.result == null) {
+                        Completion q = new CoCompletion(c);
+                        while (result == null && b.result == null &&
+                               !b.tryPushStack(q))
+                            lazySetNext(q, null); // clear on failure
+                    }
+                    break;
+                }
+                lazySetNext(c, null); // clear on failure
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrApply<T,U extends T,V> extends BiCompletion<T,U,V> {
+        Function<? super T,? extends V> fn;
+        OrApply(Executor executor, CompletableFuture<V> dep,
+                CompletableFuture<T> src,
+                CompletableFuture<U> snd,
+                Function<? super T,? extends V> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.orApply(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S extends R> boolean orApply(CompletableFuture<R> a,
+                                          CompletableFuture<S> b,
+                                          Function<? super R, ? extends T> f,
+                                          OrApply<R,S,T> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                completeValue(f.apply(rr));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U extends T,V> CompletableFuture<V> orApplyStage(
+        Executor e, CompletionStage<U> o,
+        Function<? super T, ? extends V> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (e != null || !d.orApply(this, b, f, null)) {
+            OrApply<T,U,V> c = new OrApply<T,U,V>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrAccept<T,U extends T> extends BiCompletion<T,U,Void> {
+        Consumer<? super T> fn;
+        OrAccept(Executor executor, CompletableFuture<Void> dep,
+                 CompletableFuture<T> src,
+                 CompletableFuture<U> snd,
+                 Consumer<? super T> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.orAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S extends R> boolean orAccept(CompletableFuture<R> a,
+                                           CompletableFuture<S> b,
+                                           Consumer<? super R> f,
+                                           OrAccept<R,S> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                f.accept(rr);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U extends T> CompletableFuture<Void> orAcceptStage(
+        Executor e, CompletionStage<U> o, Consumer<? super T> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.orAccept(this, b, f, null)) {
+            OrAccept<T,U> c = new OrAccept<T,U>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrRun<T,U> extends BiCompletion<T,U,Void> {
+        Runnable fn;
+        OrRun(Executor executor, CompletableFuture<Void> dep,
+              CompletableFuture<T> src,
+              CompletableFuture<U> snd,
+              Runnable fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.orRun(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final boolean orRun(CompletableFuture<?> a, CompletableFuture<?> b,
+                        Runnable f, OrRun<?,?> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                    completeThrowable(x, r);
+                else {
+                    f.run();
+                    completeNull();
+                }
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> orRunStage(Executor e, CompletionStage<?> o,
+                                               Runnable f) {
+        CompletableFuture<?> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.orRun(this, b, f, null)) {
+            OrRun<T,?> c = new OrRun<>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrRelay<T,U> extends BiCompletion<T,U,Object> { // for Or
+        OrRelay(CompletableFuture<Object> dep, CompletableFuture<T> src,
+                CompletableFuture<U> snd) {
+            super(null, dep, src, snd);
+        }
+        final CompletableFuture<Object> tryFire(int mode) {
+            CompletableFuture<Object> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null || !d.orRelay(a = src, b = snd))
+                return null;
+            src = null; snd = null; dep = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final boolean orRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+        Object r;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null))
+            return false;
+        if (result == null)
+            completeRelay(r);
+        return true;
+    }
+
+    /** Recursively constructs a tree of completions. */
+    static CompletableFuture<Object> orTree(CompletableFuture<?>[] cfs,
+                                            int lo, int hi) {
+        CompletableFuture<Object> d = new CompletableFuture<Object>();
+        if (lo <= hi) {
+            CompletableFuture<?> a, b;
+            int mid = (lo + hi) >>> 1;
+            if ((a = (lo == mid ? cfs[lo] :
+                      orTree(cfs, lo, mid))) == null ||
+                (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+                      orTree(cfs, mid+1, hi))) == null)
+                throw new NullPointerException();
+            if (!d.orRelay(a, b)) {
+                OrRelay<?,?> c = new OrRelay<>(d, a, b);
+                a.orpush(b, c);
+                c.tryFire(SYNC);
+            }
+        }
+        return d;
+    }
+
+    /* ------------- Zero-input Async forms -------------- */
+
+    @SuppressWarnings("serial")
+    static final class AsyncSupply<T> extends ForkJoinTask<Void>
+        implements Runnable, AsynchronousCompletionTask {
+        CompletableFuture<T> dep; Supplier<? extends T> fn;
+        AsyncSupply(CompletableFuture<T> dep, Supplier<? extends T> fn) {
+            this.dep = dep; this.fn = fn;
+        }
+
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) {}
+        public final boolean exec() { run(); return true; }
+
+        public void run() {
+            CompletableFuture<T> d; Supplier<? extends T> f;
+            if ((d = dep) != null && (f = fn) != null) {
+                dep = null; fn = null;
+                if (d.result == null) {
+                    try {
+                        d.completeValue(f.get());
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+                }
+                d.postComplete();
+            }
+        }
+    }
+
+    static <U> CompletableFuture<U> asyncSupplyStage(Executor e,
+                                                     Supplier<U> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<U> d = new CompletableFuture<U>();
+        e.execute(new AsyncSupply<U>(d, f));
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class AsyncRun extends ForkJoinTask<Void>
+        implements Runnable, AsynchronousCompletionTask {
+        CompletableFuture<Void> dep; Runnable fn;
+        AsyncRun(CompletableFuture<Void> dep, Runnable fn) {
+            this.dep = dep; this.fn = fn;
+        }
+
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) {}
+        public final boolean exec() { run(); return true; }
+
+        public void run() {
+            CompletableFuture<Void> d; Runnable f;
+            if ((d = dep) != null && (f = fn) != null) {
+                dep = null; fn = null;
+                if (d.result == null) {
+                    try {
+                        f.run();
+                        d.completeNull();
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+                }
+                d.postComplete();
+            }
+        }
+    }
+
+    static CompletableFuture<Void> asyncRunStage(Executor e, Runnable f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        e.execute(new AsyncRun(d, f));
+        return d;
+    }
+
+    /* ------------- Signallers -------------- */
+
+    /**
+     * Completion for recording and releasing a waiting thread.  This
+     * class implements ManagedBlocker to avoid starvation when
+     * blocking actions pile up in ForkJoinPools.
+     */
+    @SuppressWarnings("serial")
+    static final class Signaller extends Completion
+        implements ForkJoinPool.ManagedBlocker {
+        long nanos;                    // remaining wait time if timed
+        final long deadline;           // non-zero if timed
+        final boolean interruptible;
+        boolean interrupted;
+        volatile Thread thread;
+
+        Signaller(boolean interruptible, long nanos, long deadline) {
+            this.thread = Thread.currentThread();
+            this.interruptible = interruptible;
+            this.nanos = nanos;
+            this.deadline = deadline;
+        }
+        final CompletableFuture<?> tryFire(int ignore) {
+            Thread w; // no need to atomically claim
+            if ((w = thread) != null) {
+                thread = null;
+                LockSupport.unpark(w);
+            }
+            return null;
+        }
+        public boolean isReleasable() {
+            if (Thread.interrupted())
+                interrupted = true;
+            return ((interrupted && interruptible) ||
+                    (deadline != 0L &&
+                     (nanos <= 0L ||
+                      (nanos = deadline - System.nanoTime()) <= 0L)) ||
+                    thread == null);
+        }
+        public boolean block() {
+            while (!isReleasable()) {
+                if (deadline == 0L)
+                    LockSupport.park(this);
+                else
+                    LockSupport.parkNanos(this, nanos);
+            }
+            return true;
+        }
+        final boolean isLive() { return thread != null; }
+    }
+
+    /**
+     * Returns raw result after waiting, or null if interruptible and
+     * interrupted.
+     */
+    private Object waitingGet(boolean interruptible) {
+        Signaller q = null;
+        boolean queued = false;
+        int spins = SPINS;
+        Object r;
+        while ((r = result) == null) {
+            if (spins > 0) {
+                if (ThreadLocalRandom.nextSecondarySeed() >= 0)
+                    --spins;
+            }
+            else if (q == null)
+                q = new Signaller(interruptible, 0L, 0L);
+            else if (!queued)
+                queued = tryPushStack(q);
+            else {
+                try {
+                    ForkJoinPool.managedBlock(q);
+                } catch (InterruptedException ie) { // currently cannot happen
+                    q.interrupted = true;
+                }
+                if (q.interrupted && interruptible)
+                    break;
+            }
+        }
+        if (q != null) {
+            q.thread = null;
+            if (q.interrupted) {
+                if (interruptible)
+                    cleanStack();
+                else
+                    Thread.currentThread().interrupt();
+            }
+        }
+        if (r != null)
+            postComplete();
+        return r;
+    }
+
+    /**
+     * Returns raw result after waiting, or null if interrupted, or
+     * throws TimeoutException on timeout.
+     */
+    private Object timedGet(long nanos) throws TimeoutException {
+        if (Thread.interrupted())
+            return null;
+        if (nanos > 0L) {
+            long d = System.nanoTime() + nanos;
+            long deadline = (d == 0L) ? 1L : d; // avoid 0
+            Signaller q = null;
+            boolean queued = false;
+            Object r;
+            while ((r = result) == null) { // similar to untimed, without spins
+                if (q == null)
+                    q = new Signaller(true, nanos, deadline);
+                else if (!queued)
+                    queued = tryPushStack(q);
+                else if (q.nanos <= 0L)
+                    break;
+                else {
+                    try {
+                        ForkJoinPool.managedBlock(q);
+                    } catch (InterruptedException ie) {
+                        q.interrupted = true;
+                    }
+                    if (q.interrupted)
+                        break;
+                }
+            }
+            if (q != null)
+                q.thread = null;
+            if (r != null)
+                postComplete();
+            else
+                cleanStack();
+            if (r != null || (q != null && q.interrupted))
+                return r;
+        }
+        throw new TimeoutException();
+    }
+
+    /* ------------- public methods -------------- */
+
+    /**
+     * Creates a new incomplete CompletableFuture.
+     */
+    public CompletableFuture() {
+    }
+
+    /**
+     * Creates a new complete CompletableFuture with given encoded result.
+     */
+    CompletableFuture(Object r) {
+        this.result = r;
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the {@link ForkJoinPool#commonPool()} with
+     * the value obtained by calling the given Supplier.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete the returned CompletableFuture
+     * @param <U> the function's return type
+     * @return the new CompletableFuture
+     */
+    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
+        return asyncSupplyStage(ASYNC_POOL, supplier);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the given executor with the value obtained
+     * by calling the given Supplier.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete the returned CompletableFuture
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletableFuture
+     */
+    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
+                                                       Executor executor) {
+        return asyncSupplyStage(screenExecutor(executor), supplier);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the {@link ForkJoinPool#commonPool()} after
+     * it runs the given action.
+     *
+     * @param runnable the action to run before completing the
+     * returned CompletableFuture
+     * @return the new CompletableFuture
+     */
+    public static CompletableFuture<Void> runAsync(Runnable runnable) {
+        return asyncRunStage(ASYNC_POOL, runnable);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the given executor after it runs the given
+     * action.
+     *
+     * @param runnable the action to run before completing the
+     * returned CompletableFuture
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletableFuture
+     */
+    public static CompletableFuture<Void> runAsync(Runnable runnable,
+                                                   Executor executor) {
+        return asyncRunStage(screenExecutor(executor), runnable);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is already completed with
+     * the given value.
+     *
+     * @param value the value
+     * @param <U> the type of the value
+     * @return the completed CompletableFuture
+     */
+    public static <U> CompletableFuture<U> completedFuture(U value) {
+        return new CompletableFuture<U>((value == null) ? NIL : value);
+    }
+
+    /**
+     * Returns {@code true} if completed in any fashion: normally,
+     * exceptionally, or via cancellation.
+     *
+     * @return {@code true} if completed
+     */
+    public boolean isDone() {
+        return result != null;
+    }
+
+    /**
+     * Waits if necessary for this future to complete, and then
+     * returns its result.
+     *
+     * @return the result value
+     * @throws CancellationException if this future was cancelled
+     * @throws ExecutionException if this future completed exceptionally
+     * @throws InterruptedException if the current thread was interrupted
+     * while waiting
+     */
+    public T get() throws InterruptedException, ExecutionException {
+        Object r;
+        return reportGet((r = result) == null ? waitingGet(true) : r);
+    }
+
+    /**
+     * Waits if necessary for at most the given time for this future
+     * to complete, and then returns its result, if available.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return the result value
+     * @throws CancellationException if this future was cancelled
+     * @throws ExecutionException if this future completed exceptionally
+     * @throws InterruptedException if the current thread was interrupted
+     * while waiting
+     * @throws TimeoutException if the wait timed out
+     */
+    public T get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        Object r;
+        long nanos = unit.toNanos(timeout);
+        return reportGet((r = result) == null ? timedGet(nanos) : r);
+    }
+
+    /**
+     * Returns the result value when complete, or throws an
+     * (unchecked) exception if completed exceptionally. To better
+     * conform with the use of common functional forms, if a
+     * computation involved in the completion of this
+     * CompletableFuture threw an exception, this method throws an
+     * (unchecked) {@link CompletionException} with the underlying
+     * exception as its cause.
+     *
+     * @return the result value
+     * @throws CancellationException if the computation was cancelled
+     * @throws CompletionException if this future completed
+     * exceptionally or a completion computation threw an exception
+     */
+    public T join() {
+        Object r;
+        return reportJoin((r = result) == null ? waitingGet(false) : r);
+    }
+
+    /**
+     * Returns the result value (or throws any encountered exception)
+     * if completed, else returns the given valueIfAbsent.
+     *
+     * @param valueIfAbsent the value to return if not completed
+     * @return the result value, if completed, else the given valueIfAbsent
+     * @throws CancellationException if the computation was cancelled
+     * @throws CompletionException if this future completed
+     * exceptionally or a completion computation threw an exception
+     */
+    public T getNow(T valueIfAbsent) {
+        Object r;
+        return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
+    }
+
+    /**
+     * If not already completed, sets the value returned by {@link
+     * #get()} and related methods to the given value.
+     *
+     * @param value the result value
+     * @return {@code true} if this invocation caused this CompletableFuture
+     * to transition to a completed state, else {@code false}
+     */
+    public boolean complete(T value) {
+        boolean triggered = completeValue(value);
+        postComplete();
+        return triggered;
+    }
+
+    /**
+     * If not already completed, causes invocations of {@link #get()}
+     * and related methods to throw the given exception.
+     *
+     * @param ex the exception
+     * @return {@code true} if this invocation caused this CompletableFuture
+     * to transition to a completed state, else {@code false}
+     */
+    public boolean completeExceptionally(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        boolean triggered = internalComplete(new AltResult(ex));
+        postComplete();
+        return triggered;
+    }
+
+    public <U> CompletableFuture<U> thenApply(
+        Function<? super T,? extends U> fn) {
+        return uniApplyStage(null, fn);
+    }
+
+    public <U> CompletableFuture<U> thenApplyAsync(
+        Function<? super T,? extends U> fn) {
+        return uniApplyStage(defaultExecutor(), fn);
+    }
+
+    public <U> CompletableFuture<U> thenApplyAsync(
+        Function<? super T,? extends U> fn, Executor executor) {
+        return uniApplyStage(screenExecutor(executor), fn);
+    }
+
+    public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
+        return uniAcceptStage(null, action);
+    }
+
+    public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
+        return uniAcceptStage(defaultExecutor(), action);
+    }
+
+    public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
+                                                   Executor executor) {
+        return uniAcceptStage(screenExecutor(executor), action);
+    }
+
+    public CompletableFuture<Void> thenRun(Runnable action) {
+        return uniRunStage(null, action);
+    }
+
+    public CompletableFuture<Void> thenRunAsync(Runnable action) {
+        return uniRunStage(defaultExecutor(), action);
+    }
+
+    public CompletableFuture<Void> thenRunAsync(Runnable action,
+                                                Executor executor) {
+        return uniRunStage(screenExecutor(executor), action);
+    }
+
+    public <U,V> CompletableFuture<V> thenCombine(
+        CompletionStage<? extends U> other,
+        BiFunction<? super T,? super U,? extends V> fn) {
+        return biApplyStage(null, other, fn);
+    }
+
+    public <U,V> CompletableFuture<V> thenCombineAsync(
+        CompletionStage<? extends U> other,
+        BiFunction<? super T,? super U,? extends V> fn) {
+        return biApplyStage(defaultExecutor(), other, fn);
+    }
+
+    public <U,V> CompletableFuture<V> thenCombineAsync(
+        CompletionStage<? extends U> other,
+        BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
+        return biApplyStage(screenExecutor(executor), other, fn);
+    }
+
+    public <U> CompletableFuture<Void> thenAcceptBoth(
+        CompletionStage<? extends U> other,
+        BiConsumer<? super T, ? super U> action) {
+        return biAcceptStage(null, other, action);
+    }
+
+    public <U> CompletableFuture<Void> thenAcceptBothAsync(
+        CompletionStage<? extends U> other,
+        BiConsumer<? super T, ? super U> action) {
+        return biAcceptStage(defaultExecutor(), other, action);
+    }
+
+    public <U> CompletableFuture<Void> thenAcceptBothAsync(
+        CompletionStage<? extends U> other,
+        BiConsumer<? super T, ? super U> action, Executor executor) {
+        return biAcceptStage(screenExecutor(executor), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
+                                                Runnable action) {
+        return biRunStage(null, other, action);
+    }
+
+    public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                     Runnable action) {
+        return biRunStage(defaultExecutor(), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                     Runnable action,
+                                                     Executor executor) {
+        return biRunStage(screenExecutor(executor), other, action);
+    }
+
+    public <U> CompletableFuture<U> applyToEither(
+        CompletionStage<? extends T> other, Function<? super T, U> fn) {
+        return orApplyStage(null, other, fn);
+    }
+
+    public <U> CompletableFuture<U> applyToEitherAsync(
+        CompletionStage<? extends T> other, Function<? super T, U> fn) {
+        return orApplyStage(defaultExecutor(), other, fn);
+    }
+
+    public <U> CompletableFuture<U> applyToEitherAsync(
+        CompletionStage<? extends T> other, Function<? super T, U> fn,
+        Executor executor) {
+        return orApplyStage(screenExecutor(executor), other, fn);
+    }
+
+    public CompletableFuture<Void> acceptEither(
+        CompletionStage<? extends T> other, Consumer<? super T> action) {
+        return orAcceptStage(null, other, action);
+    }
+
+    public CompletableFuture<Void> acceptEitherAsync(
+        CompletionStage<? extends T> other, Consumer<? super T> action) {
+        return orAcceptStage(defaultExecutor(), other, action);
+    }
+
+    public CompletableFuture<Void> acceptEitherAsync(
+        CompletionStage<? extends T> other, Consumer<? super T> action,
+        Executor executor) {
+        return orAcceptStage(screenExecutor(executor), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
+                                                  Runnable action) {
+        return orRunStage(null, other, action);
+    }
+
+    public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
+                                                       Runnable action) {
+        return orRunStage(defaultExecutor(), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
+                                                       Runnable action,
+                                                       Executor executor) {
+        return orRunStage(screenExecutor(executor), other, action);
+    }
+
+    public <U> CompletableFuture<U> thenCompose(
+        Function<? super T, ? extends CompletionStage<U>> fn) {
+        return uniComposeStage(null, fn);
+    }
+
+    public <U> CompletableFuture<U> thenComposeAsync(
+        Function<? super T, ? extends CompletionStage<U>> fn) {
+        return uniComposeStage(defaultExecutor(), fn);
+    }
+
+    public <U> CompletableFuture<U> thenComposeAsync(
+        Function<? super T, ? extends CompletionStage<U>> fn,
+        Executor executor) {
+        return uniComposeStage(screenExecutor(executor), fn);
+    }
+
+    public CompletableFuture<T> whenComplete(
+        BiConsumer<? super T, ? super Throwable> action) {
+        return uniWhenCompleteStage(null, action);
+    }
+
+    public CompletableFuture<T> whenCompleteAsync(
+        BiConsumer<? super T, ? super Throwable> action) {
+        return uniWhenCompleteStage(defaultExecutor(), action);
+    }
+
+    public CompletableFuture<T> whenCompleteAsync(
+        BiConsumer<? super T, ? super Throwable> action, Executor executor) {
+        return uniWhenCompleteStage(screenExecutor(executor), action);
+    }
+
+    public <U> CompletableFuture<U> handle(
+        BiFunction<? super T, Throwable, ? extends U> fn) {
+        return uniHandleStage(null, fn);
+    }
+
+    public <U> CompletableFuture<U> handleAsync(
+        BiFunction<? super T, Throwable, ? extends U> fn) {
+        return uniHandleStage(defaultExecutor(), fn);
+    }
+
+    public <U> CompletableFuture<U> handleAsync(
+        BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {
+        return uniHandleStage(screenExecutor(executor), fn);
+    }
+
+    /**
+     * Returns this CompletableFuture.
+     *
+     * @return this CompletableFuture
+     */
+    public CompletableFuture<T> toCompletableFuture() {
+        return this;
+    }
+
+    // not in interface CompletionStage
+
+    /**
+     * Returns a new CompletableFuture that is completed when this
+     * CompletableFuture completes, with the result of the given
+     * function of the exception triggering this CompletableFuture's
+     * completion when it completes exceptionally; otherwise, if this
+     * CompletableFuture completes normally, then the returned
+     * CompletableFuture also completes normally with the same value.
+     * Note: More flexible versions of this functionality are
+     * available using methods {@code whenComplete} and {@code handle}.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletableFuture if this CompletableFuture completed
+     * exceptionally
+     * @return the new CompletableFuture
+     */
+    public CompletableFuture<T> exceptionally(
+        Function<Throwable, ? extends T> fn) {
+        return uniExceptionallyStage(fn);
+    }
+
+
+    /* ------------- Arbitrary-arity constructions -------------- */
+
+    /**
+     * Returns a new CompletableFuture that is completed when all of
+     * the given CompletableFutures complete.  If any of the given
+     * CompletableFutures complete exceptionally, then the returned
+     * CompletableFuture also does so, with a CompletionException
+     * holding this exception as its cause.  Otherwise, the results,
+     * if any, of the given CompletableFutures are not reflected in
+     * the returned CompletableFuture, but may be obtained by
+     * inspecting them individually. If no CompletableFutures are
+     * provided, returns a CompletableFuture completed with the value
+     * {@code null}.
+     *
+     * <p>Among the applications of this method is to await completion
+     * of a set of independent CompletableFutures before continuing a
+     * program, as in: {@code CompletableFuture.allOf(c1, c2,
+     * c3).join();}.
+     *
+     * @param cfs the CompletableFutures
+     * @return a new CompletableFuture that is completed when all of the
+     * given CompletableFutures complete
+     * @throws NullPointerException if the array or any of its elements are
+     * {@code null}
+     */
+    public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
+        return andTree(cfs, 0, cfs.length - 1);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is completed when any of
+     * the given CompletableFutures complete, with the same result.
+     * Otherwise, if it completed exceptionally, the returned
+     * CompletableFuture also does so, with a CompletionException
+     * holding this exception as its cause.  If no CompletableFutures
+     * are provided, returns an incomplete CompletableFuture.
+     *
+     * @param cfs the CompletableFutures
+     * @return a new CompletableFuture that is completed with the
+     * result or exception of any of the given CompletableFutures when
+     * one completes
+     * @throws NullPointerException if the array or any of its elements are
+     * {@code null}
+     */
+    public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
+        return orTree(cfs, 0, cfs.length - 1);
+    }
+
+    /* ------------- Control and status methods -------------- */
+
+    /**
+     * If not already completed, completes this CompletableFuture with
+     * a {@link CancellationException}. Dependent CompletableFutures
+     * that have not already completed will also complete
+     * exceptionally, with a {@link CompletionException} caused by
+     * this {@code CancellationException}.
+     *
+     * @param mayInterruptIfRunning this value has no effect in this
+     * implementation because interrupts are not used to control
+     * processing.
+     *
+     * @return {@code true} if this task is now cancelled
+     */
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        boolean cancelled = (result == null) &&
+            internalComplete(new AltResult(new CancellationException()));
+        postComplete();
+        return cancelled || isCancelled();
+    }
+
+    /**
+     * Returns {@code true} if this CompletableFuture was cancelled
+     * before it completed normally.
+     *
+     * @return {@code true} if this CompletableFuture was cancelled
+     * before it completed normally
+     */
+    public boolean isCancelled() {
+        Object r;
+        return ((r = result) instanceof AltResult) &&
+            (((AltResult)r).ex instanceof CancellationException);
+    }
+
+    /**
+     * Returns {@code true} if this CompletableFuture completed
+     * exceptionally, in any way. Possible causes include
+     * cancellation, explicit invocation of {@code
+     * completeExceptionally}, and abrupt termination of a
+     * CompletionStage action.
+     *
+     * @return {@code true} if this CompletableFuture completed
+     * exceptionally
+     */
+    public boolean isCompletedExceptionally() {
+        Object r;
+        return ((r = result) instanceof AltResult) && r != NIL;
+    }
+
+    /**
+     * Forcibly sets or resets the value subsequently returned by
+     * method {@link #get()} and related methods, whether or not
+     * already completed. This method is designed for use only in
+     * error recovery actions, and even in such situations may result
+     * in ongoing dependent completions using established versus
+     * overwritten outcomes.
+     *
+     * @param value the completion value
+     */
+    public void obtrudeValue(T value) {
+        result = (value == null) ? NIL : value;
+        postComplete();
+    }
+
+    /**
+     * Forcibly causes subsequent invocations of method {@link #get()}
+     * and related methods to throw the given exception, whether or
+     * not already completed. This method is designed for use only in
+     * error recovery actions, and even in such situations may result
+     * in ongoing dependent completions using established versus
+     * overwritten outcomes.
+     *
+     * @param ex the exception
+     * @throws NullPointerException if the exception is null
+     */
+    public void obtrudeException(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        result = new AltResult(ex);
+        postComplete();
+    }
+
+    /**
+     * Returns the estimated number of CompletableFutures whose
+     * completions are awaiting completion of this CompletableFuture.
+     * This method is designed for use in monitoring system state, not
+     * for synchronization control.
+     *
+     * @return the number of dependent CompletableFutures
+     */
+    public int getNumberOfDependents() {
+        int count = 0;
+        for (Completion p = stack; p != null; p = p.next)
+            ++count;
+        return count;
+    }
+
+    /**
+     * Returns a string identifying this CompletableFuture, as well as
+     * its completion state.  The state, in brackets, contains the
+     * String {@code "Completed Normally"} or the String {@code
+     * "Completed Exceptionally"}, or the String {@code "Not
+     * completed"} followed by the number of CompletableFutures
+     * dependent upon its completion, if any.
+     *
+     * @return a string identifying this CompletableFuture, as well as its state
+     */
+    public String toString() {
+        Object r = result;
+        int count = 0; // avoid call to getNumberOfDependents in case disabled
+        for (Completion p = stack; p != null; p = p.next)
+            ++count;
+        return super.toString() +
+            ((r == null) ?
+             ((count == 0) ?
+              "[Not completed]" :
+              "[Not completed, " + count + " dependents]") :
+             (((r instanceof AltResult) && ((AltResult)r).ex != null) ?
+              "[Completed exceptionally]" :
+              "[Completed normally]"));
+    }
+
+    // jdk9 additions
+
+    /**
+     * Returns a new incomplete CompletableFuture of the type to be
+     * returned by a CompletionStage method. Subclasses should
+     * normally override this method to return an instance of the same
+     * class as this CompletableFuture. The default implementation
+     * returns an instance of class CompletableFuture.
+     *
+     * @param <U> the type of the value
+     * @return a new CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public <U> CompletableFuture<U> newIncompleteFuture() {
+        return new CompletableFuture<U>();
+    }
+
+    /**
+     * Returns the default Executor used for async methods that do not
+     * specify an Executor. This class uses the {@link
+     * ForkJoinPool#commonPool()} if it supports more than one
+     * parallel thread, or else an Executor using one thread per async
+     * task.  This method may be overridden in subclasses to return
+     * an Executor that provides at least one independent thread.
+     *
+     * @return the executor
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public Executor defaultExecutor() {
+        return ASYNC_POOL;
+    }
+
+    /**
+     * Returns a new CompletableFuture that is completed normally with
+     * the same value as this CompletableFuture when it completes
+     * normally. If this CompletableFuture completes exceptionally,
+     * then the returned CompletableFuture completes exceptionally
+     * with a CompletionException with this exception as cause. The
+     * behavior is equivalent to {@code thenApply(x -> x)}. This
+     * method may be useful as a form of "defensive copying", to
+     * prevent clients from completing, while still being able to
+     * arrange dependent actions.
+     *
+     * @return the new CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletableFuture<T> copy() {
+        return uniCopyStage();
+    }
+
+    /**
+     * Returns a new CompletionStage that is completed normally with
+     * the same value as this CompletableFuture when it completes
+     * normally, and cannot be independently completed or otherwise
+     * used in ways not defined by the methods of interface {@link
+     * CompletionStage}.  If this CompletableFuture completes
+     * exceptionally, then the returned CompletionStage completes
+     * exceptionally with a CompletionException with this exception as
+     * cause.
+     *
+     * @return the new CompletionStage
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletionStage<T> minimalCompletionStage() {
+        return uniAsMinimalStage();
+    }
+
+    /**
+     * Completes this CompletableFuture with the result of
+     * the given Supplier function invoked from an asynchronous
+     * task using the given executor.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete this CompletableFuture
+     * @param executor the executor to use for asynchronous execution
+     * @return this CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier,
+                                              Executor executor) {
+        if (supplier == null || executor == null)
+            throw new NullPointerException();
+        executor.execute(new AsyncSupply<T>(this, supplier));
+        return this;
+    }
+
+    /**
+     * Completes this CompletableFuture with the result of the given
+     * Supplier function invoked from an asynchronous task using the
+     * default executor.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete this CompletableFuture
+     * @return this CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier) {
+        return completeAsync(supplier, defaultExecutor());
+    }
+
+    /**
+     * Exceptionally completes this CompletableFuture with
+     * a {@link TimeoutException} if not otherwise completed
+     * before the given timeout.
+     *
+     * @param timeout how long to wait before completing exceptionally
+     *        with a TimeoutException, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return this CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit) {
+        if (unit == null)
+            throw new NullPointerException();
+        if (result == null)
+            whenComplete(new Canceller(Delayer.delay(new Timeout(this),
+                                                     timeout, unit)));
+        return this;
+    }
+
+    /**
+     * Completes this CompletableFuture with the given value if not
+     * otherwise completed before the given timeout.
+     *
+     * @param value the value to use upon timeout
+     * @param timeout how long to wait before completing normally
+     *        with the given value, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return this CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletableFuture<T> completeOnTimeout(T value, long timeout,
+                                                  TimeUnit unit) {
+        if (unit == null)
+            throw new NullPointerException();
+        if (result == null)
+            whenComplete(new Canceller(Delayer.delay(
+                                           new DelayedCompleter<T>(this, value),
+                                           timeout, unit)));
+        return this;
+    }
+
+    /**
+     * Returns a new Executor that submits a task to the given base
+     * executor after the given delay (or no delay if non-positive).
+     * Each delay commences upon invocation of the returned executor's
+     * {@code execute} method.
+     *
+     * @param delay how long to delay, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code delay} parameter
+     * @param executor the base executor
+     * @return the new delayed executor
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public static Executor delayedExecutor(long delay, TimeUnit unit,
+                                           Executor executor) {
+        if (unit == null || executor == null)
+            throw new NullPointerException();
+        return new DelayedExecutor(delay, unit, executor);
+    }
+
+    /**
+     * Returns a new Executor that submits a task to the default
+     * executor after the given delay (or no delay if non-positive).
+     * Each delay commences upon invocation of the returned executor's
+     * {@code execute} method.
+     *
+     * @param delay how long to delay, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code delay} parameter
+     * @return the new delayed executor
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public static Executor delayedExecutor(long delay, TimeUnit unit) {
+        if (unit == null)
+            throw new NullPointerException();
+        return new DelayedExecutor(delay, unit, ASYNC_POOL);
+    }
+
+    /**
+     * Returns a new CompletionStage that is already completed with
+     * the given value and supports only those methods in
+     * interface {@link CompletionStage}.
+     *
+     * @param value the value
+     * @param <U> the type of the value
+     * @return the completed CompletionStage
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public static <U> CompletionStage<U> completedStage(U value) {
+        return new MinimalStage<U>((value == null) ? NIL : value);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is already completed
+     * exceptionally with the given exception.
+     *
+     * @param ex the exception
+     * @param <U> the type of the value
+     * @return the exceptionally completed CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public static <U> CompletableFuture<U> failedFuture(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        return new CompletableFuture<U>(new AltResult(ex));
+    }
+
+    /**
+     * Returns a new CompletionStage that is already completed
+     * exceptionally with the given exception and supports only those
+     * methods in interface {@link CompletionStage}.
+     *
+     * @param ex the exception
+     * @param <U> the type of the value
+     * @return the exceptionally completed CompletionStage
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public static <U> CompletionStage<U> failedStage(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        return new MinimalStage<U>(new AltResult(ex));
+    }
+
+    /**
+     * Singleton delay scheduler, used only for starting and
+     * cancelling tasks.
+     */
+    static final class Delayer {
+        static ScheduledFuture<?> delay(Runnable command, long delay,
+                                        TimeUnit unit) {
+            return delayer.schedule(command, delay, unit);
+        }
+
+        static final class DaemonThreadFactory implements ThreadFactory {
+            public Thread newThread(Runnable r) {
+                Thread t = new Thread(r);
+                t.setDaemon(true);
+                t.setName("CompletableFutureDelayScheduler");
+                return t;
+            }
+        }
+
+        static final ScheduledThreadPoolExecutor delayer;
+        static {
+            (delayer = new ScheduledThreadPoolExecutor(
+                1, new DaemonThreadFactory())).
+                setRemoveOnCancelPolicy(true);
+        }
+    }
+
+    // Little class-ified lambdas to better support monitoring
+
+    static final class DelayedExecutor implements Executor {
+        final long delay;
+        final TimeUnit unit;
+        final Executor executor;
+        DelayedExecutor(long delay, TimeUnit unit, Executor executor) {
+            this.delay = delay; this.unit = unit; this.executor = executor;
+        }
+        public void execute(Runnable r) {
+            Delayer.delay(new TaskSubmitter(executor, r), delay, unit);
+        }
+    }
+
+    /** Action to submit user task */
+    static final class TaskSubmitter implements Runnable {
+        final Executor executor;
+        final Runnable action;
+        TaskSubmitter(Executor executor, Runnable action) {
+            this.executor = executor;
+            this.action = action;
+        }
+        public void run() { executor.execute(action); }
+    }
+
+    /** Action to completeExceptionally on timeout */
+    static final class Timeout implements Runnable {
+        final CompletableFuture<?> f;
+        Timeout(CompletableFuture<?> f) { this.f = f; }
+        public void run() {
+            if (f != null && !f.isDone())
+                f.completeExceptionally(new TimeoutException());
+        }
+    }
+
+    /** Action to complete on timeout */
+    static final class DelayedCompleter<U> implements Runnable {
+        final CompletableFuture<U> f;
+        final U u;
+        DelayedCompleter(CompletableFuture<U> f, U u) { this.f = f; this.u = u; }
+        public void run() {
+            if (f != null)
+                f.complete(u);
+        }
+    }
+
+    /** Action to cancel unneeded timeouts */
+    static final class Canceller implements BiConsumer<Object, Throwable> {
+        final Future<?> f;
+        Canceller(Future<?> f) { this.f = f; }
+        public void accept(Object ignore, Throwable ex) {
+            if (ex == null && f != null && !f.isDone())
+                f.cancel(false);
+        }
+    }
+
+    /**
+     * A subclass that just throws UOE for most non-CompletionStage methods.
+     */
+    static final class MinimalStage<T> extends CompletableFuture<T> {
+        MinimalStage() { }
+        MinimalStage(Object r) { super(r); }
+        @Override public <U> CompletableFuture<U> newIncompleteFuture() {
+            return new MinimalStage<U>(); }
+        @Override public T get() {
+            throw new UnsupportedOperationException(); }
+        @Override public T get(long timeout, TimeUnit unit) {
+            throw new UnsupportedOperationException(); }
+        @Override public T getNow(T valueIfAbsent) {
+            throw new UnsupportedOperationException(); }
+        @Override public T join() {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean complete(T value) {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean completeExceptionally(Throwable ex) {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean cancel(boolean mayInterruptIfRunning) {
+            throw new UnsupportedOperationException(); }
+        @Override public void obtrudeValue(T value) {
+            throw new UnsupportedOperationException(); }
+        @Override public void obtrudeException(Throwable ex) {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean isDone() {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean isCancelled() {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean isCompletedExceptionally() {
+            throw new UnsupportedOperationException(); }
+        @Override public int getNumberOfDependents() {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> completeAsync
+            (Supplier<? extends T> supplier, Executor executor) {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> completeAsync
+            (Supplier<? extends T> supplier) {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> orTimeout
+            (long timeout, TimeUnit unit) {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> completeOnTimeout
+            (T value, long timeout, TimeUnit unit) {
+            throw new UnsupportedOperationException(); }
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long RESULT;
+    private static final long STACK;
+    private static final long NEXT;
+    static {
+        try {
+            RESULT = U.objectFieldOffset
+                (CompletableFuture.class.getDeclaredField("result"));
+            STACK = U.objectFieldOffset
+                (CompletableFuture.class.getDeclaredField("stack"));
+            NEXT = U.objectFieldOffset
+                (Completion.class.getDeclaredField("next"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/java/util/concurrent/CompletionException.java b/java/util/concurrent/CompletionException.java
new file mode 100644
index 0000000..2a3cfc5
--- /dev/null
+++ b/java/util/concurrent/CompletionException.java
@@ -0,0 +1,90 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when an error or other exception is encountered
+ * in the course of completing a result or task.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class CompletionException extends RuntimeException {
+    private static final long serialVersionUID = 7830266012832686185L;
+
+    /**
+     * Constructs a {@code CompletionException} with no detail message.
+     * The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     */
+    protected CompletionException() { }
+
+    /**
+     * Constructs a {@code CompletionException} with the specified detail
+     * message. The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     *
+     * @param message the detail message
+     */
+    protected CompletionException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a {@code CompletionException} with the specified detail
+     * message and cause.
+     *
+     * @param  message the detail message
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public CompletionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a {@code CompletionException} with the specified cause.
+     * The detail message is set to {@code (cause == null ? null :
+     * cause.toString())} (which typically contains the class and
+     * detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public CompletionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/util/concurrent/CompletionService.java b/java/util/concurrent/CompletionService.java
new file mode 100644
index 0000000..f647e21
--- /dev/null
+++ b/java/util/concurrent/CompletionService.java
@@ -0,0 +1,124 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A service that decouples the production of new asynchronous tasks
+ * from the consumption of the results of completed tasks.  Producers
+ * {@code submit} tasks for execution. Consumers {@code take}
+ * completed tasks and process their results in the order they
+ * complete.  A {@code CompletionService} can for example be used to
+ * manage asynchronous I/O, in which tasks that perform reads are
+ * submitted in one part of a program or system, and then acted upon
+ * in a different part of the program when the reads complete,
+ * possibly in a different order than they were requested.
+ *
+ * <p>Typically, a {@code CompletionService} relies on a separate
+ * {@link Executor} to actually execute the tasks, in which case the
+ * {@code CompletionService} only manages an internal completion
+ * queue. The {@link ExecutorCompletionService} class provides an
+ * implementation of this approach.
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to
+ * submitting a task to a {@code CompletionService}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions taken by that task, which in turn <i>happen-before</i>
+ * actions following a successful return from the corresponding {@code take()}.
+ */
+public interface CompletionService<V> {
+    /**
+     * Submits a value-returning task for execution and returns a Future
+     * representing the pending results of the task.  Upon completion,
+     * this task may be taken or polled.
+     *
+     * @param task the task to submit
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    Future<V> submit(Callable<V> task);
+
+    /**
+     * Submits a Runnable task for execution and returns a Future
+     * representing that task.  Upon completion, this task may be
+     * taken or polled.
+     *
+     * @param task the task to submit
+     * @param result the result to return upon successful completion
+     * @return a Future representing pending completion of the task,
+     *         and whose {@code get()} method will return the given
+     *         result value upon completion
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    Future<V> submit(Runnable task, V result);
+
+    /**
+     * Retrieves and removes the Future representing the next
+     * completed task, waiting if none are yet present.
+     *
+     * @return the Future representing the next completed task
+     * @throws InterruptedException if interrupted while waiting
+     */
+    Future<V> take() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the Future representing the next
+     * completed task, or {@code null} if none are present.
+     *
+     * @return the Future representing the next completed task, or
+     *         {@code null} if none are present
+     */
+    Future<V> poll();
+
+    /**
+     * Retrieves and removes the Future representing the next
+     * completed task, waiting if necessary up to the specified wait
+     * time if none are yet present.
+     *
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the Future representing the next completed task or
+     *         {@code null} if the specified waiting time elapses
+     *         before one is present
+     * @throws InterruptedException if interrupted while waiting
+     */
+    Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
+}
diff --git a/java/util/concurrent/CompletionStage.java b/java/util/concurrent/CompletionStage.java
new file mode 100644
index 0000000..d855945
--- /dev/null
+++ b/java/util/concurrent/CompletionStage.java
@@ -0,0 +1,869 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * A stage of a possibly asynchronous computation, that performs an
+ * action or computes a value when another CompletionStage completes.
+ * A stage completes upon termination of its computation, but this may
+ * in turn trigger other dependent stages.  The functionality defined
+ * in this interface takes only a few basic forms, which expand out to
+ * a larger set of methods to capture a range of usage styles:
+ *
+ * <ul>
+ *
+ * <li>The computation performed by a stage may be expressed as a
+ * Function, Consumer, or Runnable (using methods with names including
+ * <em>apply</em>, <em>accept</em>, or <em>run</em>, respectively)
+ * depending on whether it requires arguments and/or produces results.
+ * For example:
+ * <pre> {@code
+ * stage.thenApply(x -> square(x))
+ *      .thenAccept(x -> System.out.print(x))
+ *      .thenRun(() -> System.out.println());}</pre>
+ *
+ * An additional form (<em>compose</em>) allows the construction of
+ * computation pipelines from functions returning completion stages.
+ *
+ * <p>Any argument to a stage's computation is the outcome of a
+ * triggering stage's computation.
+ *
+ * <li>One stage's execution may be triggered by completion of a
+ * single stage, or both of two stages, or either of two stages.
+ * Dependencies on a single stage are arranged using methods with
+ * prefix <em>then</em>. Those triggered by completion of
+ * <em>both</em> of two stages may <em>combine</em> their results or
+ * effects, using correspondingly named methods. Those triggered by
+ * <em>either</em> of two stages make no guarantees about which of the
+ * results or effects are used for the dependent stage's computation.
+ *
+ * <li>Dependencies among stages control the triggering of
+ * computations, but do not otherwise guarantee any particular
+ * ordering. Additionally, execution of a new stage's computations may
+ * be arranged in any of three ways: default execution, default
+ * asynchronous execution (using methods with suffix <em>async</em>
+ * that employ the stage's default asynchronous execution facility),
+ * or custom (via a supplied {@link Executor}).  The execution
+ * properties of default and async modes are specified by
+ * CompletionStage implementations, not this interface. Methods with
+ * explicit Executor arguments may have arbitrary execution
+ * properties, and might not even support concurrent execution, but
+ * are arranged for processing in a way that accommodates asynchrony.
+ *
+ * <li>Two method forms ({@link #handle handle} and {@link
+ * #whenComplete whenComplete}) support unconditional computation
+ * whether the triggering stage completed normally or exceptionally.
+ * Method {@link #exceptionally exceptionally} supports computation
+ * only when the triggering stage completes exceptionally, computing a
+ * replacement result, similarly to the java {@code catch} keyword.
+ * In all other cases, if a stage's computation terminates abruptly
+ * with an (unchecked) exception or error, then all dependent stages
+ * requiring its completion complete exceptionally as well, with a
+ * {@link CompletionException} holding the exception as its cause.  If
+ * a stage is dependent on <em>both</em> of two stages, and both
+ * complete exceptionally, then the CompletionException may correspond
+ * to either one of these exceptions.  If a stage is dependent on
+ * <em>either</em> of two others, and only one of them completes
+ * exceptionally, no guarantees are made about whether the dependent
+ * stage completes normally or exceptionally. In the case of method
+ * {@code whenComplete}, when the supplied action itself encounters an
+ * exception, then the stage completes exceptionally with this
+ * exception unless the source stage also completed exceptionally, in
+ * which case the exceptional completion from the source stage is
+ * given preference and propagated to the dependent stage.
+ *
+ * </ul>
+ *
+ * <p>All methods adhere to the above triggering, execution, and
+ * exceptional completion specifications (which are not repeated in
+ * individual method specifications). Additionally, while arguments
+ * used to pass a completion result (that is, for parameters of type
+ * {@code T}) for methods accepting them may be null, passing a null
+ * value for any other parameter will result in a {@link
+ * NullPointerException} being thrown.
+ *
+ * <p>Method form {@link #handle handle} is the most general way of
+ * creating a continuation stage, unconditionally performing a
+ * computation that is given both the result and exception (if any) of
+ * the triggering CompletionStage, and computing an arbitrary result.
+ * Method {@link #whenComplete whenComplete} is similar, but preserves
+ * the result of the triggering stage instead of computing a new one.
+ * Because a stage's normal result may be {@code null}, both methods
+ * should have a computation structured thus:
+ *
+ * <pre>{@code (result, exception) -> {
+ *   if (exception == null) {
+ *     // triggering stage completed normally
+ *   } else {
+ *     // triggering stage completed exceptionally
+ *   }
+ * }}</pre>
+ *
+ * <p>This interface does not define methods for initially creating,
+ * forcibly completing normally or exceptionally, probing completion
+ * status or results, or awaiting completion of a stage.
+ * Implementations of CompletionStage may provide means of achieving
+ * such effects, as appropriate.  Method {@link #toCompletableFuture}
+ * enables interoperability among different implementations of this
+ * interface by providing a common conversion type.
+ *
+ * @author Doug Lea
+ * @since 1.8
+ */
+public interface CompletionStage<T> {
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed with this stage's result as the argument
+     * to the supplied function.
+     *
+     * <p>This method is analogous to
+     * {@link java.util.Optional#map Optional.map} and
+     * {@link java.util.stream.Stream#map Stream.map}.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using this stage's default asynchronous
+     * execution facility, with this stage's result as the argument to
+     * the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenApplyAsync
+        (Function<? super T,? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using the supplied Executor, with this
+     * stage's result as the argument to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenApplyAsync
+        (Function<? super T,? extends U> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed with this stage's result as the argument
+     * to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenAccept(Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using this stage's default asynchronous
+     * execution facility, with this stage's result as the argument to
+     * the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using the supplied Executor, with this
+     * stage's result as the argument to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,
+                                                 Executor executor);
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, executes the given action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenRun(Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, executes the given action using this stage's default
+     * asynchronous execution facility.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenRunAsync(Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, executes the given action using the supplied Executor.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenRunAsync(Runnable action,
+                                              Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed with the two
+     * results as arguments to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @param <V> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U,V> CompletionStage<V> thenCombine
+        (CompletionStage<? extends U> other,
+         BiFunction<? super T,? super U,? extends V> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the two
+     * results as arguments to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @param <V> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U,V> CompletionStage<V> thenCombineAsync
+        (CompletionStage<? extends U> other,
+         BiFunction<? super T,? super U,? extends V> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using the
+     * supplied executor, with the two results as arguments to the
+     * supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the type of the other CompletionStage's result
+     * @param <V> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U,V> CompletionStage<V> thenCombineAsync
+        (CompletionStage<? extends U> other,
+         BiFunction<? super T,? super U,? extends V> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed with the two
+     * results as arguments to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<Void> thenAcceptBoth
+        (CompletionStage<? extends U> other,
+         BiConsumer<? super T, ? super U> action);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the two
+     * results as arguments to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<Void> thenAcceptBothAsync
+        (CompletionStage<? extends U> other,
+         BiConsumer<? super T, ? super U> action);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using the
+     * supplied executor, with the two results as arguments to the
+     * supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the type of the other CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<Void> thenAcceptBothAsync
+        (CompletionStage<? extends U> other,
+         BiConsumer<? super T, ? super U> action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, executes the given action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,
+                                              Runnable action);
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, executes the given action
+     * using this stage's default asynchronous execution facility.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                   Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, executes the given action
+     * using the supplied executor.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                   Runnable action,
+                                                   Executor executor);
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed with the
+     * corresponding result as argument to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> applyToEither
+        (CompletionStage<? extends T> other,
+         Function<? super T, U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the
+     * corresponding result as argument to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> applyToEitherAsync
+        (CompletionStage<? extends T> other,
+         Function<? super T, U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using the
+     * supplied executor, with the corresponding result as argument to
+     * the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> applyToEitherAsync
+        (CompletionStage<? extends T> other,
+         Function<? super T, U> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed with the
+     * corresponding result as argument to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> acceptEither
+        (CompletionStage<? extends T> other,
+         Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the
+     * corresponding result as argument to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> acceptEitherAsync
+        (CompletionStage<? extends T> other,
+         Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using the
+     * supplied executor, with the corresponding result as argument to
+     * the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> acceptEitherAsync
+        (CompletionStage<? extends T> other,
+         Consumer<? super T> action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, executes the given action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterEither(CompletionStage<?> other,
+                                                Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, executes the given action
+     * using this stage's default asynchronous execution facility.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterEitherAsync
+        (CompletionStage<?> other,
+         Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, executes the given action
+     * using the supplied executor.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterEitherAsync
+        (CompletionStage<?> other,
+         Runnable action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that is completed with the same
+     * value as the CompletionStage returned by the given function.
+     *
+     * <p>When this stage completes normally, the given function is
+     * invoked with this stage's result as the argument, returning
+     * another CompletionStage.  When that stage completes normally,
+     * the CompletionStage returned by this method is completed with
+     * the same value.
+     *
+     * <p>To ensure progress, the supplied function must arrange
+     * eventual completion of its result.
+     *
+     * <p>This method is analogous to
+     * {@link java.util.Optional#flatMap Optional.flatMap} and
+     * {@link java.util.stream.Stream#flatMap Stream.flatMap}.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute another CompletionStage
+     * @param <U> the type of the returned CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenCompose
+        (Function<? super T, ? extends CompletionStage<U>> fn);
+
+    /**
+     * Returns a new CompletionStage that is completed with the same
+     * value as the CompletionStage returned by the given function,
+     * executed using this stage's default asynchronous execution
+     * facility.
+     *
+     * <p>When this stage completes normally, the given function is
+     * invoked with this stage's result as the argument, returning
+     * another CompletionStage.  When that stage completes normally,
+     * the CompletionStage returned by this method is completed with
+     * the same value.
+     *
+     * <p>To ensure progress, the supplied function must arrange
+     * eventual completion of its result.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute another CompletionStage
+     * @param <U> the type of the returned CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenComposeAsync
+        (Function<? super T, ? extends CompletionStage<U>> fn);
+
+    /**
+     * Returns a new CompletionStage that is completed with the same
+     * value as the CompletionStage returned by the given function,
+     * executed using the supplied Executor.
+     *
+     * <p>When this stage completes normally, the given function is
+     * invoked with this stage's result as the argument, returning
+     * another CompletionStage.  When that stage completes normally,
+     * the CompletionStage returned by this method is completed with
+     * the same value.
+     *
+     * <p>To ensure progress, the supplied function must arrange
+     * eventual completion of its result.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute another CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the type of the returned CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenComposeAsync
+        (Function<? super T, ? extends CompletionStage<U>> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * either normally or exceptionally, is executed with this stage's
+     * result and exception as arguments to the supplied function.
+     *
+     * <p>When this stage is complete, the given function is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments, and the
+     * function's result is used to complete the returned stage.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> handle
+        (BiFunction<? super T, Throwable, ? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * either normally or exceptionally, is executed using this stage's
+     * default asynchronous execution facility, with this stage's
+     * result and exception as arguments to the supplied function.
+     *
+     * <p>When this stage is complete, the given function is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments, and the
+     * function's result is used to complete the returned stage.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> handleAsync
+        (BiFunction<? super T, Throwable, ? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * either normally or exceptionally, is executed using the
+     * supplied executor, with this stage's result and exception as
+     * arguments to the supplied function.
+     *
+     * <p>When this stage is complete, the given function is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments, and the
+     * function's result is used to complete the returned stage.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> handleAsync
+        (BiFunction<? super T, Throwable, ? extends U> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage with the same result or exception as
+     * this stage, that executes the given action when this stage completes.
+     *
+     * <p>When this stage is complete, the given action is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments.  The returned
+     * stage is completed when the action returns.
+     *
+     * <p>Unlike method {@link #handle handle},
+     * this method is not designed to translate completion outcomes,
+     * so the supplied action should not throw an exception. However,
+     * if it does, the following rules apply: if this stage completed
+     * normally but the supplied action throws an exception, then the
+     * returned stage completes exceptionally with the supplied
+     * action's exception. Or, if this stage completed exceptionally
+     * and the supplied action throws an exception, then the returned
+     * stage completes exceptionally with this stage's exception.
+     *
+     * @param action the action to perform
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> whenComplete
+        (BiConsumer<? super T, ? super Throwable> action);
+
+    /**
+     * Returns a new CompletionStage with the same result or exception as
+     * this stage, that executes the given action using this stage's
+     * default asynchronous execution facility when this stage completes.
+     *
+     * <p>When this stage is complete, the given action is invoked with the
+     * result (or {@code null} if none) and the exception (or {@code null}
+     * if none) of this stage as arguments.  The returned stage is completed
+     * when the action returns.
+     *
+     * <p>Unlike method {@link #handleAsync(BiFunction) handleAsync},
+     * this method is not designed to translate completion outcomes,
+     * so the supplied action should not throw an exception. However,
+     * if it does, the following rules apply: If this stage completed
+     * normally but the supplied action throws an exception, then the
+     * returned stage completes exceptionally with the supplied
+     * action's exception. Or, if this stage completed exceptionally
+     * and the supplied action throws an exception, then the returned
+     * stage completes exceptionally with this stage's exception.
+     *
+     * @param action the action to perform
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> whenCompleteAsync
+        (BiConsumer<? super T, ? super Throwable> action);
+
+    /**
+     * Returns a new CompletionStage with the same result or exception as
+     * this stage, that executes the given action using the supplied
+     * Executor when this stage completes.
+     *
+     * <p>When this stage is complete, the given action is invoked with the
+     * result (or {@code null} if none) and the exception (or {@code null}
+     * if none) of this stage as arguments.  The returned stage is completed
+     * when the action returns.
+     *
+     * <p>Unlike method {@link #handleAsync(BiFunction,Executor) handleAsync},
+     * this method is not designed to translate completion outcomes,
+     * so the supplied action should not throw an exception. However,
+     * if it does, the following rules apply: If this stage completed
+     * normally but the supplied action throws an exception, then the
+     * returned stage completes exceptionally with the supplied
+     * action's exception. Or, if this stage completed exceptionally
+     * and the supplied action throws an exception, then the returned
+     * stage completes exceptionally with this stage's exception.
+     *
+     * @param action the action to perform
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> whenCompleteAsync
+        (BiConsumer<? super T, ? super Throwable> action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * exceptionally, is executed with this stage's exception as the
+     * argument to the supplied function.  Otherwise, if this stage
+     * completes normally, then the returned stage also completes
+     * normally with the same value.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage if this CompletionStage completed
+     * exceptionally
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> exceptionally
+        (Function<Throwable, ? extends T> fn);
+
+    /**
+     * Returns a {@link CompletableFuture} maintaining the same
+     * completion properties as this stage. If this stage is already a
+     * CompletableFuture, this method may return this stage itself.
+     * Otherwise, invocation of this method may be equivalent in
+     * effect to {@code thenApply(x -> x)}, but returning an instance
+     * of type {@code CompletableFuture}. A CompletionStage
+     * implementation that does not choose to interoperate with others
+     * may throw {@code UnsupportedOperationException}.
+     *
+     * @return the CompletableFuture
+     * @throws UnsupportedOperationException if this implementation
+     * does not interoperate with CompletableFuture
+     */
+    public CompletableFuture<T> toCompletableFuture();
+
+}
diff --git a/java/util/concurrent/ConcurrentHashMap.annotated.java b/java/util/concurrent/ConcurrentHashMap.annotated.java
new file mode 100644
index 0000000..bf53e84
--- /dev/null
+++ b/java/util/concurrent/ConcurrentHashMap.annotated.java
@@ -0,0 +1,238 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+
+package java.util.concurrent;
+
+import java.util.Set;
+import java.util.HashMap;
+import java.util.AbstractMap;
+import java.util.Iterator;
+import java.util.stream.Stream;
+import java.util.Spliterator;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Collection;
+import java.util.function.Function;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ConcurrentHashMap<K, V> extends java.util.AbstractMap<@libcore.util.NonNull K, @libcore.util.NonNull V> implements java.util.concurrent.ConcurrentMap<@libcore.util.NonNull K, @libcore.util.NonNull V>, java.io.Serializable {
+
+  public ConcurrentHashMap() { throw new RuntimeException("Stub!"); }
+
+  public ConcurrentHashMap(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+  public ConcurrentHashMap(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NonNull K,? extends @libcore.util.NonNull V> m) { throw new RuntimeException("Stub!"); }
+
+  public ConcurrentHashMap(int initialCapacity, float loadFactor) { throw new RuntimeException("Stub!"); }
+
+  public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { throw new RuntimeException("Stub!"); }
+
+  public int size() { throw new RuntimeException("Stub!"); }
+
+  public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V get(@libcore.util.NonNull java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+  public boolean containsKey(@libcore.util.NonNull java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+  public boolean containsValue(@libcore.util.NonNull java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V put(@libcore.util.NonNull K key, @libcore.util.NonNull V value) { throw new RuntimeException("Stub!"); }
+
+  public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NonNull K,? extends @libcore.util.NonNull V> m) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V remove(@libcore.util.NonNull java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+  public void clear() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.Set<@libcore.util.NonNull K> keySet() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.Collection<@libcore.util.NonNull V> values() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.Set<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> entrySet() { throw new RuntimeException("Stub!"); }
+
+  public int hashCode() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+  public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V putIfAbsent(@libcore.util.NonNull K key, @libcore.util.NonNull V value) { throw new RuntimeException("Stub!"); }
+
+  public boolean remove(@libcore.util.NonNull java.lang.Object key, @libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+  public boolean replace(@libcore.util.NonNull K key, @libcore.util.NonNull V oldValue, @libcore.util.NonNull V newValue) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V replace(@libcore.util.NonNull K key, @libcore.util.NonNull V value) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V getOrDefault(@libcore.util.NonNull java.lang.Object key, @libcore.util.Nullable V defaultValue) { throw new RuntimeException("Stub!"); }
+
+  public void forEach(@libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V> action) { throw new RuntimeException("Stub!"); }
+
+  public void replaceAll(@libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V,? extends @libcore.util.NonNull V> function) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V computeIfAbsent(@libcore.util.NonNull K key, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull K,? extends @libcore.util.Nullable V> mappingFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V computeIfPresent(@libcore.util.NonNull K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V compute(@libcore.util.NonNull K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.Nullable V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V merge(@libcore.util.NonNull K key, @libcore.util.NonNull V value, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull V,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+  public boolean contains(@libcore.util.NonNull java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.Enumeration<@libcore.util.NonNull K> keys() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.Enumeration<@libcore.util.NonNull V> elements() { throw new RuntimeException("Stub!"); }
+
+  public long mappingCount() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public static <@libcore.util.NonNull K> java.util.concurrent.ConcurrentHashMap.KeySetView<@libcore.util.NonNull K, @libcore.util.NonNull java.lang.Boolean> newKeySet() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public static <@libcore.util.NonNull K> java.util.concurrent.ConcurrentHashMap.KeySetView<@libcore.util.NonNull K, @libcore.util.NonNull java.lang.Boolean> newKeySet(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.concurrent.ConcurrentHashMap.KeySetView<@libcore.util.NonNull K, @libcore.util.NonNull V> keySet(@libcore.util.NonNull V mappedValue) { throw new RuntimeException("Stub!"); }
+
+  public void forEach(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V> action) { throw new RuntimeException("Stub!"); }
+
+  public <U> void forEach(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull U> action) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U search(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> searchFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U reduce(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull U,? super @libcore.util.NonNull U,? extends @libcore.util.Nullable U> reducer) { throw new RuntimeException("Stub!"); }
+
+  public double reduceToDouble(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToDoubleBiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V> transformer, double basis, @libcore.util.NonNull java.util.function.DoubleBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public long reduceToLong(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToLongBiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V> transformer, long basis, @libcore.util.NonNull java.util.function.LongBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public int reduceToInt(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToIntBiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V> transformer, int basis, @libcore.util.NonNull java.util.function.IntBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public void forEachKey(long parallelismThreshold, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull K> action) { throw new RuntimeException("Stub!"); }
+
+  public <U> void forEachKey(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull K,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull U> action) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U searchKeys(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull K,? extends @libcore.util.Nullable U> searchFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public K reduceKeys(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull K,? extends @libcore.util.Nullable K> reducer) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U reduceKeys(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull K,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull U,? super @libcore.util.NonNull U,? extends @libcore.util.Nullable U> reducer) { throw new RuntimeException("Stub!"); }
+
+  public double reduceKeysToDouble(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToDoubleFunction<? super @libcore.util.NonNull K> transformer, double basis, @libcore.util.NonNull java.util.function.DoubleBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public long reduceKeysToLong(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToLongFunction<? super @libcore.util.NonNull K> transformer, long basis, @libcore.util.NonNull java.util.function.LongBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public int reduceKeysToInt(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToIntFunction<? super @libcore.util.NonNull K> transformer, int basis, @libcore.util.NonNull java.util.function.IntBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public void forEachValue(long parallelismThreshold, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull V> action) { throw new RuntimeException("Stub!"); }
+
+  public <U> void forEachValue(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull U> action) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U searchValues(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> searchFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V reduceValues(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull V,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> reducer) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U reduceValues(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull U,? super @libcore.util.NonNull U,? extends @libcore.util.Nullable U> reducer) { throw new RuntimeException("Stub!"); }
+
+  public double reduceValuesToDouble(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToDoubleFunction<? super @libcore.util.NonNull V> transformer, double basis, @libcore.util.NonNull java.util.function.DoubleBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public long reduceValuesToLong(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToLongFunction<? super @libcore.util.NonNull V> transformer, long basis, @libcore.util.NonNull java.util.function.LongBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public int reduceValuesToInt(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToIntFunction<? super @libcore.util.NonNull V> transformer, int basis, @libcore.util.NonNull java.util.function.IntBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public void forEachEntry(long parallelismThreshold, @libcore.util.NonNull java.util.function.Consumer<? super [email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> action) { throw new RuntimeException("Stub!"); }
+
+  public <U> void forEachEntry(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull U> action) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U searchEntries(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>,? extends @libcore.util.Nullable U> searchFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public java.util.Map.Entry<@libcore.util.NonNull K, @libcore.util.NonNull V> reduceEntries(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>, [email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>,? extends [email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> reducer) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U reduceEntries(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull U,? super @libcore.util.NonNull U,? extends @libcore.util.Nullable U> reducer) { throw new RuntimeException("Stub!"); }
+
+  public double reduceEntriesToDouble(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToDoubleFunction<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> transformer, double basis, @libcore.util.NonNull java.util.function.DoubleBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public long reduceEntriesToLong(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToLongFunction<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> transformer, long basis, @libcore.util.NonNull java.util.function.LongBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public int reduceEntriesToInt(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToIntFunction<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> transformer, int basis, @libcore.util.NonNull java.util.function.IntBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  @SuppressWarnings({"unchecked", "deprecation", "all"})
+  public static class KeySetView<K, V> implements java.util.Collection<K>, java.io.Serializable, java.util.Set<K> {
+
+    KeySetView(@libcore.util.NonNull java.util.concurrent.ConcurrentHashMap<K,V> map, @libcore.util.Nullable V value) { throw new RuntimeException("Stub!"); }
+
+    @libcore.util.Nullable public V getMappedValue() { throw new RuntimeException("Stub!"); }
+
+    public boolean contains(@libcore.util.NonNull java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+    public boolean remove(@libcore.util.NonNull java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+    @libcore.util.NonNull public java.util.Iterator<@libcore.util.NonNull K> iterator() { throw new RuntimeException("Stub!"); }
+
+    public boolean add(@libcore.util.NonNull K e) { throw new RuntimeException("Stub!"); }
+
+    public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NonNull K> c) { throw new RuntimeException("Stub!"); }
+
+    public int hashCode() { throw new RuntimeException("Stub!"); }
+
+    public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+    @libcore.util.NonNull public java.util.Spliterator<@libcore.util.NonNull K> spliterator() { throw new RuntimeException("Stub!"); }
+
+    public void forEach(@libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull K> action) { throw new RuntimeException("Stub!"); }
+
+    public final boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+    public final int size() { throw new RuntimeException("Stub!"); }
+
+    public final boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+    public final void clear() { throw new RuntimeException("Stub!"); }
+
+    public final boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+    public final [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+    public final <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+    @libcore.util.NonNull public final java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+    @libcore.util.NonNull public java.util.concurrent.ConcurrentHashMap<@libcore.util.NonNull K, @libcore.util.NonNull V> getMap() { throw new RuntimeException("Stub!"); }
+
+    public final boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+  }
+
+}
diff --git a/java/util/concurrent/ConcurrentHashMap.java b/java/util/concurrent/ConcurrentHashMap.java
new file mode 100644
index 0000000..5407963
--- /dev/null
+++ b/java/util/concurrent/ConcurrentHashMap.java
@@ -0,0 +1,6383 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.Predicate;
+import java.util.function.ToDoubleBiFunction;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntBiFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongBiFunction;
+import java.util.function.ToLongFunction;
+import java.util.stream.Stream;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A hash table supporting full concurrency of retrievals and
+ * high expected concurrency for updates. This class obeys the
+ * same functional specification as {@link java.util.Hashtable}, and
+ * includes versions of methods corresponding to each method of
+ * {@code Hashtable}. However, even though all operations are
+ * thread-safe, retrieval operations do <em>not</em> entail locking,
+ * and there is <em>not</em> any support for locking the entire table
+ * in a way that prevents all access.  This class is fully
+ * interoperable with {@code Hashtable} in programs that rely on its
+ * thread safety but not on its synchronization details.
+ *
+ * <p>Retrieval operations (including {@code get}) generally do not
+ * block, so may overlap with update operations (including {@code put}
+ * and {@code remove}). Retrievals reflect the results of the most
+ * recently <em>completed</em> update operations holding upon their
+ * onset. (More formally, an update operation for a given key bears a
+ * <em>happens-before</em> relation with any (non-null) retrieval for
+ * that key reporting the updated value.)  For aggregate operations
+ * such as {@code putAll} and {@code clear}, concurrent retrievals may
+ * reflect insertion or removal of only some entries.  Similarly,
+ * Iterators, Spliterators and Enumerations return elements reflecting the
+ * state of the hash table at some point at or since the creation of the
+ * iterator/enumeration.  They do <em>not</em> throw {@link
+ * java.util.ConcurrentModificationException ConcurrentModificationException}.
+ * However, iterators are designed to be used by only one thread at a time.
+ * Bear in mind that the results of aggregate status methods including
+ * {@code size}, {@code isEmpty}, and {@code containsValue} are typically
+ * useful only when a map is not undergoing concurrent updates in other threads.
+ * Otherwise the results of these methods reflect transient states
+ * that may be adequate for monitoring or estimation purposes, but not
+ * for program control.
+ *
+ * <p>The table is dynamically expanded when there are too many
+ * collisions (i.e., keys that have distinct hash codes but fall into
+ * the same slot modulo the table size), with the expected average
+ * effect of maintaining roughly two bins per mapping (corresponding
+ * to a 0.75 load factor threshold for resizing). There may be much
+ * variance around this average as mappings are added and removed, but
+ * overall, this maintains a commonly accepted time/space tradeoff for
+ * hash tables.  However, resizing this or any other kind of hash
+ * table may be a relatively slow operation. When possible, it is a
+ * good idea to provide a size estimate as an optional {@code
+ * initialCapacity} constructor argument. An additional optional
+ * {@code loadFactor} constructor argument provides a further means of
+ * customizing initial table capacity by specifying the table density
+ * to be used in calculating the amount of space to allocate for the
+ * given number of elements.  Also, for compatibility with previous
+ * versions of this class, constructors may optionally specify an
+ * expected {@code concurrencyLevel} as an additional hint for
+ * internal sizing.  Note that using many keys with exactly the same
+ * {@code hashCode()} is a sure way to slow down performance of any
+ * hash table. To ameliorate impact, when keys are {@link Comparable},
+ * this class may use comparison order among keys to help break ties.
+ *
+ * <p>A {@link Set} projection of a ConcurrentHashMap may be created
+ * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed
+ * (using {@link #keySet(Object)} when only keys are of interest, and the
+ * mapped values are (perhaps transiently) not used or all take the
+ * same mapping value.
+ *
+ * <p>A ConcurrentHashMap can be used as a scalable frequency map (a
+ * form of histogram or multiset) by using {@link
+ * java.util.concurrent.atomic.LongAdder} values and initializing via
+ * {@link #computeIfAbsent computeIfAbsent}. For example, to add a count
+ * to a {@code ConcurrentHashMap<String,LongAdder> freqs}, you can use
+ * {@code freqs.computeIfAbsent(key, k -> new LongAdder()).increment();}
+ *
+ * <p>This class and its views and iterators implement all of the
+ * <em>optional</em> methods of the {@link Map} and {@link Iterator}
+ * interfaces.
+ *
+ * <p>Like {@link Hashtable} but unlike {@link HashMap}, this class
+ * does <em>not</em> allow {@code null} to be used as a key or value.
+ *
+ * <p>ConcurrentHashMaps support a set of sequential and parallel bulk
+ * operations that, unlike most {@link Stream} methods, are designed
+ * to be safely, and often sensibly, applied even with maps that are
+ * being concurrently updated by other threads; for example, when
+ * computing a snapshot summary of the values in a shared registry.
+ * There are three kinds of operation, each with four forms, accepting
+ * functions with keys, values, entries, and (key, value) pairs as
+ * arguments and/or return values. Because the elements of a
+ * ConcurrentHashMap are not ordered in any particular way, and may be
+ * processed in different orders in different parallel executions, the
+ * correctness of supplied functions should not depend on any
+ * ordering, or on any other objects or values that may transiently
+ * change while computation is in progress; and except for forEach
+ * actions, should ideally be side-effect-free. Bulk operations on
+ * {@link java.util.Map.Entry} objects do not support method {@code
+ * setValue}.
+ *
+ * <ul>
+ * <li>forEach: Performs a given action on each element.
+ * A variant form applies a given transformation on each element
+ * before performing the action.
+ *
+ * <li>search: Returns the first available non-null result of
+ * applying a given function on each element; skipping further
+ * search when a result is found.
+ *
+ * <li>reduce: Accumulates each element.  The supplied reduction
+ * function cannot rely on ordering (more formally, it should be
+ * both associative and commutative).  There are five variants:
+ *
+ * <ul>
+ *
+ * <li>Plain reductions. (There is not a form of this method for
+ * (key, value) function arguments since there is no corresponding
+ * return type.)
+ *
+ * <li>Mapped reductions that accumulate the results of a given
+ * function applied to each element.
+ *
+ * <li>Reductions to scalar doubles, longs, and ints, using a
+ * given basis value.
+ *
+ * </ul>
+ * </ul>
+ *
+ * <p>These bulk operations accept a {@code parallelismThreshold}
+ * argument. Methods proceed sequentially if the current map size is
+ * estimated to be less than the given threshold. Using a value of
+ * {@code Long.MAX_VALUE} suppresses all parallelism.  Using a value
+ * of {@code 1} results in maximal parallelism by partitioning into
+ * enough subtasks to fully utilize the {@link
+ * ForkJoinPool#commonPool()} that is used for all parallel
+ * computations. Normally, you would initially choose one of these
+ * extreme values, and then measure performance of using in-between
+ * values that trade off overhead versus throughput.
+ *
+ * <p>The concurrency properties of bulk operations follow
+ * from those of ConcurrentHashMap: Any non-null result returned
+ * from {@code get(key)} and related access methods bears a
+ * happens-before relation with the associated insertion or
+ * update.  The result of any bulk operation reflects the
+ * composition of these per-element relations (but is not
+ * necessarily atomic with respect to the map as a whole unless it
+ * is somehow known to be quiescent).  Conversely, because keys
+ * and values in the map are never null, null serves as a reliable
+ * atomic indicator of the current lack of any result.  To
+ * maintain this property, null serves as an implicit basis for
+ * all non-scalar reduction operations. For the double, long, and
+ * int versions, the basis should be one that, when combined with
+ * any other value, returns that other value (more formally, it
+ * should be the identity element for the reduction). Most common
+ * reductions have these properties; for example, computing a sum
+ * with basis 0 or a minimum with basis MAX_VALUE.
+ *
+ * <p>Search and transformation functions provided as arguments
+ * should similarly return null to indicate the lack of any result
+ * (in which case it is not used). In the case of mapped
+ * reductions, this also enables transformations to serve as
+ * filters, returning null (or, in the case of primitive
+ * specializations, the identity basis) if the element should not
+ * be combined. You can create compound transformations and
+ * filterings by composing them yourself under this "null means
+ * there is nothing there now" rule before using them in search or
+ * reduce operations.
+ *
+ * <p>Methods accepting and/or returning Entry arguments maintain
+ * key-value associations. They may be useful for example when
+ * finding the key for the greatest value. Note that "plain" Entry
+ * arguments can be supplied using {@code new
+ * AbstractMap.SimpleEntry(k,v)}.
+ *
+ * <p>Bulk operations may complete abruptly, throwing an
+ * exception encountered in the application of a supplied
+ * function. Bear in mind when handling such exceptions that other
+ * concurrently executing functions could also have thrown
+ * exceptions, or would have done so if the first exception had
+ * not occurred.
+ *
+ * <p>Speedups for parallel compared to sequential forms are common
+ * but not guaranteed.  Parallel operations involving brief functions
+ * on small maps may execute more slowly than sequential forms if the
+ * underlying work to parallelize the computation is more expensive
+ * than the computation itself.  Similarly, parallelization may not
+ * lead to much actual parallelism if all processors are busy
+ * performing unrelated tasks.
+ *
+ * <p>All arguments to all task methods must be non-null.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ */
+public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
+    implements ConcurrentMap<K,V>, Serializable {
+    private static final long serialVersionUID = 7249069246763182397L;
+
+    /*
+     * Overview:
+     *
+     * The primary design goal of this hash table is to maintain
+     * concurrent readability (typically method get(), but also
+     * iterators and related methods) while minimizing update
+     * contention. Secondary goals are to keep space consumption about
+     * the same or better than java.util.HashMap, and to support high
+     * initial insertion rates on an empty table by many threads.
+     *
+     * This map usually acts as a binned (bucketed) hash table.  Each
+     * key-value mapping is held in a Node.  Most nodes are instances
+     * of the basic Node class with hash, key, value, and next
+     * fields. However, various subclasses exist: TreeNodes are
+     * arranged in balanced trees, not lists.  TreeBins hold the roots
+     * of sets of TreeNodes. ForwardingNodes are placed at the heads
+     * of bins during resizing. ReservationNodes are used as
+     * placeholders while establishing values in computeIfAbsent and
+     * related methods.  The types TreeBin, ForwardingNode, and
+     * ReservationNode do not hold normal user keys, values, or
+     * hashes, and are readily distinguishable during search etc
+     * because they have negative hash fields and null key and value
+     * fields. (These special nodes are either uncommon or transient,
+     * so the impact of carrying around some unused fields is
+     * insignificant.)
+     *
+     * The table is lazily initialized to a power-of-two size upon the
+     * first insertion.  Each bin in the table normally contains a
+     * list of Nodes (most often, the list has only zero or one Node).
+     * Table accesses require volatile/atomic reads, writes, and
+     * CASes.  Because there is no other way to arrange this without
+     * adding further indirections, we use intrinsics
+     * (sun.misc.Unsafe) operations.
+     *
+     * We use the top (sign) bit of Node hash fields for control
+     * purposes -- it is available anyway because of addressing
+     * constraints.  Nodes with negative hash fields are specially
+     * handled or ignored in map methods.
+     *
+     * Insertion (via put or its variants) of the first node in an
+     * empty bin is performed by just CASing it to the bin.  This is
+     * by far the most common case for put operations under most
+     * key/hash distributions.  Other update operations (insert,
+     * delete, and replace) require locks.  We do not want to waste
+     * the space required to associate a distinct lock object with
+     * each bin, so instead use the first node of a bin list itself as
+     * a lock. Locking support for these locks relies on builtin
+     * "synchronized" monitors.
+     *
+     * Using the first node of a list as a lock does not by itself
+     * suffice though: When a node is locked, any update must first
+     * validate that it is still the first node after locking it, and
+     * retry if not. Because new nodes are always appended to lists,
+     * once a node is first in a bin, it remains first until deleted
+     * or the bin becomes invalidated (upon resizing).
+     *
+     * The main disadvantage of per-bin locks is that other update
+     * operations on other nodes in a bin list protected by the same
+     * lock can stall, for example when user equals() or mapping
+     * functions take a long time.  However, statistically, under
+     * random hash codes, this is not a common problem.  Ideally, the
+     * frequency of nodes in bins follows a Poisson distribution
+     * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
+     * parameter of about 0.5 on average, given the resizing threshold
+     * of 0.75, although with a large variance because of resizing
+     * granularity. Ignoring variance, the expected occurrences of
+     * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The
+     * first values are:
+     *
+     * 0:    0.60653066
+     * 1:    0.30326533
+     * 2:    0.07581633
+     * 3:    0.01263606
+     * 4:    0.00157952
+     * 5:    0.00015795
+     * 6:    0.00001316
+     * 7:    0.00000094
+     * 8:    0.00000006
+     * more: less than 1 in ten million
+     *
+     * Lock contention probability for two threads accessing distinct
+     * elements is roughly 1 / (8 * #elements) under random hashes.
+     *
+     * Actual hash code distributions encountered in practice
+     * sometimes deviate significantly from uniform randomness.  This
+     * includes the case when N > (1<<30), so some keys MUST collide.
+     * Similarly for dumb or hostile usages in which multiple keys are
+     * designed to have identical hash codes or ones that differs only
+     * in masked-out high bits. So we use a secondary strategy that
+     * applies when the number of nodes in a bin exceeds a
+     * threshold. These TreeBins use a balanced tree to hold nodes (a
+     * specialized form of red-black trees), bounding search time to
+     * O(log N).  Each search step in a TreeBin is at least twice as
+     * slow as in a regular list, but given that N cannot exceed
+     * (1<<64) (before running out of addresses) this bounds search
+     * steps, lock hold times, etc, to reasonable constants (roughly
+     * 100 nodes inspected per operation worst case) so long as keys
+     * are Comparable (which is very common -- String, Long, etc).
+     * TreeBin nodes (TreeNodes) also maintain the same "next"
+     * traversal pointers as regular nodes, so can be traversed in
+     * iterators in the same way.
+     *
+     * The table is resized when occupancy exceeds a percentage
+     * threshold (nominally, 0.75, but see below).  Any thread
+     * noticing an overfull bin may assist in resizing after the
+     * initiating thread allocates and sets up the replacement array.
+     * However, rather than stalling, these other threads may proceed
+     * with insertions etc.  The use of TreeBins shields us from the
+     * worst case effects of overfilling while resizes are in
+     * progress.  Resizing proceeds by transferring bins, one by one,
+     * from the table to the next table. However, threads claim small
+     * blocks of indices to transfer (via field transferIndex) before
+     * doing so, reducing contention.  A generation stamp in field
+     * sizeCtl ensures that resizings do not overlap. Because we are
+     * using power-of-two expansion, the elements from each bin must
+     * either stay at same index, or move with a power of two
+     * offset. We eliminate unnecessary node creation by catching
+     * cases where old nodes can be reused because their next fields
+     * won't change.  On average, only about one-sixth of them need
+     * cloning when a table doubles. The nodes they replace will be
+     * garbage collectable as soon as they are no longer referenced by
+     * any reader thread that may be in the midst of concurrently
+     * traversing table.  Upon transfer, the old table bin contains
+     * only a special forwarding node (with hash field "MOVED") that
+     * contains the next table as its key. On encountering a
+     * forwarding node, access and update operations restart, using
+     * the new table.
+     *
+     * Each bin transfer requires its bin lock, which can stall
+     * waiting for locks while resizing. However, because other
+     * threads can join in and help resize rather than contend for
+     * locks, average aggregate waits become shorter as resizing
+     * progresses.  The transfer operation must also ensure that all
+     * accessible bins in both the old and new table are usable by any
+     * traversal.  This is arranged in part by proceeding from the
+     * last bin (table.length - 1) up towards the first.  Upon seeing
+     * a forwarding node, traversals (see class Traverser) arrange to
+     * move to the new table without revisiting nodes.  To ensure that
+     * no intervening nodes are skipped even when moved out of order,
+     * a stack (see class TableStack) is created on first encounter of
+     * a forwarding node during a traversal, to maintain its place if
+     * later processing the current table. The need for these
+     * save/restore mechanics is relatively rare, but when one
+     * forwarding node is encountered, typically many more will be.
+     * So Traversers use a simple caching scheme to avoid creating so
+     * many new TableStack nodes. (Thanks to Peter Levart for
+     * suggesting use of a stack here.)
+     *
+     * The traversal scheme also applies to partial traversals of
+     * ranges of bins (via an alternate Traverser constructor)
+     * to support partitioned aggregate operations.  Also, read-only
+     * operations give up if ever forwarded to a null table, which
+     * provides support for shutdown-style clearing, which is also not
+     * currently implemented.
+     *
+     * Lazy table initialization minimizes footprint until first use,
+     * and also avoids resizings when the first operation is from a
+     * putAll, constructor with map argument, or deserialization.
+     * These cases attempt to override the initial capacity settings,
+     * but harmlessly fail to take effect in cases of races.
+     *
+     * The element count is maintained using a specialization of
+     * LongAdder. We need to incorporate a specialization rather than
+     * just use a LongAdder in order to access implicit
+     * contention-sensing that leads to creation of multiple
+     * CounterCells.  The counter mechanics avoid contention on
+     * updates but can encounter cache thrashing if read too
+     * frequently during concurrent access. To avoid reading so often,
+     * resizing under contention is attempted only upon adding to a
+     * bin already holding two or more nodes. Under uniform hash
+     * distributions, the probability of this occurring at threshold
+     * is around 13%, meaning that only about 1 in 8 puts check
+     * threshold (and after resizing, many fewer do so).
+     *
+     * TreeBins use a special form of comparison for search and
+     * related operations (which is the main reason we cannot use
+     * existing collections such as TreeMaps). TreeBins contain
+     * Comparable elements, but may contain others, as well as
+     * elements that are Comparable but not necessarily Comparable for
+     * the same T, so we cannot invoke compareTo among them. To handle
+     * this, the tree is ordered primarily by hash value, then by
+     * Comparable.compareTo order if applicable.  On lookup at a node,
+     * if elements are not comparable or compare as 0 then both left
+     * and right children may need to be searched in the case of tied
+     * hash values. (This corresponds to the full list search that
+     * would be necessary if all elements were non-Comparable and had
+     * tied hashes.) On insertion, to keep a total ordering (or as
+     * close as is required here) across rebalancings, we compare
+     * classes and identityHashCodes as tie-breakers. The red-black
+     * balancing code is updated from pre-jdk-collections
+     * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java)
+     * based in turn on Cormen, Leiserson, and Rivest "Introduction to
+     * Algorithms" (CLR).
+     *
+     * TreeBins also require an additional locking mechanism.  While
+     * list traversal is always possible by readers even during
+     * updates, tree traversal is not, mainly because of tree-rotations
+     * that may change the root node and/or its linkages.  TreeBins
+     * include a simple read-write lock mechanism parasitic on the
+     * main bin-synchronization strategy: Structural adjustments
+     * associated with an insertion or removal are already bin-locked
+     * (and so cannot conflict with other writers) but must wait for
+     * ongoing readers to finish. Since there can be only one such
+     * waiter, we use a simple scheme using a single "waiter" field to
+     * block writers.  However, readers need never block.  If the root
+     * lock is held, they proceed along the slow traversal path (via
+     * next-pointers) until the lock becomes available or the list is
+     * exhausted, whichever comes first. These cases are not fast, but
+     * maximize aggregate expected throughput.
+     *
+     * Maintaining API and serialization compatibility with previous
+     * versions of this class introduces several oddities. Mainly: We
+     * leave untouched but unused constructor arguments referring to
+     * concurrencyLevel. We accept a loadFactor constructor argument,
+     * but apply it only to initial table capacity (which is the only
+     * time that we can guarantee to honor it.) We also declare an
+     * unused "Segment" class that is instantiated in minimal form
+     * only when serializing.
+     *
+     * Also, solely for compatibility with previous versions of this
+     * class, it extends AbstractMap, even though all of its methods
+     * are overridden, so it is just useless baggage.
+     *
+     * This file is organized to make things a little easier to follow
+     * while reading than they might otherwise: First the main static
+     * declarations and utilities, then fields, then main public
+     * methods (with a few factorings of multiple public methods into
+     * internal ones), then sizing methods, trees, traversers, and
+     * bulk operations.
+     */
+
+    /* ---------------- Constants -------------- */
+
+    /**
+     * The largest possible table capacity.  This value must be
+     * exactly 1<<30 to stay within Java array allocation and indexing
+     * bounds for power of two table sizes, and is further required
+     * because the top two bits of 32bit hash fields are used for
+     * control purposes.
+     */
+    private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The default initial table capacity.  Must be a power of 2
+     * (i.e., at least 1) and at most MAXIMUM_CAPACITY.
+     */
+    private static final int DEFAULT_CAPACITY = 16;
+
+    /**
+     * The largest possible (non-power of two) array size.
+     * Needed by toArray and related methods.
+     */
+    static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * The default concurrency level for this table. Unused but
+     * defined for compatibility with previous versions of this class.
+     */
+    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
+
+    /**
+     * The load factor for this table. Overrides of this value in
+     * constructors affect only the initial table capacity.  The
+     * actual floating point value isn't normally used -- it is
+     * simpler to use expressions such as {@code n - (n >>> 2)} for
+     * the associated resizing threshold.
+     */
+    private static final float LOAD_FACTOR = 0.75f;
+
+    /**
+     * The bin count threshold for using a tree rather than list for a
+     * bin.  Bins are converted to trees when adding an element to a
+     * bin with at least this many nodes. The value must be greater
+     * than 2, and should be at least 8 to mesh with assumptions in
+     * tree removal about conversion back to plain bins upon
+     * shrinkage.
+     */
+    static final int TREEIFY_THRESHOLD = 8;
+
+    /**
+     * The bin count threshold for untreeifying a (split) bin during a
+     * resize operation. Should be less than TREEIFY_THRESHOLD, and at
+     * most 6 to mesh with shrinkage detection under removal.
+     */
+    static final int UNTREEIFY_THRESHOLD = 6;
+
+    /**
+     * The smallest table capacity for which bins may be treeified.
+     * (Otherwise the table is resized if too many nodes in a bin.)
+     * The value should be at least 4 * TREEIFY_THRESHOLD to avoid
+     * conflicts between resizing and treeification thresholds.
+     */
+    static final int MIN_TREEIFY_CAPACITY = 64;
+
+    /**
+     * Minimum number of rebinnings per transfer step. Ranges are
+     * subdivided to allow multiple resizer threads.  This value
+     * serves as a lower bound to avoid resizers encountering
+     * excessive memory contention.  The value should be at least
+     * DEFAULT_CAPACITY.
+     */
+    private static final int MIN_TRANSFER_STRIDE = 16;
+
+    /**
+     * The number of bits used for generation stamp in sizeCtl.
+     * Must be at least 6 for 32bit arrays.
+     */
+    private static final int RESIZE_STAMP_BITS = 16;
+
+    /**
+     * The maximum number of threads that can help resize.
+     * Must fit in 32 - RESIZE_STAMP_BITS bits.
+     */
+    private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;
+
+    /**
+     * The bit shift for recording size stamp in sizeCtl.
+     */
+    private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;
+
+    /*
+     * Encodings for Node hash fields. See above for explanation.
+     */
+    static final int MOVED     = -1; // hash for forwarding nodes
+    static final int TREEBIN   = -2; // hash for roots of trees
+    static final int RESERVED  = -3; // hash for transient reservations
+    static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
+
+    /** Number of CPUS, to place bounds on some sizings */
+    static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * Serialized pseudo-fields, provided only for jdk7 compatibility.
+     * @serialField segments Segment[]
+     *   The segments, each of which is a specialized hash table.
+     * @serialField segmentMask int
+     *   Mask value for indexing into segments. The upper bits of a
+     *   key's hash code are used to choose the segment.
+     * @serialField segmentShift int
+     *   Shift value for indexing within segments.
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("segments", Segment[].class),
+        new ObjectStreamField("segmentMask", Integer.TYPE),
+        new ObjectStreamField("segmentShift", Integer.TYPE),
+    };
+
+    /* ---------------- Nodes -------------- */
+
+    /**
+     * Key-value entry.  This class is never exported out as a
+     * user-mutable Map.Entry (i.e., one supporting setValue; see
+     * MapEntry below), but can be used for read-only traversals used
+     * in bulk tasks.  Subclasses of Node with a negative hash field
+     * are special, and contain null keys and values (but are never
+     * exported).  Otherwise, keys and vals are never null.
+     */
+    static class Node<K,V> implements Map.Entry<K,V> {
+        final int hash;
+        final K key;
+        volatile V val;
+        volatile Node<K,V> next;
+
+        Node(int hash, K key, V val, Node<K,V> next) {
+            this.hash = hash;
+            this.key = key;
+            this.val = val;
+            this.next = next;
+        }
+
+        public final K getKey()     { return key; }
+        public final V getValue()   { return val; }
+        public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
+        public final String toString() {
+            return Helpers.mapEntryToString(key, val);
+        }
+        public final V setValue(V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        public final boolean equals(Object o) {
+            Object k, v, u; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    (k == key || k.equals(key)) &&
+                    (v == (u = val) || v.equals(u)));
+        }
+
+        /**
+         * Virtualized support for map.get(); overridden in subclasses.
+         */
+        Node<K,V> find(int h, Object k) {
+            Node<K,V> e = this;
+            if (k != null) {
+                do {
+                    K ek;
+                    if (e.hash == h &&
+                        ((ek = e.key) == k || (ek != null && k.equals(ek))))
+                        return e;
+                } while ((e = e.next) != null);
+            }
+            return null;
+        }
+    }
+
+    /* ---------------- Static utilities -------------- */
+
+    /**
+     * Spreads (XORs) higher bits of hash to lower and also forces top
+     * bit to 0. Because the table uses power-of-two masking, sets of
+     * hashes that vary only in bits above the current mask will
+     * always collide. (Among known examples are sets of Float keys
+     * holding consecutive whole numbers in small tables.)  So we
+     * apply a transform that spreads the impact of higher bits
+     * downward. There is a tradeoff between speed, utility, and
+     * quality of bit-spreading. Because many common sets of hashes
+     * are already reasonably distributed (so don't benefit from
+     * spreading), and because we use trees to handle large sets of
+     * collisions in bins, we just XOR some shifted bits in the
+     * cheapest possible way to reduce systematic lossage, as well as
+     * to incorporate impact of the highest bits that would otherwise
+     * never be used in index calculations because of table bounds.
+     */
+    static final int spread(int h) {
+        return (h ^ (h >>> 16)) & HASH_BITS;
+    }
+
+    /**
+     * Returns a power of two table size for the given desired capacity.
+     * See Hackers Delight, sec 3.2
+     */
+    private static final int tableSizeFor(int c) {
+        int n = c - 1;
+        n |= n >>> 1;
+        n |= n >>> 2;
+        n |= n >>> 4;
+        n |= n >>> 8;
+        n |= n >>> 16;
+        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
+    }
+
+    /**
+     * Returns x's Class if it is of the form "class C implements
+     * Comparable<C>", else null.
+     */
+    static Class<?> comparableClassFor(Object x) {
+        if (x instanceof Comparable) {
+            Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
+            if ((c = x.getClass()) == String.class) // bypass checks
+                return c;
+            if ((ts = c.getGenericInterfaces()) != null) {
+                for (int i = 0; i < ts.length; ++i) {
+                    if (((t = ts[i]) instanceof ParameterizedType) &&
+                        ((p = (ParameterizedType)t).getRawType() ==
+                         Comparable.class) &&
+                        (as = p.getActualTypeArguments()) != null &&
+                        as.length == 1 && as[0] == c) // type arg is c
+                        return c;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns k.compareTo(x) if x matches kc (k's screened comparable
+     * class), else 0.
+     */
+    @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
+    static int compareComparables(Class<?> kc, Object k, Object x) {
+        return (x == null || x.getClass() != kc ? 0 :
+                ((Comparable)k).compareTo(x));
+    }
+
+    /* ---------------- Table element access -------------- */
+
+    /*
+     * Volatile access methods are used for table elements as well as
+     * elements of in-progress next table while resizing.  All uses of
+     * the tab arguments must be null checked by callers.  All callers
+     * also paranoically precheck that tab's length is not zero (or an
+     * equivalent check), thus ensuring that any index argument taking
+     * the form of a hash value anded with (length - 1) is a valid
+     * index.  Note that, to be correct wrt arbitrary concurrency
+     * errors by users, these checks must operate on local variables,
+     * which accounts for some odd-looking inline assignments below.
+     * Note that calls to setTabAt always occur within locked regions,
+     * and so in principle require only release ordering, not
+     * full volatile semantics, but are currently coded as volatile
+     * writes to be conservative.
+     */
+
+    @SuppressWarnings("unchecked")
+    static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
+        return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
+    }
+
+    static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
+                                        Node<K,V> c, Node<K,V> v) {
+        return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
+    }
+
+    static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
+        U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
+    }
+
+    /* ---------------- Fields -------------- */
+
+    /**
+     * The array of bins. Lazily initialized upon first insertion.
+     * Size is always a power of two. Accessed directly by iterators.
+     */
+    transient volatile Node<K,V>[] table;
+
+    /**
+     * The next table to use; non-null only while resizing.
+     */
+    private transient volatile Node<K,V>[] nextTable;
+
+    /**
+     * Base counter value, used mainly when there is no contention,
+     * but also as a fallback during table initialization
+     * races. Updated via CAS.
+     */
+    private transient volatile long baseCount;
+
+    /**
+     * Table initialization and resizing control.  When negative, the
+     * table is being initialized or resized: -1 for initialization,
+     * else -(1 + the number of active resizing threads).  Otherwise,
+     * when table is null, holds the initial table size to use upon
+     * creation, or 0 for default. After initialization, holds the
+     * next element count value upon which to resize the table.
+     */
+    private transient volatile int sizeCtl;
+
+    /**
+     * The next table index (plus one) to split while resizing.
+     */
+    private transient volatile int transferIndex;
+
+    /**
+     * Spinlock (locked via CAS) used when resizing and/or creating CounterCells.
+     */
+    private transient volatile int cellsBusy;
+
+    /**
+     * Table of counter cells. When non-null, size is a power of 2.
+     */
+    private transient volatile CounterCell[] counterCells;
+
+    // views
+    private transient KeySetView<K,V> keySet;
+    private transient ValuesView<K,V> values;
+    private transient EntrySetView<K,V> entrySet;
+
+
+    /* ---------------- Public operations -------------- */
+
+    /**
+     * Creates a new, empty map with the default initial table size (16).
+     */
+    public ConcurrentHashMap() {
+    }
+
+    /**
+     * Creates a new, empty map with an initial table size
+     * accommodating the specified number of elements without the need
+     * to dynamically resize.
+     *
+     * @param initialCapacity The implementation performs internal
+     * sizing to accommodate this many elements.
+     * @throws IllegalArgumentException if the initial capacity of
+     * elements is negative
+     */
+    public ConcurrentHashMap(int initialCapacity) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException();
+        int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
+                   MAXIMUM_CAPACITY :
+                   tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
+        this.sizeCtl = cap;
+    }
+
+    /**
+     * Creates a new map with the same mappings as the given map.
+     *
+     * @param m the map
+     */
+    public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
+        this.sizeCtl = DEFAULT_CAPACITY;
+        putAll(m);
+    }
+
+    /**
+     * Creates a new, empty map with an initial table size based on
+     * the given number of elements ({@code initialCapacity}) and
+     * initial table density ({@code loadFactor}).
+     *
+     * @param initialCapacity the initial capacity. The implementation
+     * performs internal sizing to accommodate this many elements,
+     * given the specified load factor.
+     * @param loadFactor the load factor (table density) for
+     * establishing the initial table size
+     * @throws IllegalArgumentException if the initial capacity of
+     * elements is negative or the load factor is nonpositive
+     *
+     * @since 1.6
+     */
+    public ConcurrentHashMap(int initialCapacity, float loadFactor) {
+        this(initialCapacity, loadFactor, 1);
+    }
+
+    /**
+     * Creates a new, empty map with an initial table size based on
+     * the given number of elements ({@code initialCapacity}), table
+     * density ({@code loadFactor}), and number of concurrently
+     * updating threads ({@code concurrencyLevel}).
+     *
+     * @param initialCapacity the initial capacity. The implementation
+     * performs internal sizing to accommodate this many elements,
+     * given the specified load factor.
+     * @param loadFactor the load factor (table density) for
+     * establishing the initial table size
+     * @param concurrencyLevel the estimated number of concurrently
+     * updating threads. The implementation may use this value as
+     * a sizing hint.
+     * @throws IllegalArgumentException if the initial capacity is
+     * negative or the load factor or concurrencyLevel are
+     * nonpositive
+     */
+    public ConcurrentHashMap(int initialCapacity,
+                             float loadFactor, int concurrencyLevel) {
+        if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
+            throw new IllegalArgumentException();
+        if (initialCapacity < concurrencyLevel)   // Use at least as many bins
+            initialCapacity = concurrencyLevel;   // as estimated threads
+        long size = (long)(1.0 + (long)initialCapacity / loadFactor);
+        int cap = (size >= (long)MAXIMUM_CAPACITY) ?
+            MAXIMUM_CAPACITY : tableSizeFor((int)size);
+        this.sizeCtl = cap;
+    }
+
+    // Original (since JDK1.2) Map methods
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size() {
+        long n = sumCount();
+        return ((n < 0L) ? 0 :
+                (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE :
+                (int)n);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEmpty() {
+        return sumCount() <= 0L; // ignore transient negative values
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code key.equals(k)},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * @throws NullPointerException if the specified key is null
+     */
+    public V get(Object key) {
+        Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
+        int h = spread(key.hashCode());
+        if ((tab = table) != null && (n = tab.length) > 0 &&
+            (e = tabAt(tab, (n - 1) & h)) != null) {
+            if ((eh = e.hash) == h) {
+                if ((ek = e.key) == key || (ek != null && key.equals(ek)))
+                    return e.val;
+            }
+            else if (eh < 0)
+                return (p = e.find(h, key)) != null ? p.val : null;
+            while ((e = e.next) != null) {
+                if (e.hash == h &&
+                    ((ek = e.key) == key || (ek != null && key.equals(ek))))
+                    return e.val;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Tests if the specified object is a key in this table.
+     *
+     * @param  key possible key
+     * @return {@code true} if and only if the specified object
+     *         is a key in this table, as determined by the
+     *         {@code equals} method; {@code false} otherwise
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean containsKey(Object key) {
+        return get(key) != null;
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value. Note: This method may require a full traversal
+     * of the map, and is much slower than method {@code containsKey}.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified value
+     * @throws NullPointerException if the specified value is null
+     */
+    public boolean containsValue(Object value) {
+        if (value == null)
+            throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                V v;
+                if ((v = p.val) == value || (v != null && value.equals(v)))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Maps the specified key to the specified value in this table.
+     * Neither the key nor the value can be null.
+     *
+     * <p>The value can be retrieved by calling the {@code get} method
+     * with a key that is equal to the original key.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V put(K key, V value) {
+        return putVal(key, value, false);
+    }
+
+    /** Implementation for put and putIfAbsent */
+    final V putVal(K key, V value, boolean onlyIfAbsent) {
+        if (key == null || value == null) throw new NullPointerException();
+        int hash = spread(key.hashCode());
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
+                if (casTabAt(tab, i, null,
+                             new Node<K,V>(hash, key, value, null)))
+                    break;                   // no lock when adding to empty bin
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                V oldVal = null;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f;; ++binCount) {
+                                K ek;
+                                if (e.hash == hash &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    oldVal = e.val;
+                                    if (!onlyIfAbsent)
+                                        e.val = value;
+                                    break;
+                                }
+                                Node<K,V> pred = e;
+                                if ((e = e.next) == null) {
+                                    pred.next = new Node<K,V>(hash, key,
+                                                              value, null);
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            Node<K,V> p;
+                            binCount = 2;
+                            if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
+                                                           value)) != null) {
+                                oldVal = p.val;
+                                if (!onlyIfAbsent)
+                                    p.val = value;
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    if (oldVal != null)
+                        return oldVal;
+                    break;
+                }
+            }
+        }
+        addCount(1L, binCount);
+        return null;
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this one.
+     * These mappings replace any mappings that this map had for any of the
+     * keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        tryPresize(m.size());
+        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
+            putVal(e.getKey(), e.getValue(), false);
+    }
+
+    /**
+     * Removes the key (and its corresponding value) from this map.
+     * This method does nothing if the key is not in the map.
+     *
+     * @param  key the key that needs to be removed
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}
+     * @throws NullPointerException if the specified key is null
+     */
+    public V remove(Object key) {
+        return replaceNode(key, null, null);
+    }
+
+    /**
+     * Implementation for the four public remove/replace methods:
+     * Replaces node value with v, conditional upon match of cv if
+     * non-null.  If resulting value is null, delete.
+     */
+    final V replaceNode(Object key, V value, Object cv) {
+        int hash = spread(key.hashCode());
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0 ||
+                (f = tabAt(tab, i = (n - 1) & hash)) == null)
+                break;
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                V oldVal = null;
+                boolean validated = false;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            validated = true;
+                            for (Node<K,V> e = f, pred = null;;) {
+                                K ek;
+                                if (e.hash == hash &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    V ev = e.val;
+                                    if (cv == null || cv == ev ||
+                                        (ev != null && cv.equals(ev))) {
+                                        oldVal = ev;
+                                        if (value != null)
+                                            e.val = value;
+                                        else if (pred != null)
+                                            pred.next = e.next;
+                                        else
+                                            setTabAt(tab, i, e.next);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null)
+                                    break;
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            validated = true;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null &&
+                                (p = r.findTreeNode(hash, key, null)) != null) {
+                                V pv = p.val;
+                                if (cv == null || cv == pv ||
+                                    (pv != null && cv.equals(pv))) {
+                                    oldVal = pv;
+                                    if (value != null)
+                                        p.val = value;
+                                    else if (t.removeTreeNode(p))
+                                        setTabAt(tab, i, untreeify(t.first));
+                                }
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (validated) {
+                    if (oldVal != null) {
+                        if (value == null)
+                            addCount(-1L, -1);
+                        return oldVal;
+                    }
+                    break;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     */
+    public void clear() {
+        long delta = 0L; // negative number of deletions
+        int i = 0;
+        Node<K,V>[] tab = table;
+        while (tab != null && i < tab.length) {
+            int fh;
+            Node<K,V> f = tabAt(tab, i);
+            if (f == null)
+                ++i;
+            else if ((fh = f.hash) == MOVED) {
+                tab = helpTransfer(tab, f);
+                i = 0; // restart
+            }
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        Node<K,V> p = (fh >= 0 ? f :
+                                       (f instanceof TreeBin) ?
+                                       ((TreeBin<K,V>)f).first : null);
+                        while (p != null) {
+                            --delta;
+                            p = p.next;
+                        }
+                        setTabAt(tab, i++, null);
+                    }
+                }
+            }
+        }
+        if (delta != 0L)
+            addCount(delta, -1);
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa. The set supports element
+     * removal, which removes the corresponding mapping from this map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or
+     * {@code addAll} operations.
+     *
+     * <p> The set returned by this method is guaranteed to an instance of
+     * {@link KeySetView}.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#DISTINCT}, and {@link Spliterator#NONNULL}.
+     *
+     * @return the set view
+     */
+    // Android-changed: Return type for backwards compat. Was KeySetView<K,V>. http://b/28099367
+    @dalvik.annotation.codegen.CovariantReturnType(returnType = KeySetView.class, presentAfter = 28)
+    public Set<K> keySet() {
+        KeySetView<K,V> ks;
+        return (ks = keySet) != null ? ks : (keySet = new KeySetView<K,V>(this, null));
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from this map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll}, and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT}
+     * and {@link Spliterator#NONNULL}.
+     *
+     * @return the collection view
+     */
+    public Collection<V> values() {
+        ValuesView<K,V> vs;
+        return (vs = values) != null ? vs : (values = new ValuesView<K,V>(this));
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#DISTINCT}, and {@link Spliterator#NONNULL}.
+     *
+     * @return the set view
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        EntrySetView<K,V> es;
+        return (es = entrySet) != null ? es : (entrySet = new EntrySetView<K,V>(this));
+    }
+
+    /**
+     * Returns the hash code value for this {@link Map}, i.e.,
+     * the sum of, for each key-value pair in the map,
+     * {@code key.hashCode() ^ value.hashCode()}.
+     *
+     * @return the hash code value for this map
+     */
+    public int hashCode() {
+        int h = 0;
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; )
+                h += p.key.hashCode() ^ p.val.hashCode();
+        }
+        return h;
+    }
+
+    /**
+     * Returns a string representation of this map.  The string
+     * representation consists of a list of key-value mappings (in no
+     * particular order) enclosed in braces ("{@code {}}").  Adjacent
+     * mappings are separated by the characters {@code ", "} (comma
+     * and space).  Each key-value mapping is rendered as the key
+     * followed by an equals sign ("{@code =}") followed by the
+     * associated value.
+     *
+     * @return a string representation of this map
+     */
+    public String toString() {
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        Traverser<K,V> it = new Traverser<K,V>(t, f, 0, f);
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        Node<K,V> p;
+        if ((p = it.advance()) != null) {
+            for (;;) {
+                K k = p.key;
+                V v = p.val;
+                sb.append(k == this ? "(this Map)" : k);
+                sb.append('=');
+                sb.append(v == this ? "(this Map)" : v);
+                if ((p = it.advance()) == null)
+                    break;
+                sb.append(',').append(' ');
+            }
+        }
+        return sb.append('}').toString();
+    }
+
+    /**
+     * Compares the specified object with this map for equality.
+     * Returns {@code true} if the given object is a map with the same
+     * mappings as this map.  This operation may return misleading
+     * results if either map is concurrently modified during execution
+     * of this method.
+     *
+     * @param o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (o != this) {
+            if (!(o instanceof Map))
+                return false;
+            Map<?,?> m = (Map<?,?>) o;
+            Node<K,V>[] t;
+            int f = (t = table) == null ? 0 : t.length;
+            Traverser<K,V> it = new Traverser<K,V>(t, f, 0, f);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                V val = p.val;
+                Object v = m.get(p.key);
+                if (v == null || (v != val && !v.equals(val)))
+                    return false;
+            }
+            for (Map.Entry<?,?> e : m.entrySet()) {
+                Object mk, mv, v;
+                if ((mk = e.getKey()) == null ||
+                    (mv = e.getValue()) == null ||
+                    (v = get(mk)) == null ||
+                    (mv != v && !mv.equals(v)))
+                    return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Stripped-down version of helper class used in previous version,
+     * declared for the sake of serialization compatibility.
+     */
+    static class Segment<K,V> extends ReentrantLock implements Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        final float loadFactor;
+        Segment(float lf) { this.loadFactor = lf; }
+    }
+
+    /**
+     * Saves the state of the {@code ConcurrentHashMap} instance to a
+     * stream (i.e., serializes it).
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData
+     * the serialized fields, followed by the key (Object) and value
+     * (Object) for each key-value mapping, followed by a null pair.
+     * The key-value mappings are emitted in no particular order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // For serialization compatibility
+        // Emulate segment calculation from previous version of this class
+        int sshift = 0;
+        int ssize = 1;
+        while (ssize < DEFAULT_CONCURRENCY_LEVEL) {
+            ++sshift;
+            ssize <<= 1;
+        }
+        int segmentShift = 32 - sshift;
+        int segmentMask = ssize - 1;
+        @SuppressWarnings("unchecked")
+        Segment<K,V>[] segments = (Segment<K,V>[])
+            new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
+        for (int i = 0; i < segments.length; ++i)
+            segments[i] = new Segment<K,V>(LOAD_FACTOR);
+        java.io.ObjectOutputStream.PutField streamFields = s.putFields();
+        streamFields.put("segments", segments);
+        streamFields.put("segmentShift", segmentShift);
+        streamFields.put("segmentMask", segmentMask);
+        s.writeFields();
+
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                s.writeObject(p.key);
+                s.writeObject(p.val);
+            }
+        }
+        s.writeObject(null);
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes the instance from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        /*
+         * To improve performance in typical cases, we create nodes
+         * while reading, then place in table once size is known.
+         * However, we must also validate uniqueness and deal with
+         * overpopulated bins while doing so, which requires
+         * specialized versions of putVal mechanics.
+         */
+        sizeCtl = -1; // force exclusion for table construction
+        s.defaultReadObject();
+        long size = 0L;
+        Node<K,V> p = null;
+        for (;;) {
+            @SuppressWarnings("unchecked")
+            K k = (K) s.readObject();
+            @SuppressWarnings("unchecked")
+            V v = (V) s.readObject();
+            if (k != null && v != null) {
+                p = new Node<K,V>(spread(k.hashCode()), k, v, p);
+                ++size;
+            }
+            else
+                break;
+        }
+        if (size == 0L)
+            sizeCtl = 0;
+        else {
+            int n;
+            if (size >= (long)(MAXIMUM_CAPACITY >>> 1))
+                n = MAXIMUM_CAPACITY;
+            else {
+                int sz = (int)size;
+                n = tableSizeFor(sz + (sz >>> 1) + 1);
+            }
+            @SuppressWarnings("unchecked")
+            Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n];
+            int mask = n - 1;
+            long added = 0L;
+            while (p != null) {
+                boolean insertAtFront;
+                Node<K,V> next = p.next, first;
+                int h = p.hash, j = h & mask;
+                if ((first = tabAt(tab, j)) == null)
+                    insertAtFront = true;
+                else {
+                    K k = p.key;
+                    if (first.hash < 0) {
+                        TreeBin<K,V> t = (TreeBin<K,V>)first;
+                        if (t.putTreeVal(h, k, p.val) == null)
+                            ++added;
+                        insertAtFront = false;
+                    }
+                    else {
+                        int binCount = 0;
+                        insertAtFront = true;
+                        Node<K,V> q; K qk;
+                        for (q = first; q != null; q = q.next) {
+                            if (q.hash == h &&
+                                ((qk = q.key) == k ||
+                                 (qk != null && k.equals(qk)))) {
+                                insertAtFront = false;
+                                break;
+                            }
+                            ++binCount;
+                        }
+                        if (insertAtFront && binCount >= TREEIFY_THRESHOLD) {
+                            insertAtFront = false;
+                            ++added;
+                            p.next = first;
+                            TreeNode<K,V> hd = null, tl = null;
+                            for (q = p; q != null; q = q.next) {
+                                TreeNode<K,V> t = new TreeNode<K,V>
+                                    (q.hash, q.key, q.val, null, null);
+                                if ((t.prev = tl) == null)
+                                    hd = t;
+                                else
+                                    tl.next = t;
+                                tl = t;
+                            }
+                            setTabAt(tab, j, new TreeBin<K,V>(hd));
+                        }
+                    }
+                }
+                if (insertAtFront) {
+                    ++added;
+                    p.next = first;
+                    setTabAt(tab, j, p);
+                }
+                p = next;
+            }
+            table = tab;
+            sizeCtl = n - (n >>> 2);
+            baseCount = added;
+        }
+    }
+
+    // ConcurrentMap methods
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V putIfAbsent(K key, V value) {
+        return putVal(key, value, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean remove(Object key, Object value) {
+        if (key == null)
+            throw new NullPointerException();
+        return value != null && replaceNode(key, null, value) != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NullPointerException if any of the arguments are null
+     */
+    public boolean replace(K key, V oldValue, V newValue) {
+        if (key == null || oldValue == null || newValue == null)
+            throw new NullPointerException();
+        return replaceNode(key, newValue, oldValue) != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V replace(K key, V value) {
+        if (key == null || value == null)
+            throw new NullPointerException();
+        return replaceNode(key, value, null);
+    }
+
+    // Overrides of JDK8+ Map extension method defaults
+
+    /**
+     * Returns the value to which the specified key is mapped, or the
+     * given default value if this map contains no mapping for the
+     * key.
+     *
+     * @param key the key whose associated value is to be returned
+     * @param defaultValue the value to return if this map contains
+     * no mapping for the given key
+     * @return the mapping for the key, if present; else the default value
+     * @throws NullPointerException if the specified key is null
+     */
+    public V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return (v = get(key)) == null ? defaultValue : v;
+    }
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                action.accept(p.key, p.val);
+            }
+        }
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        if (function == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                V oldValue = p.val;
+                for (K key = p.key;;) {
+                    V newValue = function.apply(key, oldValue);
+                    if (newValue == null)
+                        throw new NullPointerException();
+                    if (replaceNode(key, newValue, oldValue) != null ||
+                        (oldValue = get(key)) == null)
+                        break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper method for EntrySetView.removeIf.
+     */
+    boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
+        if (function == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        boolean removed = false;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                K k = p.key;
+                V v = p.val;
+                Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
+                if (function.test(e) && replaceNode(k, null, v) != null)
+                    removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Helper method for ValuesView.removeIf.
+     */
+    boolean removeValueIf(Predicate<? super V> function) {
+        if (function == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        boolean removed = false;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                K k = p.key;
+                V v = p.val;
+                if (function.test(v) && replaceNode(k, null, v) != null)
+                    removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * If the specified key is not already associated with a value,
+     * attempts to compute its value using the given mapping function
+     * and enters it into this map unless {@code null}.  The entire
+     * method invocation is performed atomically, so the function is
+     * applied at most once per key.  Some attempted update operations
+     * on this map by other threads may be blocked while computation
+     * is in progress, so the computation should be short and simple,
+     * and must not attempt to update any other mappings of this map.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param mappingFunction the function to compute a value
+     * @return the current (existing or computed) value associated with
+     *         the specified key, or null if the computed value is null
+     * @throws NullPointerException if the specified key or mappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the mappingFunction does so,
+     *         in which case the mapping is left unestablished
+     */
+    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+        if (key == null || mappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
+                Node<K,V> r = new ReservationNode<K,V>();
+                synchronized (r) {
+                    if (casTabAt(tab, i, null, r)) {
+                        binCount = 1;
+                        Node<K,V> node = null;
+                        try {
+                            if ((val = mappingFunction.apply(key)) != null)
+                                node = new Node<K,V>(h, key, val, null);
+                        } finally {
+                            setTabAt(tab, i, node);
+                        }
+                    }
+                }
+                if (binCount != 0)
+                    break;
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                boolean added = false;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = e.val;
+                                    break;
+                                }
+                                Node<K,V> pred = e;
+                                if ((e = e.next) == null) {
+                                    if ((val = mappingFunction.apply(key)) != null) {
+                                        if (pred.next != null)
+                                            throw new IllegalStateException("Recursive update");
+                                        added = true;
+                                        pred.next = new Node<K,V>(h, key, val, null);
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 2;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null &&
+                                (p = r.findTreeNode(h, key, null)) != null)
+                                val = p.val;
+                            else if ((val = mappingFunction.apply(key)) != null) {
+                                added = true;
+                                t.putTreeVal(h, key, val);
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    if (!added)
+                        return val;
+                    break;
+                }
+            }
+        }
+        if (val != null)
+            addCount(1L, binCount);
+        return val;
+    }
+
+    /**
+     * If the value for the specified key is present, attempts to
+     * compute a new mapping given the key and its current mapped
+     * value.  The entire method invocation is performed atomically.
+     * Some attempted update operations on this map by other threads
+     * may be blocked while computation is in progress, so the
+     * computation should be short and simple, and must not attempt to
+     * update any other mappings of this map.
+     *
+     * @param key key with which a value may be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or remappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int delta = 0;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null)
+                break;
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f, pred = null;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = remappingFunction.apply(key, e.val);
+                                    if (val != null)
+                                        e.val = val;
+                                    else {
+                                        delta = -1;
+                                        Node<K,V> en = e.next;
+                                        if (pred != null)
+                                            pred.next = en;
+                                        else
+                                            setTabAt(tab, i, en);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null)
+                                    break;
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 2;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null &&
+                                (p = r.findTreeNode(h, key, null)) != null) {
+                                val = remappingFunction.apply(key, p.val);
+                                if (val != null)
+                                    p.val = val;
+                                else {
+                                    delta = -1;
+                                    if (t.removeTreeNode(p))
+                                        setTabAt(tab, i, untreeify(t.first));
+                                }
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0)
+                    break;
+            }
+        }
+        if (delta != 0)
+            addCount((long)delta, binCount);
+        return val;
+    }
+
+    /**
+     * Attempts to compute a mapping for the specified key and its
+     * current mapped value (or {@code null} if there is no current
+     * mapping). The entire method invocation is performed atomically.
+     * Some attempted update operations on this map by other threads
+     * may be blocked while computation is in progress, so the
+     * computation should be short and simple, and must not attempt to
+     * update any other mappings of this Map.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or remappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V compute(K key,
+                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int delta = 0;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
+                Node<K,V> r = new ReservationNode<K,V>();
+                synchronized (r) {
+                    if (casTabAt(tab, i, null, r)) {
+                        binCount = 1;
+                        Node<K,V> node = null;
+                        try {
+                            if ((val = remappingFunction.apply(key, null)) != null) {
+                                delta = 1;
+                                node = new Node<K,V>(h, key, val, null);
+                            }
+                        } finally {
+                            setTabAt(tab, i, node);
+                        }
+                    }
+                }
+                if (binCount != 0)
+                    break;
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f, pred = null;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = remappingFunction.apply(key, e.val);
+                                    if (val != null)
+                                        e.val = val;
+                                    else {
+                                        delta = -1;
+                                        Node<K,V> en = e.next;
+                                        if (pred != null)
+                                            pred.next = en;
+                                        else
+                                            setTabAt(tab, i, en);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null) {
+                                    val = remappingFunction.apply(key, null);
+                                    if (val != null) {
+                                        if (pred.next != null)
+                                            throw new IllegalStateException("Recursive update");
+                                        delta = 1;
+                                        pred.next =
+                                            new Node<K,V>(h, key, val, null);
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 1;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null)
+                                p = r.findTreeNode(h, key, null);
+                            else
+                                p = null;
+                            V pv = (p == null) ? null : p.val;
+                            val = remappingFunction.apply(key, pv);
+                            if (val != null) {
+                                if (p != null)
+                                    p.val = val;
+                                else {
+                                    delta = 1;
+                                    t.putTreeVal(h, key, val);
+                                }
+                            }
+                            else if (p != null) {
+                                delta = -1;
+                                if (t.removeTreeNode(p))
+                                    setTabAt(tab, i, untreeify(t.first));
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    break;
+                }
+            }
+        }
+        if (delta != 0)
+            addCount((long)delta, binCount);
+        return val;
+    }
+
+    /**
+     * If the specified key is not already associated with a
+     * (non-null) value, associates it with the given value.
+     * Otherwise, replaces the value with the results of the given
+     * remapping function, or removes if {@code null}. The entire
+     * method invocation is performed atomically.  Some attempted
+     * update operations on this map by other threads may be blocked
+     * while computation is in progress, so the computation should be
+     * short and simple, and must not attempt to update any other
+     * mappings of this Map.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value the value to use if absent
+     * @param remappingFunction the function to recompute a value if present
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or the
+     *         remappingFunction is null
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        if (key == null || value == null || remappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int delta = 0;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
+                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value, null))) {
+                    delta = 1;
+                    val = value;
+                    break;
+                }
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f, pred = null;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = remappingFunction.apply(e.val, value);
+                                    if (val != null)
+                                        e.val = val;
+                                    else {
+                                        delta = -1;
+                                        Node<K,V> en = e.next;
+                                        if (pred != null)
+                                            pred.next = en;
+                                        else
+                                            setTabAt(tab, i, en);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null) {
+                                    delta = 1;
+                                    val = value;
+                                    pred.next =
+                                        new Node<K,V>(h, key, val, null);
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 2;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r = t.root;
+                            TreeNode<K,V> p = (r == null) ? null :
+                                r.findTreeNode(h, key, null);
+                            val = (p == null) ? value :
+                                remappingFunction.apply(p.val, value);
+                            if (val != null) {
+                                if (p != null)
+                                    p.val = val;
+                                else {
+                                    delta = 1;
+                                    t.putTreeVal(h, key, val);
+                                }
+                            }
+                            else if (p != null) {
+                                delta = -1;
+                                if (t.removeTreeNode(p))
+                                    setTabAt(tab, i, untreeify(t.first));
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    break;
+                }
+            }
+        }
+        if (delta != 0)
+            addCount((long)delta, binCount);
+        return val;
+    }
+
+    // Hashtable legacy methods
+
+    /**
+     * Tests if some key maps into the specified value in this table.
+     *
+     * <p>Note that this method is identical in functionality to
+     * {@link #containsValue(Object)}, and exists solely to ensure
+     * full compatibility with class {@link java.util.Hashtable},
+     * which supported this method prior to introduction of the
+     * Java Collections Framework.
+     *
+     * @param  value a value to search for
+     * @return {@code true} if and only if some key maps to the
+     *         {@code value} argument in this table as
+     *         determined by the {@code equals} method;
+     *         {@code false} otherwise
+     * @throws NullPointerException if the specified value is null
+     */
+    public boolean contains(Object value) {
+        return containsValue(value);
+    }
+
+    /**
+     * Returns an enumeration of the keys in this table.
+     *
+     * @return an enumeration of the keys in this table
+     * @see #keySet()
+     */
+    public Enumeration<K> keys() {
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        return new KeyIterator<K,V>(t, f, 0, f, this);
+    }
+
+    /**
+     * Returns an enumeration of the values in this table.
+     *
+     * @return an enumeration of the values in this table
+     * @see #values()
+     */
+    public Enumeration<V> elements() {
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        return new ValueIterator<K,V>(t, f, 0, f, this);
+    }
+
+    // ConcurrentHashMap-only methods
+
+    /**
+     * Returns the number of mappings. This method should be used
+     * instead of {@link #size} because a ConcurrentHashMap may
+     * contain more mappings than can be represented as an int. The
+     * value returned is an estimate; the actual count may differ if
+     * there are concurrent insertions or removals.
+     *
+     * @return the number of mappings
+     * @since 1.8
+     */
+    public long mappingCount() {
+        long n = sumCount();
+        return (n < 0L) ? 0L : n; // ignore transient negative values
+    }
+
+    /**
+     * Creates a new {@link Set} backed by a ConcurrentHashMap
+     * from the given type to {@code Boolean.TRUE}.
+     *
+     * @param <K> the element type of the returned set
+     * @return the new set
+     * @since 1.8
+     */
+    public static <K> KeySetView<K,Boolean> newKeySet() {
+        return new KeySetView<K,Boolean>
+            (new ConcurrentHashMap<K,Boolean>(), Boolean.TRUE);
+    }
+
+    /**
+     * Creates a new {@link Set} backed by a ConcurrentHashMap
+     * from the given type to {@code Boolean.TRUE}.
+     *
+     * @param initialCapacity The implementation performs internal
+     * sizing to accommodate this many elements.
+     * @param <K> the element type of the returned set
+     * @return the new set
+     * @throws IllegalArgumentException if the initial capacity of
+     * elements is negative
+     * @since 1.8
+     */
+    public static <K> KeySetView<K,Boolean> newKeySet(int initialCapacity) {
+        return new KeySetView<K,Boolean>
+            (new ConcurrentHashMap<K,Boolean>(initialCapacity), Boolean.TRUE);
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys in this map, using the
+     * given common mapped value for any additions (i.e., {@link
+     * Collection#add} and {@link Collection#addAll(Collection)}).
+     * This is of course only appropriate if it is acceptable to use
+     * the same value for all additions from this view.
+     *
+     * @param mappedValue the mapped value to use for any additions
+     * @return the set view
+     * @throws NullPointerException if the mappedValue is null
+     */
+    public KeySetView<K,V> keySet(V mappedValue) {
+        if (mappedValue == null)
+            throw new NullPointerException();
+        return new KeySetView<K,V>(this, mappedValue);
+    }
+
+    /* ---------------- Special Nodes -------------- */
+
+    /**
+     * A node inserted at head of bins during transfer operations.
+     */
+    static final class ForwardingNode<K,V> extends Node<K,V> {
+        final Node<K,V>[] nextTable;
+        ForwardingNode(Node<K,V>[] tab) {
+            super(MOVED, null, null, null);
+            this.nextTable = tab;
+        }
+
+        Node<K,V> find(int h, Object k) {
+            // loop to avoid arbitrarily deep recursion on forwarding nodes
+            outer: for (Node<K,V>[] tab = nextTable;;) {
+                Node<K,V> e; int n;
+                if (k == null || tab == null || (n = tab.length) == 0 ||
+                    (e = tabAt(tab, (n - 1) & h)) == null)
+                    return null;
+                for (;;) {
+                    int eh; K ek;
+                    if ((eh = e.hash) == h &&
+                        ((ek = e.key) == k || (ek != null && k.equals(ek))))
+                        return e;
+                    if (eh < 0) {
+                        if (e instanceof ForwardingNode) {
+                            tab = ((ForwardingNode<K,V>)e).nextTable;
+                            continue outer;
+                        }
+                        else
+                            return e.find(h, k);
+                    }
+                    if ((e = e.next) == null)
+                        return null;
+                }
+            }
+        }
+    }
+
+    /**
+     * A place-holder node used in computeIfAbsent and compute.
+     */
+    static final class ReservationNode<K,V> extends Node<K,V> {
+        ReservationNode() {
+            super(RESERVED, null, null, null);
+        }
+
+        Node<K,V> find(int h, Object k) {
+            return null;
+        }
+    }
+
+    /* ---------------- Table Initialization and Resizing -------------- */
+
+    /**
+     * Returns the stamp bits for resizing a table of size n.
+     * Must be negative when shifted left by RESIZE_STAMP_SHIFT.
+     */
+    static final int resizeStamp(int n) {
+        return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
+    }
+
+    /**
+     * Initializes table, using the size recorded in sizeCtl.
+     */
+    private final Node<K,V>[] initTable() {
+        Node<K,V>[] tab; int sc;
+        while ((tab = table) == null || tab.length == 0) {
+            if ((sc = sizeCtl) < 0)
+                Thread.yield(); // lost initialization race; just spin
+            else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+                try {
+                    if ((tab = table) == null || tab.length == 0) {
+                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
+                        @SuppressWarnings("unchecked")
+                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
+                        table = tab = nt;
+                        sc = n - (n >>> 2);
+                    }
+                } finally {
+                    sizeCtl = sc;
+                }
+                break;
+            }
+        }
+        return tab;
+    }
+
+    /**
+     * Adds to count, and if table is too small and not already
+     * resizing, initiates transfer. If already resizing, helps
+     * perform transfer if work is available.  Rechecks occupancy
+     * after a transfer to see if another resize is already needed
+     * because resizings are lagging additions.
+     *
+     * @param x the count to add
+     * @param check if <0, don't check resize, if <= 1 only check if uncontended
+     */
+    private final void addCount(long x, int check) {
+        CounterCell[] as; long b, s;
+        if ((as = counterCells) != null ||
+            !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
+            CounterCell a; long v; int m;
+            boolean uncontended = true;
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
+                !(uncontended =
+                  U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
+                fullAddCount(x, uncontended);
+                return;
+            }
+            if (check <= 1)
+                return;
+            s = sumCount();
+        }
+        if (check >= 0) {
+            Node<K,V>[] tab, nt; int n, sc;
+            while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
+                   (n = tab.length) < MAXIMUM_CAPACITY) {
+                int rs = resizeStamp(n);
+                if (sc < 0) {
+                    if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
+                        sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
+                        transferIndex <= 0)
+                        break;
+                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
+                        transfer(tab, nt);
+                }
+                else if (U.compareAndSwapInt(this, SIZECTL, sc,
+                                             (rs << RESIZE_STAMP_SHIFT) + 2))
+                    transfer(tab, null);
+                s = sumCount();
+            }
+        }
+    }
+
+    /**
+     * Helps transfer if a resize is in progress.
+     */
+    final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
+        Node<K,V>[] nextTab; int sc;
+        if (tab != null && (f instanceof ForwardingNode) &&
+            (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
+            int rs = resizeStamp(tab.length);
+            while (nextTab == nextTable && table == tab &&
+                   (sc = sizeCtl) < 0) {
+                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
+                    sc == rs + MAX_RESIZERS || transferIndex <= 0)
+                    break;
+                if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
+                    transfer(tab, nextTab);
+                    break;
+                }
+            }
+            return nextTab;
+        }
+        return table;
+    }
+
+    /**
+     * Tries to presize table to accommodate the given number of elements.
+     *
+     * @param size number of elements (doesn't need to be perfectly accurate)
+     */
+    private final void tryPresize(int size) {
+        int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
+            tableSizeFor(size + (size >>> 1) + 1);
+        int sc;
+        while ((sc = sizeCtl) >= 0) {
+            Node<K,V>[] tab = table; int n;
+            if (tab == null || (n = tab.length) == 0) {
+                n = (sc > c) ? sc : c;
+                if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+                    try {
+                        if (table == tab) {
+                            @SuppressWarnings("unchecked")
+                            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
+                            table = nt;
+                            sc = n - (n >>> 2);
+                        }
+                    } finally {
+                        sizeCtl = sc;
+                    }
+                }
+            }
+            else if (c <= sc || n >= MAXIMUM_CAPACITY)
+                break;
+            else if (tab == table) {
+                int rs = resizeStamp(n);
+                if (U.compareAndSwapInt(this, SIZECTL, sc,
+                                        (rs << RESIZE_STAMP_SHIFT) + 2))
+                    transfer(tab, null);
+            }
+        }
+    }
+
+    /**
+     * Moves and/or copies the nodes in each bin to new table. See
+     * above for explanation.
+     */
+    private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
+        int n = tab.length, stride;
+        if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
+            stride = MIN_TRANSFER_STRIDE; // subdivide range
+        if (nextTab == null) {            // initiating
+            try {
+                @SuppressWarnings("unchecked")
+                Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
+                nextTab = nt;
+            } catch (Throwable ex) {      // try to cope with OOME
+                sizeCtl = Integer.MAX_VALUE;
+                return;
+            }
+            nextTable = nextTab;
+            transferIndex = n;
+        }
+        int nextn = nextTab.length;
+        ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
+        boolean advance = true;
+        boolean finishing = false; // to ensure sweep before committing nextTab
+        for (int i = 0, bound = 0;;) {
+            Node<K,V> f; int fh;
+            while (advance) {
+                int nextIndex, nextBound;
+                if (--i >= bound || finishing)
+                    advance = false;
+                else if ((nextIndex = transferIndex) <= 0) {
+                    i = -1;
+                    advance = false;
+                }
+                else if (U.compareAndSwapInt
+                         (this, TRANSFERINDEX, nextIndex,
+                          nextBound = (nextIndex > stride ?
+                                       nextIndex - stride : 0))) {
+                    bound = nextBound;
+                    i = nextIndex - 1;
+                    advance = false;
+                }
+            }
+            if (i < 0 || i >= n || i + n >= nextn) {
+                int sc;
+                if (finishing) {
+                    nextTable = null;
+                    table = nextTab;
+                    sizeCtl = (n << 1) - (n >>> 1);
+                    return;
+                }
+                if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
+                    if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
+                        return;
+                    finishing = advance = true;
+                    i = n; // recheck before commit
+                }
+            }
+            else if ((f = tabAt(tab, i)) == null)
+                advance = casTabAt(tab, i, null, fwd);
+            else if ((fh = f.hash) == MOVED)
+                advance = true; // already processed
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        Node<K,V> ln, hn;
+                        if (fh >= 0) {
+                            int runBit = fh & n;
+                            Node<K,V> lastRun = f;
+                            for (Node<K,V> p = f.next; p != null; p = p.next) {
+                                int b = p.hash & n;
+                                if (b != runBit) {
+                                    runBit = b;
+                                    lastRun = p;
+                                }
+                            }
+                            if (runBit == 0) {
+                                ln = lastRun;
+                                hn = null;
+                            }
+                            else {
+                                hn = lastRun;
+                                ln = null;
+                            }
+                            for (Node<K,V> p = f; p != lastRun; p = p.next) {
+                                int ph = p.hash; K pk = p.key; V pv = p.val;
+                                if ((ph & n) == 0)
+                                    ln = new Node<K,V>(ph, pk, pv, ln);
+                                else
+                                    hn = new Node<K,V>(ph, pk, pv, hn);
+                            }
+                            setTabAt(nextTab, i, ln);
+                            setTabAt(nextTab, i + n, hn);
+                            setTabAt(tab, i, fwd);
+                            advance = true;
+                        }
+                        else if (f instanceof TreeBin) {
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> lo = null, loTail = null;
+                            TreeNode<K,V> hi = null, hiTail = null;
+                            int lc = 0, hc = 0;
+                            for (Node<K,V> e = t.first; e != null; e = e.next) {
+                                int h = e.hash;
+                                TreeNode<K,V> p = new TreeNode<K,V>
+                                    (h, e.key, e.val, null, null);
+                                if ((h & n) == 0) {
+                                    if ((p.prev = loTail) == null)
+                                        lo = p;
+                                    else
+                                        loTail.next = p;
+                                    loTail = p;
+                                    ++lc;
+                                }
+                                else {
+                                    if ((p.prev = hiTail) == null)
+                                        hi = p;
+                                    else
+                                        hiTail.next = p;
+                                    hiTail = p;
+                                    ++hc;
+                                }
+                            }
+                            ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
+                                (hc != 0) ? new TreeBin<K,V>(lo) : t;
+                            hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
+                                (lc != 0) ? new TreeBin<K,V>(hi) : t;
+                            setTabAt(nextTab, i, ln);
+                            setTabAt(nextTab, i + n, hn);
+                            setTabAt(tab, i, fwd);
+                            advance = true;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /* ---------------- Counter support -------------- */
+
+    /**
+     * A padded cell for distributing counts.  Adapted from LongAdder
+     * and Striped64.  See their internal docs for explanation.
+     */
+    // Android-removed: @Contended, this hint is not used by the Android runtime.
+    //@jdk.internal.vm.annotation.Contended
+    static final class CounterCell {
+        volatile long value;
+        CounterCell(long x) { value = x; }
+    }
+
+    final long sumCount() {
+        CounterCell[] as = counterCells; CounterCell a;
+        long sum = baseCount;
+        if (as != null) {
+            for (int i = 0; i < as.length; ++i) {
+                if ((a = as[i]) != null)
+                    sum += a.value;
+            }
+        }
+        return sum;
+    }
+
+    // See LongAdder version for explanation
+    private final void fullAddCount(long x, boolean wasUncontended) {
+        int h;
+        if ((h = ThreadLocalRandom.getProbe()) == 0) {
+            ThreadLocalRandom.localInit();      // force initialization
+            h = ThreadLocalRandom.getProbe();
+            wasUncontended = true;
+        }
+        boolean collide = false;                // True if last slot nonempty
+        for (;;) {
+            CounterCell[] as; CounterCell a; int n; long v;
+            if ((as = counterCells) != null && (n = as.length) > 0) {
+                if ((a = as[(n - 1) & h]) == null) {
+                    if (cellsBusy == 0) {            // Try to attach new Cell
+                        CounterCell r = new CounterCell(x); // Optimistic create
+                        if (cellsBusy == 0 &&
+                            U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+                            boolean created = false;
+                            try {               // Recheck under lock
+                                CounterCell[] rs; int m, j;
+                                if ((rs = counterCells) != null &&
+                                    (m = rs.length) > 0 &&
+                                    rs[j = (m - 1) & h] == null) {
+                                    rs[j] = r;
+                                    created = true;
+                                }
+                            } finally {
+                                cellsBusy = 0;
+                            }
+                            if (created)
+                                break;
+                            continue;           // Slot is now non-empty
+                        }
+                    }
+                    collide = false;
+                }
+                else if (!wasUncontended)       // CAS already known to fail
+                    wasUncontended = true;      // Continue after rehash
+                else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
+                    break;
+                else if (counterCells != as || n >= NCPU)
+                    collide = false;            // At max size or stale
+                else if (!collide)
+                    collide = true;
+                else if (cellsBusy == 0 &&
+                         U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+                    try {
+                        if (counterCells == as) {// Expand table unless stale
+                            CounterCell[] rs = new CounterCell[n << 1];
+                            for (int i = 0; i < n; ++i)
+                                rs[i] = as[i];
+                            counterCells = rs;
+                        }
+                    } finally {
+                        cellsBusy = 0;
+                    }
+                    collide = false;
+                    continue;                   // Retry with expanded table
+                }
+                h = ThreadLocalRandom.advanceProbe(h);
+            }
+            else if (cellsBusy == 0 && counterCells == as &&
+                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+                boolean init = false;
+                try {                           // Initialize table
+                    if (counterCells == as) {
+                        CounterCell[] rs = new CounterCell[2];
+                        rs[h & 1] = new CounterCell(x);
+                        counterCells = rs;
+                        init = true;
+                    }
+                } finally {
+                    cellsBusy = 0;
+                }
+                if (init)
+                    break;
+            }
+            else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
+                break;                          // Fall back on using base
+        }
+    }
+
+    /* ---------------- Conversion from/to TreeBins -------------- */
+
+    /**
+     * Replaces all linked nodes in bin at given index unless table is
+     * too small, in which case resizes instead.
+     */
+    private final void treeifyBin(Node<K,V>[] tab, int index) {
+        Node<K,V> b; int n;
+        if (tab != null) {
+            if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
+                tryPresize(n << 1);
+            else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
+                synchronized (b) {
+                    if (tabAt(tab, index) == b) {
+                        TreeNode<K,V> hd = null, tl = null;
+                        for (Node<K,V> e = b; e != null; e = e.next) {
+                            TreeNode<K,V> p =
+                                new TreeNode<K,V>(e.hash, e.key, e.val,
+                                                  null, null);
+                            if ((p.prev = tl) == null)
+                                hd = p;
+                            else
+                                tl.next = p;
+                            tl = p;
+                        }
+                        setTabAt(tab, index, new TreeBin<K,V>(hd));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a list on non-TreeNodes replacing those in given list.
+     */
+    static <K,V> Node<K,V> untreeify(Node<K,V> b) {
+        Node<K,V> hd = null, tl = null;
+        for (Node<K,V> q = b; q != null; q = q.next) {
+            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val, null);
+            if (tl == null)
+                hd = p;
+            else
+                tl.next = p;
+            tl = p;
+        }
+        return hd;
+    }
+
+    /* ---------------- TreeNodes -------------- */
+
+    /**
+     * Nodes for use in TreeBins.
+     */
+    static final class TreeNode<K,V> extends Node<K,V> {
+        TreeNode<K,V> parent;  // red-black tree links
+        TreeNode<K,V> left;
+        TreeNode<K,V> right;
+        TreeNode<K,V> prev;    // needed to unlink next upon deletion
+        boolean red;
+
+        TreeNode(int hash, K key, V val, Node<K,V> next,
+                 TreeNode<K,V> parent) {
+            super(hash, key, val, next);
+            this.parent = parent;
+        }
+
+        Node<K,V> find(int h, Object k) {
+            return findTreeNode(h, k, null);
+        }
+
+        /**
+         * Returns the TreeNode (or null if not found) for the given key
+         * starting at given root.
+         */
+        final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) {
+            if (k != null) {
+                TreeNode<K,V> p = this;
+                do {
+                    int ph, dir; K pk; TreeNode<K,V> q;
+                    TreeNode<K,V> pl = p.left, pr = p.right;
+                    if ((ph = p.hash) > h)
+                        p = pl;
+                    else if (ph < h)
+                        p = pr;
+                    else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
+                        return p;
+                    else if (pl == null)
+                        p = pr;
+                    else if (pr == null)
+                        p = pl;
+                    else if ((kc != null ||
+                              (kc = comparableClassFor(k)) != null) &&
+                             (dir = compareComparables(kc, k, pk)) != 0)
+                        p = (dir < 0) ? pl : pr;
+                    else if ((q = pr.findTreeNode(h, k, kc)) != null)
+                        return q;
+                    else
+                        p = pl;
+                } while (p != null);
+            }
+            return null;
+        }
+    }
+
+    /* ---------------- TreeBins -------------- */
+
+    /**
+     * TreeNodes used at the heads of bins. TreeBins do not hold user
+     * keys or values, but instead point to list of TreeNodes and
+     * their root. They also maintain a parasitic read-write lock
+     * forcing writers (who hold bin lock) to wait for readers (who do
+     * not) to complete before tree restructuring operations.
+     */
+    static final class TreeBin<K,V> extends Node<K,V> {
+        TreeNode<K,V> root;
+        volatile TreeNode<K,V> first;
+        volatile Thread waiter;
+        volatile int lockState;
+        // values for lockState
+        static final int WRITER = 1; // set while holding write lock
+        static final int WAITER = 2; // set when waiting for write lock
+        static final int READER = 4; // increment value for setting read lock
+
+        /**
+         * Tie-breaking utility for ordering insertions when equal
+         * hashCodes and non-comparable. We don't require a total
+         * order, just a consistent insertion rule to maintain
+         * equivalence across rebalancings. Tie-breaking further than
+         * necessary simplifies testing a bit.
+         */
+        static int tieBreakOrder(Object a, Object b) {
+            int d;
+            if (a == null || b == null ||
+                (d = a.getClass().getName().
+                 compareTo(b.getClass().getName())) == 0)
+                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
+                     -1 : 1);
+            return d;
+        }
+
+        /**
+         * Creates bin with initial set of nodes headed by b.
+         */
+        TreeBin(TreeNode<K,V> b) {
+            super(TREEBIN, null, null, null);
+            this.first = b;
+            TreeNode<K,V> r = null;
+            for (TreeNode<K,V> x = b, next; x != null; x = next) {
+                next = (TreeNode<K,V>)x.next;
+                x.left = x.right = null;
+                if (r == null) {
+                    x.parent = null;
+                    x.red = false;
+                    r = x;
+                }
+                else {
+                    K k = x.key;
+                    int h = x.hash;
+                    Class<?> kc = null;
+                    for (TreeNode<K,V> p = r;;) {
+                        int dir, ph;
+                        K pk = p.key;
+                        if ((ph = p.hash) > h)
+                            dir = -1;
+                        else if (ph < h)
+                            dir = 1;
+                        else if ((kc == null &&
+                                  (kc = comparableClassFor(k)) == null) ||
+                                 (dir = compareComparables(kc, k, pk)) == 0)
+                            dir = tieBreakOrder(k, pk);
+                        TreeNode<K,V> xp = p;
+                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                            x.parent = xp;
+                            if (dir <= 0)
+                                xp.left = x;
+                            else
+                                xp.right = x;
+                            r = balanceInsertion(r, x);
+                            break;
+                        }
+                    }
+                }
+            }
+            this.root = r;
+            assert checkInvariants(root);
+        }
+
+        /**
+         * Acquires write lock for tree restructuring.
+         */
+        private final void lockRoot() {
+            if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
+                contendedLock(); // offload to separate method
+        }
+
+        /**
+         * Releases write lock for tree restructuring.
+         */
+        private final void unlockRoot() {
+            lockState = 0;
+        }
+
+        /**
+         * Possibly blocks awaiting root lock.
+         */
+        private final void contendedLock() {
+            boolean waiting = false;
+            for (int s;;) {
+                if (((s = lockState) & ~WAITER) == 0) {
+                    if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
+                        if (waiting)
+                            waiter = null;
+                        return;
+                    }
+                }
+                else if ((s & WAITER) == 0) {
+                    if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
+                        waiting = true;
+                        waiter = Thread.currentThread();
+                    }
+                }
+                else if (waiting)
+                    LockSupport.park(this);
+            }
+        }
+
+        /**
+         * Returns matching node or null if none. Tries to search
+         * using tree comparisons from root, but continues linear
+         * search when lock not available.
+         */
+        final Node<K,V> find(int h, Object k) {
+            if (k != null) {
+                for (Node<K,V> e = first; e != null; ) {
+                    int s; K ek;
+                    if (((s = lockState) & (WAITER|WRITER)) != 0) {
+                        if (e.hash == h &&
+                            ((ek = e.key) == k || (ek != null && k.equals(ek))))
+                            return e;
+                        e = e.next;
+                    }
+                    else if (U.compareAndSwapInt(this, LOCKSTATE, s,
+                                                 s + READER)) {
+                        TreeNode<K,V> r, p;
+                        try {
+                            p = ((r = root) == null ? null :
+                                 r.findTreeNode(h, k, null));
+                        } finally {
+                            Thread w;
+                            if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
+                                (READER|WAITER) && (w = waiter) != null)
+                                LockSupport.unpark(w);
+                        }
+                        return p;
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Finds or adds a node.
+         * @return null if added
+         */
+        final TreeNode<K,V> putTreeVal(int h, K k, V v) {
+            Class<?> kc = null;
+            boolean searched = false;
+            for (TreeNode<K,V> p = root;;) {
+                int dir, ph; K pk;
+                if (p == null) {
+                    first = root = new TreeNode<K,V>(h, k, v, null, null);
+                    break;
+                }
+                else if ((ph = p.hash) > h)
+                    dir = -1;
+                else if (ph < h)
+                    dir = 1;
+                else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
+                    return p;
+                else if ((kc == null &&
+                          (kc = comparableClassFor(k)) == null) ||
+                         (dir = compareComparables(kc, k, pk)) == 0) {
+                    if (!searched) {
+                        TreeNode<K,V> q, ch;
+                        searched = true;
+                        if (((ch = p.left) != null &&
+                             (q = ch.findTreeNode(h, k, kc)) != null) ||
+                            ((ch = p.right) != null &&
+                             (q = ch.findTreeNode(h, k, kc)) != null))
+                            return q;
+                    }
+                    dir = tieBreakOrder(k, pk);
+                }
+
+                TreeNode<K,V> xp = p;
+                if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                    TreeNode<K,V> x, f = first;
+                    first = x = new TreeNode<K,V>(h, k, v, f, xp);
+                    if (f != null)
+                        f.prev = x;
+                    if (dir <= 0)
+                        xp.left = x;
+                    else
+                        xp.right = x;
+                    if (!xp.red)
+                        x.red = true;
+                    else {
+                        lockRoot();
+                        try {
+                            root = balanceInsertion(root, x);
+                        } finally {
+                            unlockRoot();
+                        }
+                    }
+                    break;
+                }
+            }
+            assert checkInvariants(root);
+            return null;
+        }
+
+        /**
+         * Removes the given node, that must be present before this
+         * call.  This is messier than typical red-black deletion code
+         * because we cannot swap the contents of an interior node
+         * with a leaf successor that is pinned by "next" pointers
+         * that are accessible independently of lock. So instead we
+         * swap the tree linkages.
+         *
+         * @return true if now too small, so should be untreeified
+         */
+        final boolean removeTreeNode(TreeNode<K,V> p) {
+            TreeNode<K,V> next = (TreeNode<K,V>)p.next;
+            TreeNode<K,V> pred = p.prev;  // unlink traversal pointers
+            TreeNode<K,V> r, rl;
+            if (pred == null)
+                first = next;
+            else
+                pred.next = next;
+            if (next != null)
+                next.prev = pred;
+            if (first == null) {
+                root = null;
+                return true;
+            }
+            if ((r = root) == null || r.right == null || // too small
+                (rl = r.left) == null || rl.left == null)
+                return true;
+            lockRoot();
+            try {
+                TreeNode<K,V> replacement;
+                TreeNode<K,V> pl = p.left;
+                TreeNode<K,V> pr = p.right;
+                if (pl != null && pr != null) {
+                    TreeNode<K,V> s = pr, sl;
+                    while ((sl = s.left) != null) // find successor
+                        s = sl;
+                    boolean c = s.red; s.red = p.red; p.red = c; // swap colors
+                    TreeNode<K,V> sr = s.right;
+                    TreeNode<K,V> pp = p.parent;
+                    if (s == pr) { // p was s's direct parent
+                        p.parent = s;
+                        s.right = p;
+                    }
+                    else {
+                        TreeNode<K,V> sp = s.parent;
+                        if ((p.parent = sp) != null) {
+                            if (s == sp.left)
+                                sp.left = p;
+                            else
+                                sp.right = p;
+                        }
+                        if ((s.right = pr) != null)
+                            pr.parent = s;
+                    }
+                    p.left = null;
+                    if ((p.right = sr) != null)
+                        sr.parent = p;
+                    if ((s.left = pl) != null)
+                        pl.parent = s;
+                    if ((s.parent = pp) == null)
+                        r = s;
+                    else if (p == pp.left)
+                        pp.left = s;
+                    else
+                        pp.right = s;
+                    if (sr != null)
+                        replacement = sr;
+                    else
+                        replacement = p;
+                }
+                else if (pl != null)
+                    replacement = pl;
+                else if (pr != null)
+                    replacement = pr;
+                else
+                    replacement = p;
+                if (replacement != p) {
+                    TreeNode<K,V> pp = replacement.parent = p.parent;
+                    if (pp == null)
+                        r = replacement;
+                    else if (p == pp.left)
+                        pp.left = replacement;
+                    else
+                        pp.right = replacement;
+                    p.left = p.right = p.parent = null;
+                }
+
+                root = (p.red) ? r : balanceDeletion(r, replacement);
+
+                if (p == replacement) {  // detach pointers
+                    TreeNode<K,V> pp;
+                    if ((pp = p.parent) != null) {
+                        if (p == pp.left)
+                            pp.left = null;
+                        else if (p == pp.right)
+                            pp.right = null;
+                        p.parent = null;
+                    }
+                }
+            } finally {
+                unlockRoot();
+            }
+            assert checkInvariants(root);
+            return false;
+        }
+
+        /* ------------------------------------------------------------ */
+        // Red-black tree methods, all adapted from CLR
+
+        static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
+                                              TreeNode<K,V> p) {
+            TreeNode<K,V> r, pp, rl;
+            if (p != null && (r = p.right) != null) {
+                if ((rl = p.right = r.left) != null)
+                    rl.parent = p;
+                if ((pp = r.parent = p.parent) == null)
+                    (root = r).red = false;
+                else if (pp.left == p)
+                    pp.left = r;
+                else
+                    pp.right = r;
+                r.left = p;
+                p.parent = r;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
+                                               TreeNode<K,V> p) {
+            TreeNode<K,V> l, pp, lr;
+            if (p != null && (l = p.left) != null) {
+                if ((lr = p.left = l.right) != null)
+                    lr.parent = p;
+                if ((pp = l.parent = p.parent) == null)
+                    (root = l).red = false;
+                else if (pp.right == p)
+                    pp.right = l;
+                else
+                    pp.left = l;
+                l.right = p;
+                p.parent = l;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
+                                                    TreeNode<K,V> x) {
+            x.red = true;
+            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
+                if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (!xp.red || (xpp = xp.parent) == null)
+                    return root;
+                if (xp == (xppl = xpp.left)) {
+                    if ((xppr = xpp.right) != null && xppr.red) {
+                        xppr.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.right) {
+                            root = rotateLeft(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateRight(root, xpp);
+                            }
+                        }
+                    }
+                }
+                else {
+                    if (xppl != null && xppl.red) {
+                        xppl.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.left) {
+                            root = rotateRight(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateLeft(root, xpp);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
+                                                   TreeNode<K,V> x) {
+            for (TreeNode<K,V> xp, xpl, xpr;;) {
+                if (x == null || x == root)
+                    return root;
+                else if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (x.red) {
+                    x.red = false;
+                    return root;
+                }
+                else if ((xpl = xp.left) == x) {
+                    if ((xpr = xp.right) != null && xpr.red) {
+                        xpr.red = false;
+                        xp.red = true;
+                        root = rotateLeft(root, xp);
+                        xpr = (xp = x.parent) == null ? null : xp.right;
+                    }
+                    if (xpr == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpr.left, sr = xpr.right;
+                        if ((sr == null || !sr.red) &&
+                            (sl == null || !sl.red)) {
+                            xpr.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sr == null || !sr.red) {
+                                if (sl != null)
+                                    sl.red = false;
+                                xpr.red = true;
+                                root = rotateRight(root, xpr);
+                                xpr = (xp = x.parent) == null ?
+                                    null : xp.right;
+                            }
+                            if (xpr != null) {
+                                xpr.red = (xp == null) ? false : xp.red;
+                                if ((sr = xpr.right) != null)
+                                    sr.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateLeft(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+                else { // symmetric
+                    if (xpl != null && xpl.red) {
+                        xpl.red = false;
+                        xp.red = true;
+                        root = rotateRight(root, xp);
+                        xpl = (xp = x.parent) == null ? null : xp.left;
+                    }
+                    if (xpl == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpl.left, sr = xpl.right;
+                        if ((sl == null || !sl.red) &&
+                            (sr == null || !sr.red)) {
+                            xpl.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sl == null || !sl.red) {
+                                if (sr != null)
+                                    sr.red = false;
+                                xpl.red = true;
+                                root = rotateLeft(root, xpl);
+                                xpl = (xp = x.parent) == null ?
+                                    null : xp.left;
+                            }
+                            if (xpl != null) {
+                                xpl.red = (xp == null) ? false : xp.red;
+                                if ((sl = xpl.left) != null)
+                                    sl.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateRight(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Checks invariants recursively for the tree of Nodes rooted at t.
+         */
+        static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
+            TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
+                tb = t.prev, tn = (TreeNode<K,V>)t.next;
+            if (tb != null && tb.next != t)
+                return false;
+            if (tn != null && tn.prev != t)
+                return false;
+            if (tp != null && t != tp.left && t != tp.right)
+                return false;
+            if (tl != null && (tl.parent != t || tl.hash > t.hash))
+                return false;
+            if (tr != null && (tr.parent != t || tr.hash < t.hash))
+                return false;
+            if (t.red && tl != null && tl.red && tr != null && tr.red)
+                return false;
+            if (tl != null && !checkInvariants(tl))
+                return false;
+            if (tr != null && !checkInvariants(tr))
+                return false;
+            return true;
+        }
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long LOCKSTATE;
+        static {
+            try {
+                LOCKSTATE = U.objectFieldOffset
+                    (TreeBin.class.getDeclaredField("lockState"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /* ----------------Table Traversal -------------- */
+
+    /**
+     * Records the table, its length, and current traversal index for a
+     * traverser that must process a region of a forwarded table before
+     * proceeding with current table.
+     */
+    static final class TableStack<K,V> {
+        int length;
+        int index;
+        Node<K,V>[] tab;
+        TableStack<K,V> next;
+    }
+
+    /**
+     * Encapsulates traversal for methods such as containsValue; also
+     * serves as a base class for other iterators and spliterators.
+     *
+     * Method advance visits once each still-valid node that was
+     * reachable upon iterator construction. It might miss some that
+     * were added to a bin after the bin was visited, which is OK wrt
+     * consistency guarantees. Maintaining this property in the face
+     * of possible ongoing resizes requires a fair amount of
+     * bookkeeping state that is difficult to optimize away amidst
+     * volatile accesses.  Even so, traversal maintains reasonable
+     * throughput.
+     *
+     * Normally, iteration proceeds bin-by-bin traversing lists.
+     * However, if the table has been resized, then all future steps
+     * must traverse both the bin at the current index as well as at
+     * (index + baseSize); and so on for further resizings. To
+     * paranoically cope with potential sharing by users of iterators
+     * across threads, iteration terminates if a bounds checks fails
+     * for a table read.
+     */
+    static class Traverser<K,V> {
+        Node<K,V>[] tab;        // current table; updated if resized
+        Node<K,V> next;         // the next entry to use
+        TableStack<K,V> stack, spare; // to save/restore on ForwardingNodes
+        int index;              // index of bin to use next
+        int baseIndex;          // current index of initial table
+        int baseLimit;          // index bound for initial table
+        final int baseSize;     // initial table size
+
+        Traverser(Node<K,V>[] tab, int size, int index, int limit) {
+            this.tab = tab;
+            this.baseSize = size;
+            this.baseIndex = this.index = index;
+            this.baseLimit = limit;
+            this.next = null;
+        }
+
+        /**
+         * Advances if possible, returning next valid node, or null if none.
+         */
+        final Node<K,V> advance() {
+            Node<K,V> e;
+            if ((e = next) != null)
+                e = e.next;
+            for (;;) {
+                Node<K,V>[] t; int i, n;  // must use locals in checks
+                if (e != null)
+                    return next = e;
+                if (baseIndex >= baseLimit || (t = tab) == null ||
+                    (n = t.length) <= (i = index) || i < 0)
+                    return next = null;
+                if ((e = tabAt(t, i)) != null && e.hash < 0) {
+                    if (e instanceof ForwardingNode) {
+                        tab = ((ForwardingNode<K,V>)e).nextTable;
+                        e = null;
+                        pushState(t, i, n);
+                        continue;
+                    }
+                    else if (e instanceof TreeBin)
+                        e = ((TreeBin<K,V>)e).first;
+                    else
+                        e = null;
+                }
+                if (stack != null)
+                    recoverState(n);
+                else if ((index = i + baseSize) >= n)
+                    index = ++baseIndex; // visit upper slots if present
+            }
+        }
+
+        /**
+         * Saves traversal state upon encountering a forwarding node.
+         */
+        private void pushState(Node<K,V>[] t, int i, int n) {
+            TableStack<K,V> s = spare;  // reuse if possible
+            if (s != null)
+                spare = s.next;
+            else
+                s = new TableStack<K,V>();
+            s.tab = t;
+            s.length = n;
+            s.index = i;
+            s.next = stack;
+            stack = s;
+        }
+
+        /**
+         * Possibly pops traversal state.
+         *
+         * @param n length of current table
+         */
+        private void recoverState(int n) {
+            TableStack<K,V> s; int len;
+            while ((s = stack) != null && (index += (len = s.length)) >= n) {
+                n = len;
+                index = s.index;
+                tab = s.tab;
+                s.tab = null;
+                TableStack<K,V> next = s.next;
+                s.next = spare; // save for reuse
+                stack = next;
+                spare = s;
+            }
+            if (s == null && (index += baseSize) >= n)
+                index = ++baseIndex;
+        }
+    }
+
+    /**
+     * Base of key, value, and entry Iterators. Adds fields to
+     * Traverser to support iterator.remove.
+     */
+    static class BaseIterator<K,V> extends Traverser<K,V> {
+        final ConcurrentHashMap<K,V> map;
+        Node<K,V> lastReturned;
+        BaseIterator(Node<K,V>[] tab, int size, int index, int limit,
+                    ConcurrentHashMap<K,V> map) {
+            super(tab, size, index, limit);
+            this.map = map;
+            advance();
+        }
+
+        public final boolean hasNext() { return next != null; }
+        public final boolean hasMoreElements() { return next != null; }
+
+        public final void remove() {
+            Node<K,V> p;
+            if ((p = lastReturned) == null)
+                throw new IllegalStateException();
+            lastReturned = null;
+            map.replaceNode(p.key, null, null);
+        }
+    }
+
+    static final class KeyIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<K>, Enumeration<K> {
+        KeyIterator(Node<K,V>[] tab, int index, int size, int limit,
+                    ConcurrentHashMap<K,V> map) {
+            super(tab, index, size, limit, map);
+        }
+
+        public final K next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            K k = p.key;
+            lastReturned = p;
+            advance();
+            return k;
+        }
+
+        public final K nextElement() { return next(); }
+    }
+
+    static final class ValueIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<V>, Enumeration<V> {
+        ValueIterator(Node<K,V>[] tab, int index, int size, int limit,
+                      ConcurrentHashMap<K,V> map) {
+            super(tab, index, size, limit, map);
+        }
+
+        public final V next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            V v = p.val;
+            lastReturned = p;
+            advance();
+            return v;
+        }
+
+        public final V nextElement() { return next(); }
+    }
+
+    static final class EntryIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<Map.Entry<K,V>> {
+        EntryIterator(Node<K,V>[] tab, int index, int size, int limit,
+                      ConcurrentHashMap<K,V> map) {
+            super(tab, index, size, limit, map);
+        }
+
+        public final Map.Entry<K,V> next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            K k = p.key;
+            V v = p.val;
+            lastReturned = p;
+            advance();
+            return new MapEntry<K,V>(k, v, map);
+        }
+    }
+
+    /**
+     * Exported Entry for EntryIterator.
+     */
+    static final class MapEntry<K,V> implements Map.Entry<K,V> {
+        final K key; // non-null
+        V val;       // non-null
+        final ConcurrentHashMap<K,V> map;
+        MapEntry(K key, V val, ConcurrentHashMap<K,V> map) {
+            this.key = key;
+            this.val = val;
+            this.map = map;
+        }
+        public K getKey()        { return key; }
+        public V getValue()      { return val; }
+        public int hashCode()    { return key.hashCode() ^ val.hashCode(); }
+        public String toString() {
+            return Helpers.mapEntryToString(key, val);
+        }
+
+        public boolean equals(Object o) {
+            Object k, v; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    (k == key || k.equals(key)) &&
+                    (v == val || v.equals(val)));
+        }
+
+        /**
+         * Sets our entry's value and writes through to the map. The
+         * value to return is somewhat arbitrary here. Since we do not
+         * necessarily track asynchronous changes, the most recent
+         * "previous" value could be different from what we return (or
+         * could even have been removed, in which case the put will
+         * re-establish). We do not and cannot guarantee more.
+         */
+        public V setValue(V value) {
+            if (value == null) throw new NullPointerException();
+            V v = val;
+            val = value;
+            map.put(key, value);
+            return v;
+        }
+    }
+
+    static final class KeySpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<K> {
+        long est;               // size estimate
+        KeySpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                       long est) {
+            super(tab, size, index, limit);
+            this.est = est;
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new KeySpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                        f, est >>>= 1);
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null;)
+                action.accept(p.key);
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept(p.key);
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+    }
+
+    static final class ValueSpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<V> {
+        long est;               // size estimate
+        ValueSpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                         long est) {
+            super(tab, size, index, limit);
+            this.est = est;
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new ValueSpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                          f, est >>>= 1);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null;)
+                action.accept(p.val);
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept(p.val);
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.CONCURRENT | Spliterator.NONNULL;
+        }
+    }
+
+    static final class EntrySpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        final ConcurrentHashMap<K,V> map; // To export MapEntry
+        long est;               // size estimate
+        EntrySpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                         long est, ConcurrentHashMap<K,V> map) {
+            super(tab, size, index, limit);
+            this.map = map;
+            this.est = est;
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new EntrySpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                          f, est >>>= 1, map);
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null; )
+                action.accept(new MapEntry<K,V>(p.key, p.val, map));
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept(new MapEntry<K,V>(p.key, p.val, map));
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+    }
+
+    // Parallel bulk operations
+
+    /**
+     * Computes initial batch value for bulk tasks. The returned value
+     * is approximately exp2 of the number of times (minus one) to
+     * split task by two before executing leaf action. This value is
+     * faster to compute and more convenient to use as a guide to
+     * splitting than is the depth, since it is used while dividing by
+     * two anyway.
+     */
+    final int batchFor(long b) {
+        long n;
+        if (b == Long.MAX_VALUE || (n = sumCount()) <= 1L || n < b)
+            return 0;
+        int sp = ForkJoinPool.getCommonPoolParallelism() << 2; // slack of 4
+        return (b <= 0L || (n /= b) >= sp) ? sp : (int)n;
+    }
+
+    /**
+     * Performs the given action for each (key, value).
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEach(long parallelismThreshold,
+                        BiConsumer<? super K,? super V> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachMappingTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each (key, value).
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEach(long parallelismThreshold,
+                            BiFunction<? super K, ? super V, ? extends U> transformer,
+                            Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedMappingTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each (key, value), or null if none.  Upon
+     * success, further element processing is suppressed and the
+     * results of any other parallel invocations of the search
+     * function are ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each (key, value), or null if none
+     * @since 1.8
+     */
+    public <U> U search(long parallelismThreshold,
+                        BiFunction<? super K, ? super V, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchMappingsTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public <U> U reduce(long parallelismThreshold,
+                        BiFunction<? super K, ? super V, ? extends U> transformer,
+                        BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public double reduceToDouble(long parallelismThreshold,
+                                 ToDoubleBiFunction<? super K, ? super V> transformer,
+                                 double basis,
+                                 DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public long reduceToLong(long parallelismThreshold,
+                             ToLongBiFunction<? super K, ? super V> transformer,
+                             long basis,
+                             LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public int reduceToInt(long parallelismThreshold,
+                           ToIntBiFunction<? super K, ? super V> transformer,
+                           int basis,
+                           IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each key.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachKey(long parallelismThreshold,
+                           Consumer<? super K> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachKeyTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each key.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEachKey(long parallelismThreshold,
+                               Function<? super K, ? extends U> transformer,
+                               Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedKeyTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each key, or null if none. Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each key, or null if none
+     * @since 1.8
+     */
+    public <U> U searchKeys(long parallelismThreshold,
+                            Function<? super K, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchKeysTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all keys using the given
+     * reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all keys using the given
+     * reducer to combine values, or null if none
+     * @since 1.8
+     */
+    public K reduceKeys(long parallelismThreshold,
+                        BiFunction<? super K, ? super K, ? extends K> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceKeysTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, or
+     * null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public <U> U reduceKeys(long parallelismThreshold,
+                            Function<? super K, ? extends U> transformer,
+         BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public double reduceKeysToDouble(long parallelismThreshold,
+                                     ToDoubleFunction<? super K> transformer,
+                                     double basis,
+                                     DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public long reduceKeysToLong(long parallelismThreshold,
+                                 ToLongFunction<? super K> transformer,
+                                 long basis,
+                                 LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public int reduceKeysToInt(long parallelismThreshold,
+                               ToIntFunction<? super K> transformer,
+                               int basis,
+                               IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachValue(long parallelismThreshold,
+                             Consumer<? super V> action) {
+        if (action == null)
+            throw new NullPointerException();
+        new ForEachValueTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEachValue(long parallelismThreshold,
+                                 Function<? super V, ? extends U> transformer,
+                                 Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedValueTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each value, or null if none.  Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each value, or null if none
+     * @since 1.8
+     */
+    public <U> U searchValues(long parallelismThreshold,
+                              Function<? super V, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchValuesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all values using the
+     * given reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all values
+     * @since 1.8
+     */
+    public V reduceValues(long parallelismThreshold,
+                          BiFunction<? super V, ? super V, ? extends V> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceValuesTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values, or
+     * null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public <U> U reduceValues(long parallelismThreshold,
+                              Function<? super V, ? extends U> transformer,
+                              BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public double reduceValuesToDouble(long parallelismThreshold,
+                                       ToDoubleFunction<? super V> transformer,
+                                       double basis,
+                                       DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public long reduceValuesToLong(long parallelismThreshold,
+                                   ToLongFunction<? super V> transformer,
+                                   long basis,
+                                   LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public int reduceValuesToInt(long parallelismThreshold,
+                                 ToIntFunction<? super V> transformer,
+                                 int basis,
+                                 IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each entry.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachEntry(long parallelismThreshold,
+                             Consumer<? super Map.Entry<K,V>> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachEntryTask<K,V>(null, batchFor(parallelismThreshold), 0, 0, table,
+                                  action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each entry.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEachEntry(long parallelismThreshold,
+                                 Function<Map.Entry<K,V>, ? extends U> transformer,
+                                 Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedEntryTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each entry, or null if none.  Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each entry, or null if none
+     * @since 1.8
+     */
+    public <U> U searchEntries(long parallelismThreshold,
+                               Function<Map.Entry<K,V>, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchEntriesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all entries using the
+     * given reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all entries
+     * @since 1.8
+     */
+    public Map.Entry<K,V> reduceEntries(long parallelismThreshold,
+                                        BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceEntriesTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public <U> U reduceEntries(long parallelismThreshold,
+                               Function<Map.Entry<K,V>, ? extends U> transformer,
+                               BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public double reduceEntriesToDouble(long parallelismThreshold,
+                                        ToDoubleFunction<Map.Entry<K,V>> transformer,
+                                        double basis,
+                                        DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public long reduceEntriesToLong(long parallelismThreshold,
+                                    ToLongFunction<Map.Entry<K,V>> transformer,
+                                    long basis,
+                                    LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public int reduceEntriesToInt(long parallelismThreshold,
+                                  ToIntFunction<Map.Entry<K,V>> transformer,
+                                  int basis,
+                                  IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+
+    /* ----------------Views -------------- */
+
+    /**
+     * Base class for views.
+     */
+    abstract static class CollectionView<K,V,E>
+        implements Collection<E>, java.io.Serializable {
+        private static final long serialVersionUID = 7249069246763182397L;
+        final ConcurrentHashMap<K,V> map;
+        CollectionView(ConcurrentHashMap<K,V> map)  { this.map = map; }
+
+        /**
+         * Returns the map backing this view.
+         *
+         * @return the map backing this view
+         */
+        public ConcurrentHashMap<K,V> getMap() { return map; }
+
+        /**
+         * Removes all of the elements from this view, by removing all
+         * the mappings from the map backing this view.
+         */
+        public final void clear()      { map.clear(); }
+        public final int size()        { return map.size(); }
+        public final boolean isEmpty() { return map.isEmpty(); }
+
+        // implementations below rely on concrete classes supplying these
+        // abstract methods
+        /**
+         * Returns an iterator over the elements in this collection.
+         *
+         * <p>The returned iterator is
+         * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+         *
+         * @return an iterator over the elements in this collection
+         */
+        public abstract Iterator<E> iterator();
+        public abstract boolean contains(Object o);
+        public abstract boolean remove(Object o);
+
+        private static final String OOME_MSG = "Required array size too large";
+
+        public final Object[] toArray() {
+            long sz = map.mappingCount();
+            if (sz > MAX_ARRAY_SIZE)
+                throw new OutOfMemoryError(OOME_MSG);
+            int n = (int)sz;
+            Object[] r = new Object[n];
+            int i = 0;
+            for (E e : this) {
+                if (i == n) {
+                    if (n >= MAX_ARRAY_SIZE)
+                        throw new OutOfMemoryError(OOME_MSG);
+                    if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
+                        n = MAX_ARRAY_SIZE;
+                    else
+                        n += (n >>> 1) + 1;
+                    r = Arrays.copyOf(r, n);
+                }
+                r[i++] = e;
+            }
+            return (i == n) ? r : Arrays.copyOf(r, i);
+        }
+
+        @SuppressWarnings("unchecked")
+        public final <T> T[] toArray(T[] a) {
+            long sz = map.mappingCount();
+            if (sz > MAX_ARRAY_SIZE)
+                throw new OutOfMemoryError(OOME_MSG);
+            int m = (int)sz;
+            T[] r = (a.length >= m) ? a :
+                (T[])java.lang.reflect.Array
+                .newInstance(a.getClass().getComponentType(), m);
+            int n = r.length;
+            int i = 0;
+            for (E e : this) {
+                if (i == n) {
+                    if (n >= MAX_ARRAY_SIZE)
+                        throw new OutOfMemoryError(OOME_MSG);
+                    if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
+                        n = MAX_ARRAY_SIZE;
+                    else
+                        n += (n >>> 1) + 1;
+                    r = Arrays.copyOf(r, n);
+                }
+                r[i++] = (T)e;
+            }
+            if (a == r && i < n) {
+                r[i] = null; // null-terminate
+                return r;
+            }
+            return (i == n) ? r : Arrays.copyOf(r, i);
+        }
+
+        /**
+         * Returns a string representation of this collection.
+         * The string representation consists of the string representations
+         * of the collection's elements in the order they are returned by
+         * its iterator, enclosed in square brackets ({@code "[]"}).
+         * Adjacent elements are separated by the characters {@code ", "}
+         * (comma and space).  Elements are converted to strings as by
+         * {@link String#valueOf(Object)}.
+         *
+         * @return a string representation of this collection
+         */
+        public final String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append('[');
+            Iterator<E> it = iterator();
+            if (it.hasNext()) {
+                for (;;) {
+                    Object e = it.next();
+                    sb.append(e == this ? "(this Collection)" : e);
+                    if (!it.hasNext())
+                        break;
+                    sb.append(',').append(' ');
+                }
+            }
+            return sb.append(']').toString();
+        }
+
+        public final boolean containsAll(Collection<?> c) {
+            if (c != this) {
+                for (Object e : c) {
+                    if (e == null || !contains(e))
+                        return false;
+                }
+            }
+            return true;
+        }
+
+        public final boolean removeAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean modified = false;
+            for (Iterator<E> it = iterator(); it.hasNext();) {
+                if (c.contains(it.next())) {
+                    it.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+        public final boolean retainAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean modified = false;
+            for (Iterator<E> it = iterator(); it.hasNext();) {
+                if (!c.contains(it.next())) {
+                    it.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+    }
+
+    /**
+     * A view of a ConcurrentHashMap as a {@link Set} of keys, in
+     * which additions may optionally be enabled by mapping to a
+     * common value.  This class cannot be directly instantiated.
+     * See {@link #keySet(Object) keySet(V)},
+     * {@link #newKeySet() newKeySet()},
+     * {@link #newKeySet(int) newKeySet(int)}.
+     *
+     * @since 1.8
+     */
+    public static class KeySetView<K,V> extends CollectionView<K,V,K>
+        implements Set<K>, java.io.Serializable {
+        private static final long serialVersionUID = 7249069246763182397L;
+        private final V value;
+        KeySetView(ConcurrentHashMap<K,V> map, V value) {  // non-public
+            super(map);
+            this.value = value;
+        }
+
+        /**
+         * Returns the default mapped value for additions,
+         * or {@code null} if additions are not supported.
+         *
+         * @return the default mapped value for additions, or {@code null}
+         * if not supported
+         */
+        public V getMappedValue() { return value; }
+
+        /**
+         * {@inheritDoc}
+         * @throws NullPointerException if the specified key is null
+         */
+        public boolean contains(Object o) { return map.containsKey(o); }
+
+        /**
+         * Removes the key from this map view, by removing the key (and its
+         * corresponding value) from the backing map.  This method does
+         * nothing if the key is not in the map.
+         *
+         * @param  o the key to be removed from the backing map
+         * @return {@code true} if the backing map contained the specified key
+         * @throws NullPointerException if the specified key is null
+         */
+        public boolean remove(Object o) { return map.remove(o) != null; }
+
+        /**
+         * @return an iterator over the keys of the backing map
+         */
+        public Iterator<K> iterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new KeyIterator<K,V>(t, f, 0, f, m);
+        }
+
+        /**
+         * Adds the specified key to this set view by mapping the key to
+         * the default mapped value in the backing map, if defined.
+         *
+         * @param e key to be added
+         * @return {@code true} if this set changed as a result of the call
+         * @throws NullPointerException if the specified key is null
+         * @throws UnsupportedOperationException if no default mapped value
+         * for additions was provided
+         */
+        public boolean add(K e) {
+            V v;
+            if ((v = value) == null)
+                throw new UnsupportedOperationException();
+            return map.putVal(e, v, true) == null;
+        }
+
+        /**
+         * Adds all of the elements in the specified collection to this set,
+         * as if by calling {@link #add} on each one.
+         *
+         * @param c the elements to be inserted into this set
+         * @return {@code true} if this set changed as a result of the call
+         * @throws NullPointerException if the collection or any of its
+         * elements are {@code null}
+         * @throws UnsupportedOperationException if no default mapped value
+         * for additions was provided
+         */
+        public boolean addAll(Collection<? extends K> c) {
+            boolean added = false;
+            V v;
+            if ((v = value) == null)
+                throw new UnsupportedOperationException();
+            for (K e : c) {
+                if (map.putVal(e, v, true) == null)
+                    added = true;
+            }
+            return added;
+        }
+
+        public int hashCode() {
+            int h = 0;
+            for (K e : this)
+                h += e.hashCode();
+            return h;
+        }
+
+        public boolean equals(Object o) {
+            Set<?> c;
+            return ((o instanceof Set) &&
+                    ((c = (Set<?>)o) == this ||
+                     (containsAll(c) && c.containsAll(this))));
+        }
+
+        public Spliterator<K> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new KeySpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n);
+        }
+
+        public void forEach(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept(p.key);
+            }
+        }
+    }
+
+    /**
+     * A view of a ConcurrentHashMap as a {@link Collection} of
+     * values, in which additions are disabled. This class cannot be
+     * directly instantiated. See {@link #values()}.
+     */
+    static final class ValuesView<K,V> extends CollectionView<K,V,V>
+        implements Collection<V>, java.io.Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        ValuesView(ConcurrentHashMap<K,V> map) { super(map); }
+        public final boolean contains(Object o) {
+            return map.containsValue(o);
+        }
+
+        public final boolean remove(Object o) {
+            if (o != null) {
+                for (Iterator<V> it = iterator(); it.hasNext();) {
+                    if (o.equals(it.next())) {
+                        it.remove();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public final Iterator<V> iterator() {
+            ConcurrentHashMap<K,V> m = map;
+            Node<K,V>[] t;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new ValueIterator<K,V>(t, f, 0, f, m);
+        }
+
+        public final boolean add(V e) {
+            throw new UnsupportedOperationException();
+        }
+        public final boolean addAll(Collection<? extends V> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean removeIf(Predicate<? super V> filter) {
+            return map.removeValueIf(filter);
+        }
+
+        public Spliterator<V> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new ValueSpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n);
+        }
+
+        public void forEach(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept(p.val);
+            }
+        }
+    }
+
+    /**
+     * A view of a ConcurrentHashMap as a {@link Set} of (key, value)
+     * entries.  This class cannot be directly instantiated. See
+     * {@link #entrySet()}.
+     */
+    static final class EntrySetView<K,V> extends CollectionView<K,V,Map.Entry<K,V>>
+        implements Set<Map.Entry<K,V>>, java.io.Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        EntrySetView(ConcurrentHashMap<K,V> map) { super(map); }
+
+        public boolean contains(Object o) {
+            Object k, v, r; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (r = map.get(k)) != null &&
+                    (v = e.getValue()) != null &&
+                    (v == r || v.equals(r)));
+        }
+
+        public boolean remove(Object o) {
+            Object k, v; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    map.remove(k, v));
+        }
+
+        /**
+         * @return an iterator over the entries of the backing map
+         */
+        public Iterator<Map.Entry<K,V>> iterator() {
+            ConcurrentHashMap<K,V> m = map;
+            Node<K,V>[] t;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new EntryIterator<K,V>(t, f, 0, f, m);
+        }
+
+        public boolean add(Entry<K,V> e) {
+            return map.putVal(e.getKey(), e.getValue(), false) == null;
+        }
+
+        public boolean addAll(Collection<? extends Entry<K,V>> c) {
+            boolean added = false;
+            for (Entry<K,V> e : c) {
+                if (add(e))
+                    added = true;
+            }
+            return added;
+        }
+
+        public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
+            return map.removeEntryIf(filter);
+        }
+
+        public final int hashCode() {
+            int h = 0;
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; ) {
+                    h += p.hashCode();
+                }
+            }
+            return h;
+        }
+
+        public final boolean equals(Object o) {
+            Set<?> c;
+            return ((o instanceof Set) &&
+                    ((c = (Set<?>)o) == this ||
+                     (containsAll(c) && c.containsAll(this))));
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new EntrySpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n, m);
+        }
+
+        public void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept(new MapEntry<K,V>(p.key, p.val, map));
+            }
+        }
+
+    }
+
+    // -------------------------------------------------------
+
+    /**
+     * Base class for bulk tasks. Repeats some fields and code from
+     * class Traverser, because we need to subclass CountedCompleter.
+     */
+    @SuppressWarnings("serial")
+    abstract static class BulkTask<K,V,R> extends CountedCompleter<R> {
+        Node<K,V>[] tab;        // same as Traverser
+        Node<K,V> next;
+        TableStack<K,V> stack, spare;
+        int index;
+        int baseIndex;
+        int baseLimit;
+        final int baseSize;
+        int batch;              // split control
+
+        BulkTask(BulkTask<K,V,?> par, int b, int i, int f, Node<K,V>[] t) {
+            super(par);
+            this.batch = b;
+            this.index = this.baseIndex = i;
+            if ((this.tab = t) == null)
+                this.baseSize = this.baseLimit = 0;
+            else if (par == null)
+                this.baseSize = this.baseLimit = t.length;
+            else {
+                this.baseLimit = f;
+                this.baseSize = par.baseSize;
+            }
+        }
+
+        /**
+         * Same as Traverser version.
+         */
+        final Node<K,V> advance() {
+            Node<K,V> e;
+            if ((e = next) != null)
+                e = e.next;
+            for (;;) {
+                Node<K,V>[] t; int i, n;
+                if (e != null)
+                    return next = e;
+                if (baseIndex >= baseLimit || (t = tab) == null ||
+                    (n = t.length) <= (i = index) || i < 0)
+                    return next = null;
+                if ((e = tabAt(t, i)) != null && e.hash < 0) {
+                    if (e instanceof ForwardingNode) {
+                        tab = ((ForwardingNode<K,V>)e).nextTable;
+                        e = null;
+                        pushState(t, i, n);
+                        continue;
+                    }
+                    else if (e instanceof TreeBin)
+                        e = ((TreeBin<K,V>)e).first;
+                    else
+                        e = null;
+                }
+                if (stack != null)
+                    recoverState(n);
+                else if ((index = i + baseSize) >= n)
+                    index = ++baseIndex;
+            }
+        }
+
+        private void pushState(Node<K,V>[] t, int i, int n) {
+            TableStack<K,V> s = spare;
+            if (s != null)
+                spare = s.next;
+            else
+                s = new TableStack<K,V>();
+            s.tab = t;
+            s.length = n;
+            s.index = i;
+            s.next = stack;
+            stack = s;
+        }
+
+        private void recoverState(int n) {
+            TableStack<K,V> s; int len;
+            while ((s = stack) != null && (index += (len = s.length)) >= n) {
+                n = len;
+                index = s.index;
+                tab = s.tab;
+                s.tab = null;
+                TableStack<K,V> next = s.next;
+                s.next = spare; // save for reuse
+                stack = next;
+                spare = s;
+            }
+            if (s == null && (index += baseSize) >= n)
+                index = ++baseIndex;
+        }
+    }
+
+    /*
+     * Task classes. Coded in a regular but ugly format/style to
+     * simplify checks that each variant differs in the right way from
+     * others. The null screenings exist because compilers cannot tell
+     * that we've already null-checked task arguments, so we force
+     * simplest hoisted bypass to help avoid convoluted traps.
+     */
+    @SuppressWarnings("serial")
+    static final class ForEachKeyTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super K> action;
+        ForEachKeyTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super K> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super K> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachKeyTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null;)
+                    action.accept(p.key);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachValueTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super V> action;
+        ForEachValueTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super V> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super V> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachValueTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null;)
+                    action.accept(p.val);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachEntryTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super Entry<K,V>> action;
+        ForEachEntryTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super Entry<K,V>> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super Entry<K,V>> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachEntryTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    action.accept(p);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachMappingTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final BiConsumer<? super K, ? super V> action;
+        ForEachMappingTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiConsumer<? super K,? super V> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final BiConsumer<? super K, ? super V> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachMappingTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    action.accept(p.key, p.val);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedKeyTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<? super K, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedKeyTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super K, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<? super K, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedKeyTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedValueTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<? super V, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedValueTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super V, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<? super V, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedValueTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.val)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedEntryTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<Map.Entry<K,V>, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedEntryTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<Map.Entry<K,V>, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<Map.Entry<K,V>, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedEntryTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedMappingTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final BiFunction<? super K, ? super V, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedMappingTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiFunction<? super K, ? super V, ? extends U> transformer,
+             Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedMappingTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key, p.val)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchKeysTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super K, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super K, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<? super K, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchKeysTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p.key)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchValuesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super V, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super V, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<? super V, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchValuesTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p.val)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchEntriesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<Entry<K,V>, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<Entry<K,V>, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<Entry<K,V>, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchEntriesTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchMappingsTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final BiFunction<? super K, ? super V, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchMappingsTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiFunction<? super K, ? super V, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchMappingsTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p.key, p.val)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ReduceKeysTask<K,V>
+        extends BulkTask<K,V,K> {
+        final BiFunction<? super K, ? super K, ? extends K> reducer;
+        K result;
+        ReduceKeysTask<K,V> rights, nextRight;
+        ReduceKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceKeysTask<K,V> nextRight,
+             BiFunction<? super K, ? super K, ? extends K> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final K getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super K, ? super K, ? extends K> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceKeysTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                K r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    K u = p.key;
+                    r = (r == null) ? u : u == null ? r : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    ReduceKeysTask<K,V>
+                        t = (ReduceKeysTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        K tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ReduceValuesTask<K,V>
+        extends BulkTask<K,V,V> {
+        final BiFunction<? super V, ? super V, ? extends V> reducer;
+        V result;
+        ReduceValuesTask<K,V> rights, nextRight;
+        ReduceValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceValuesTask<K,V> nextRight,
+             BiFunction<? super V, ? super V, ? extends V> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final V getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super V, ? super V, ? extends V> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceValuesTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                V r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    V v = p.val;
+                    r = (r == null) ? v : reducer.apply(r, v);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    ReduceValuesTask<K,V>
+                        t = (ReduceValuesTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        V tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ReduceEntriesTask<K,V>
+        extends BulkTask<K,V,Map.Entry<K,V>> {
+        final BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer;
+        Map.Entry<K,V> result;
+        ReduceEntriesTask<K,V> rights, nextRight;
+        ReduceEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceEntriesTask<K,V> nextRight,
+             BiFunction<Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final Map.Entry<K,V> getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceEntriesTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                Map.Entry<K,V> r = null;
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = (r == null) ? p : reducer.apply(r, p);
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    ReduceEntriesTask<K,V>
+                        t = (ReduceEntriesTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        Map.Entry<K,V> tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super K, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceKeysTask<K,V,U> rights, nextRight;
+        MapReduceKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysTask<K,V,U> nextRight,
+             Function<? super K, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<? super K, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysTask<K,V,U>
+                        t = (MapReduceKeysTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super V, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceValuesTask<K,V,U> rights, nextRight;
+        MapReduceValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesTask<K,V,U> nextRight,
+             Function<? super V, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<? super V, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.val)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesTask<K,V,U>
+                        t = (MapReduceValuesTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<Map.Entry<K,V>, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceEntriesTask<K,V,U> rights, nextRight;
+        MapReduceEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesTask<K,V,U> nextRight,
+             Function<Map.Entry<K,V>, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<Map.Entry<K,V>, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesTask<K,V,U>
+                        t = (MapReduceEntriesTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final BiFunction<? super K, ? super V, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceMappingsTask<K,V,U> rights, nextRight;
+        MapReduceMappingsTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsTask<K,V,U> nextRight,
+             BiFunction<? super K, ? super V, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key, p.val)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsTask<K,V,U>
+                        t = (MapReduceMappingsTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<? super K> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceKeysToDoubleTask<K,V> rights, nextRight;
+        MapReduceKeysToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<? super K> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<? super K> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToDoubleTask<K,V>
+                        t = (MapReduceKeysToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<? super V> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceValuesToDoubleTask<K,V> rights, nextRight;
+        MapReduceValuesToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<? super V> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<? super V> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToDoubleTask<K,V>
+                        t = (MapReduceValuesToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<Map.Entry<K,V>> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceEntriesToDoubleTask<K,V> rights, nextRight;
+        MapReduceEntriesToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<Map.Entry<K,V>> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<Map.Entry<K,V>> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToDoubleTask<K,V>
+                        t = (MapReduceEntriesToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleBiFunction<? super K, ? super V> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceMappingsToDoubleTask<K,V> rights, nextRight;
+        MapReduceMappingsToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToDoubleTask<K,V> nextRight,
+             ToDoubleBiFunction<? super K, ? super V> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleBiFunction<? super K, ? super V> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToDoubleTask<K,V>
+                        t = (MapReduceMappingsToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<? super K> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceKeysToLongTask<K,V> rights, nextRight;
+        MapReduceKeysToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToLongTask<K,V> nextRight,
+             ToLongFunction<? super K> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<? super K> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToLongTask<K,V>
+                        t = (MapReduceKeysToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<? super V> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceValuesToLongTask<K,V> rights, nextRight;
+        MapReduceValuesToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToLongTask<K,V> nextRight,
+             ToLongFunction<? super V> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<? super V> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToLongTask<K,V>
+                        t = (MapReduceValuesToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<Map.Entry<K,V>> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceEntriesToLongTask<K,V> rights, nextRight;
+        MapReduceEntriesToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToLongTask<K,V> nextRight,
+             ToLongFunction<Map.Entry<K,V>> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<Map.Entry<K,V>> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToLongTask<K,V>
+                        t = (MapReduceEntriesToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongBiFunction<? super K, ? super V> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceMappingsToLongTask<K,V> rights, nextRight;
+        MapReduceMappingsToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToLongTask<K,V> nextRight,
+             ToLongBiFunction<? super K, ? super V> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongBiFunction<? super K, ? super V> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToLongTask<K,V>
+                        t = (MapReduceMappingsToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<? super K> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceKeysToIntTask<K,V> rights, nextRight;
+        MapReduceKeysToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToIntTask<K,V> nextRight,
+             ToIntFunction<? super K> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<? super K> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToIntTask<K,V>
+                        t = (MapReduceKeysToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<? super V> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceValuesToIntTask<K,V> rights, nextRight;
+        MapReduceValuesToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToIntTask<K,V> nextRight,
+             ToIntFunction<? super V> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<? super V> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToIntTask<K,V>
+                        t = (MapReduceValuesToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<Map.Entry<K,V>> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceEntriesToIntTask<K,V> rights, nextRight;
+        MapReduceEntriesToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToIntTask<K,V> nextRight,
+             ToIntFunction<Map.Entry<K,V>> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<Map.Entry<K,V>> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToIntTask<K,V>
+                        t = (MapReduceEntriesToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntBiFunction<? super K, ? super V> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceMappingsToIntTask<K,V> rights, nextRight;
+        MapReduceMappingsToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToIntTask<K,V> nextRight,
+             ToIntBiFunction<? super K, ? super V> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntBiFunction<? super K, ? super V> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToIntTask<K,V>
+                        t = (MapReduceMappingsToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long SIZECTL;
+    private static final long TRANSFERINDEX;
+    private static final long BASECOUNT;
+    private static final long CELLSBUSY;
+    private static final long CELLVALUE;
+    private static final int ABASE;
+    private static final int ASHIFT;
+
+    static {
+        try {
+            SIZECTL = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("sizeCtl"));
+            TRANSFERINDEX = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("transferIndex"));
+            BASECOUNT = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("baseCount"));
+            CELLSBUSY = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("cellsBusy"));
+
+            CELLVALUE = U.objectFieldOffset
+                (CounterCell.class.getDeclaredField("value"));
+
+            ABASE = U.arrayBaseOffset(Node[].class);
+            int scale = U.arrayIndexScale(Node[].class);
+            if ((scale & (scale - 1)) != 0)
+                throw new Error("array index scale not a power of two");
+            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/java/util/concurrent/ConcurrentLinkedDeque.java b/java/util/concurrent/ConcurrentLinkedDeque.java
new file mode 100644
index 0000000..3edde54
--- /dev/null
+++ b/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -0,0 +1,1628 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from members of
+ * JCP JSR-166 Expert Group and released to the public domain, as explained
+ * at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractCollection;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An unbounded concurrent {@linkplain Deque deque} based on linked nodes.
+ * Concurrent insertion, removal, and access operations execute safely
+ * across multiple threads.
+ * A {@code ConcurrentLinkedDeque} is an appropriate choice when
+ * many threads will share access to a common collection.
+ * Like most other concurrent collection implementations, this class
+ * does not permit the use of {@code null} elements.
+ *
+ * <p>Iterators and spliterators are
+ * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ *
+ * <p>Beware that, unlike in most collections, the {@code size} method
+ * is <em>NOT</em> a constant-time operation. Because of the
+ * asynchronous nature of these deques, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Deque} and {@link Iterator} interfaces.
+ *
+ * <p>Memory consistency effects: As with other concurrent collections,
+ * actions in a thread prior to placing an object into a
+ * {@code ConcurrentLinkedDeque}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code ConcurrentLinkedDeque} in another thread.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ * @author Martin Buchholz
+ * @param <E> the type of elements held in this deque
+ */
+public class ConcurrentLinkedDeque<E>
+    extends AbstractCollection<E>
+    implements Deque<E>, java.io.Serializable {
+
+    /*
+     * This is an implementation of a concurrent lock-free deque
+     * supporting interior removes but not interior insertions, as
+     * required to support the entire Deque interface.
+     *
+     * We extend the techniques developed for ConcurrentLinkedQueue and
+     * LinkedTransferQueue (see the internal docs for those classes).
+     * Understanding the ConcurrentLinkedQueue implementation is a
+     * prerequisite for understanding the implementation of this class.
+     *
+     * The data structure is a symmetrical doubly-linked "GC-robust"
+     * linked list of nodes.  We minimize the number of volatile writes
+     * using two techniques: advancing multiple hops with a single CAS
+     * and mixing volatile and non-volatile writes of the same memory
+     * locations.
+     *
+     * A node contains the expected E ("item") and links to predecessor
+     * ("prev") and successor ("next") nodes:
+     *
+     * class Node<E> { volatile Node<E> prev, next; volatile E item; }
+     *
+     * A node p is considered "live" if it contains a non-null item
+     * (p.item != null).  When an item is CASed to null, the item is
+     * atomically logically deleted from the collection.
+     *
+     * At any time, there is precisely one "first" node with a null
+     * prev reference that terminates any chain of prev references
+     * starting at a live node.  Similarly there is precisely one
+     * "last" node terminating any chain of next references starting at
+     * a live node.  The "first" and "last" nodes may or may not be live.
+     * The "first" and "last" nodes are always mutually reachable.
+     *
+     * A new element is added atomically by CASing the null prev or
+     * next reference in the first or last node to a fresh node
+     * containing the element.  The element's node atomically becomes
+     * "live" at that point.
+     *
+     * A node is considered "active" if it is a live node, or the
+     * first or last node.  Active nodes cannot be unlinked.
+     *
+     * A "self-link" is a next or prev reference that is the same node:
+     *   p.prev == p  or  p.next == p
+     * Self-links are used in the node unlinking process.  Active nodes
+     * never have self-links.
+     *
+     * A node p is active if and only if:
+     *
+     * p.item != null ||
+     * (p.prev == null && p.next != p) ||
+     * (p.next == null && p.prev != p)
+     *
+     * The deque object has two node references, "head" and "tail".
+     * The head and tail are only approximations to the first and last
+     * nodes of the deque.  The first node can always be found by
+     * following prev pointers from head; likewise for tail.  However,
+     * it is permissible for head and tail to be referring to deleted
+     * nodes that have been unlinked and so may not be reachable from
+     * any live node.
+     *
+     * There are 3 stages of node deletion;
+     * "logical deletion", "unlinking", and "gc-unlinking".
+     *
+     * 1. "logical deletion" by CASing item to null atomically removes
+     * the element from the collection, and makes the containing node
+     * eligible for unlinking.
+     *
+     * 2. "unlinking" makes a deleted node unreachable from active
+     * nodes, and thus eventually reclaimable by GC.  Unlinked nodes
+     * may remain reachable indefinitely from an iterator.
+     *
+     * Physical node unlinking is merely an optimization (albeit a
+     * critical one), and so can be performed at our convenience.  At
+     * any time, the set of live nodes maintained by prev and next
+     * links are identical, that is, the live nodes found via next
+     * links from the first node is equal to the elements found via
+     * prev links from the last node.  However, this is not true for
+     * nodes that have already been logically deleted - such nodes may
+     * be reachable in one direction only.
+     *
+     * 3. "gc-unlinking" takes unlinking further by making active
+     * nodes unreachable from deleted nodes, making it easier for the
+     * GC to reclaim future deleted nodes.  This step makes the data
+     * structure "gc-robust", as first described in detail by Boehm
+     * (http://portal.acm.org/citation.cfm?doid=503272.503282).
+     *
+     * GC-unlinked nodes may remain reachable indefinitely from an
+     * iterator, but unlike unlinked nodes, are never reachable from
+     * head or tail.
+     *
+     * Making the data structure GC-robust will eliminate the risk of
+     * unbounded memory retention with conservative GCs and is likely
+     * to improve performance with generational GCs.
+     *
+     * When a node is dequeued at either end, e.g. via poll(), we would
+     * like to break any references from the node to active nodes.  We
+     * develop further the use of self-links that was very effective in
+     * other concurrent collection classes.  The idea is to replace
+     * prev and next pointers with special values that are interpreted
+     * to mean off-the-list-at-one-end.  These are approximations, but
+     * good enough to preserve the properties we want in our
+     * traversals, e.g. we guarantee that a traversal will never visit
+     * the same element twice, but we don't guarantee whether a
+     * traversal that runs out of elements will be able to see more
+     * elements later after enqueues at that end.  Doing gc-unlinking
+     * safely is particularly tricky, since any node can be in use
+     * indefinitely (for example by an iterator).  We must ensure that
+     * the nodes pointed at by head/tail never get gc-unlinked, since
+     * head/tail are needed to get "back on track" by other nodes that
+     * are gc-unlinked.  gc-unlinking accounts for much of the
+     * implementation complexity.
+     *
+     * Since neither unlinking nor gc-unlinking are necessary for
+     * correctness, there are many implementation choices regarding
+     * frequency (eagerness) of these operations.  Since volatile
+     * reads are likely to be much cheaper than CASes, saving CASes by
+     * unlinking multiple adjacent nodes at a time may be a win.
+     * gc-unlinking can be performed rarely and still be effective,
+     * since it is most important that long chains of deleted nodes
+     * are occasionally broken.
+     *
+     * The actual representation we use is that p.next == p means to
+     * goto the first node (which in turn is reached by following prev
+     * pointers from head), and p.next == null && p.prev == p means
+     * that the iteration is at an end and that p is a (static final)
+     * dummy node, NEXT_TERMINATOR, and not the last active node.
+     * Finishing the iteration when encountering such a TERMINATOR is
+     * good enough for read-only traversals, so such traversals can use
+     * p.next == null as the termination condition.  When we need to
+     * find the last (active) node, for enqueueing a new node, we need
+     * to check whether we have reached a TERMINATOR node; if so,
+     * restart traversal from tail.
+     *
+     * The implementation is completely directionally symmetrical,
+     * except that most public methods that iterate through the list
+     * follow next pointers ("forward" direction).
+     *
+     * We believe (without full proof) that all single-element deque
+     * operations (e.g., addFirst, peekLast, pollLast) are linearizable
+     * (see Herlihy and Shavit's book).  However, some combinations of
+     * operations are known not to be linearizable.  In particular,
+     * when an addFirst(A) is racing with pollFirst() removing B, it is
+     * possible for an observer iterating over the elements to observe
+     * A B C and subsequently observe A C, even though no interior
+     * removes are ever performed.  Nevertheless, iterators behave
+     * reasonably, providing the "weakly consistent" guarantees.
+     *
+     * Empirically, microbenchmarks suggest that this class adds about
+     * 40% overhead relative to ConcurrentLinkedQueue, which feels as
+     * good as we can hope for.
+     */
+
+    private static final long serialVersionUID = 876323262645176354L;
+
+    /**
+     * A node from which the first node on list (that is, the unique node p
+     * with p.prev == null && p.next != p) can be reached in O(1) time.
+     * Invariants:
+     * - the first node is always O(1) reachable from head via prev links
+     * - all live nodes are reachable from the first node via succ()
+     * - head != null
+     * - (tmp = head).next != tmp || tmp != head
+     * - head is never gc-unlinked (but may be unlinked)
+     * Non-invariants:
+     * - head.item may or may not be null
+     * - head may not be reachable from the first or last node, or from tail
+     */
+    private transient volatile Node<E> head;
+
+    /**
+     * A node from which the last node on list (that is, the unique node p
+     * with p.next == null && p.prev != p) can be reached in O(1) time.
+     * Invariants:
+     * - the last node is always O(1) reachable from tail via next links
+     * - all live nodes are reachable from the last node via pred()
+     * - tail != null
+     * - tail is never gc-unlinked (but may be unlinked)
+     * Non-invariants:
+     * - tail.item may or may not be null
+     * - tail may not be reachable from the first or last node, or from head
+     */
+    private transient volatile Node<E> tail;
+
+    private static final Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR;
+
+    @SuppressWarnings("unchecked")
+    Node<E> prevTerminator() {
+        return (Node<E>) PREV_TERMINATOR;
+    }
+
+    @SuppressWarnings("unchecked")
+    Node<E> nextTerminator() {
+        return (Node<E>) NEXT_TERMINATOR;
+    }
+
+    static final class Node<E> {
+        volatile Node<E> prev;
+        volatile E item;
+        volatile Node<E> next;
+
+        Node() {  // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
+        }
+
+        /**
+         * Constructs a new node.  Uses relaxed write because item can
+         * only be seen after publication via casNext or casPrev.
+         */
+        Node(E item) {
+            U.putObject(this, ITEM, item);
+        }
+
+        boolean casItem(E cmp, E val) {
+            return U.compareAndSwapObject(this, ITEM, cmp, val);
+        }
+
+        void lazySetNext(Node<E> val) {
+            U.putOrderedObject(this, NEXT, val);
+        }
+
+        boolean casNext(Node<E> cmp, Node<E> val) {
+            return U.compareAndSwapObject(this, NEXT, cmp, val);
+        }
+
+        void lazySetPrev(Node<E> val) {
+            U.putOrderedObject(this, PREV, val);
+        }
+
+        boolean casPrev(Node<E> cmp, Node<E> val) {
+            return U.compareAndSwapObject(this, PREV, cmp, val);
+        }
+
+        // Unsafe mechanics
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long PREV;
+        private static final long ITEM;
+        private static final long NEXT;
+
+        static {
+            try {
+                PREV = U.objectFieldOffset
+                    (Node.class.getDeclaredField("prev"));
+                ITEM = U.objectFieldOffset
+                    (Node.class.getDeclaredField("item"));
+                NEXT = U.objectFieldOffset
+                    (Node.class.getDeclaredField("next"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /**
+     * Links e as first element.
+     */
+    private void linkFirst(E e) {
+        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+
+        restartFromHead:
+        for (;;)
+            for (Node<E> h = head, p = h, q;;) {
+                if ((q = p.prev) != null &&
+                    (q = (p = q).prev) != null)
+                    // Check for head updates every other hop.
+                    // If p == q, we are sure to follow head instead.
+                    p = (h != (h = head)) ? h : q;
+                else if (p.next == p) // PREV_TERMINATOR
+                    continue restartFromHead;
+                else {
+                    // p is first node
+                    newNode.lazySetNext(p); // CAS piggyback
+                    if (p.casPrev(null, newNode)) {
+                        // Successful CAS is the linearization point
+                        // for e to become an element of this deque,
+                        // and for newNode to become "live".
+                        if (p != h) // hop two nodes at a time
+                            casHead(h, newNode);  // Failure is OK.
+                        return;
+                    }
+                    // Lost CAS race to another thread; re-read prev
+                }
+            }
+    }
+
+    /**
+     * Links e as last element.
+     */
+    private void linkLast(E e) {
+        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+
+        restartFromTail:
+        for (;;)
+            for (Node<E> t = tail, p = t, q;;) {
+                if ((q = p.next) != null &&
+                    (q = (p = q).next) != null)
+                    // Check for tail updates every other hop.
+                    // If p == q, we are sure to follow tail instead.
+                    p = (t != (t = tail)) ? t : q;
+                else if (p.prev == p) // NEXT_TERMINATOR
+                    continue restartFromTail;
+                else {
+                    // p is last node
+                    newNode.lazySetPrev(p); // CAS piggyback
+                    if (p.casNext(null, newNode)) {
+                        // Successful CAS is the linearization point
+                        // for e to become an element of this deque,
+                        // and for newNode to become "live".
+                        if (p != t) // hop two nodes at a time
+                            casTail(t, newNode);  // Failure is OK.
+                        return;
+                    }
+                    // Lost CAS race to another thread; re-read next
+                }
+            }
+    }
+
+    private static final int HOPS = 2;
+
+    /**
+     * Unlinks non-null node x.
+     */
+    void unlink(Node<E> x) {
+        // assert x != null;
+        // assert x.item == null;
+        // assert x != PREV_TERMINATOR;
+        // assert x != NEXT_TERMINATOR;
+
+        final Node<E> prev = x.prev;
+        final Node<E> next = x.next;
+        if (prev == null) {
+            unlinkFirst(x, next);
+        } else if (next == null) {
+            unlinkLast(x, prev);
+        } else {
+            // Unlink interior node.
+            //
+            // This is the common case, since a series of polls at the
+            // same end will be "interior" removes, except perhaps for
+            // the first one, since end nodes cannot be unlinked.
+            //
+            // At any time, all active nodes are mutually reachable by
+            // following a sequence of either next or prev pointers.
+            //
+            // Our strategy is to find the unique active predecessor
+            // and successor of x.  Try to fix up their links so that
+            // they point to each other, leaving x unreachable from
+            // active nodes.  If successful, and if x has no live
+            // predecessor/successor, we additionally try to gc-unlink,
+            // leaving active nodes unreachable from x, by rechecking
+            // that the status of predecessor and successor are
+            // unchanged and ensuring that x is not reachable from
+            // tail/head, before setting x's prev/next links to their
+            // logical approximate replacements, self/TERMINATOR.
+            Node<E> activePred, activeSucc;
+            boolean isFirst, isLast;
+            int hops = 1;
+
+            // Find active predecessor
+            for (Node<E> p = prev; ; ++hops) {
+                if (p.item != null) {
+                    activePred = p;
+                    isFirst = false;
+                    break;
+                }
+                Node<E> q = p.prev;
+                if (q == null) {
+                    if (p.next == p)
+                        return;
+                    activePred = p;
+                    isFirst = true;
+                    break;
+                }
+                else if (p == q)
+                    return;
+                else
+                    p = q;
+            }
+
+            // Find active successor
+            for (Node<E> p = next; ; ++hops) {
+                if (p.item != null) {
+                    activeSucc = p;
+                    isLast = false;
+                    break;
+                }
+                Node<E> q = p.next;
+                if (q == null) {
+                    if (p.prev == p)
+                        return;
+                    activeSucc = p;
+                    isLast = true;
+                    break;
+                }
+                else if (p == q)
+                    return;
+                else
+                    p = q;
+            }
+
+            // TODO: better HOP heuristics
+            if (hops < HOPS
+                // always squeeze out interior deleted nodes
+                && (isFirst | isLast))
+                return;
+
+            // Squeeze out deleted nodes between activePred and
+            // activeSucc, including x.
+            skipDeletedSuccessors(activePred);
+            skipDeletedPredecessors(activeSucc);
+
+            // Try to gc-unlink, if possible
+            if ((isFirst | isLast) &&
+
+                // Recheck expected state of predecessor and successor
+                (activePred.next == activeSucc) &&
+                (activeSucc.prev == activePred) &&
+                (isFirst ? activePred.prev == null : activePred.item != null) &&
+                (isLast  ? activeSucc.next == null : activeSucc.item != null)) {
+
+                updateHead(); // Ensure x is not reachable from head
+                updateTail(); // Ensure x is not reachable from tail
+
+                // Finally, actually gc-unlink
+                x.lazySetPrev(isFirst ? prevTerminator() : x);
+                x.lazySetNext(isLast  ? nextTerminator() : x);
+            }
+        }
+    }
+
+    /**
+     * Unlinks non-null first node.
+     */
+    private void unlinkFirst(Node<E> first, Node<E> next) {
+        // assert first != null;
+        // assert next != null;
+        // assert first.item == null;
+        for (Node<E> o = null, p = next, q;;) {
+            if (p.item != null || (q = p.next) == null) {
+                if (o != null && p.prev != p && first.casNext(next, p)) {
+                    skipDeletedPredecessors(p);
+                    if (first.prev == null &&
+                        (p.next == null || p.item != null) &&
+                        p.prev == first) {
+
+                        updateHead(); // Ensure o is not reachable from head
+                        updateTail(); // Ensure o is not reachable from tail
+
+                        // Finally, actually gc-unlink
+                        o.lazySetNext(o);
+                        o.lazySetPrev(prevTerminator());
+                    }
+                }
+                return;
+            }
+            else if (p == q)
+                return;
+            else {
+                o = p;
+                p = q;
+            }
+        }
+    }
+
+    /**
+     * Unlinks non-null last node.
+     */
+    private void unlinkLast(Node<E> last, Node<E> prev) {
+        // assert last != null;
+        // assert prev != null;
+        // assert last.item == null;
+        for (Node<E> o = null, p = prev, q;;) {
+            if (p.item != null || (q = p.prev) == null) {
+                if (o != null && p.next != p && last.casPrev(prev, p)) {
+                    skipDeletedSuccessors(p);
+                    if (last.next == null &&
+                        (p.prev == null || p.item != null) &&
+                        p.next == last) {
+
+                        updateHead(); // Ensure o is not reachable from head
+                        updateTail(); // Ensure o is not reachable from tail
+
+                        // Finally, actually gc-unlink
+                        o.lazySetPrev(o);
+                        o.lazySetNext(nextTerminator());
+                    }
+                }
+                return;
+            }
+            else if (p == q)
+                return;
+            else {
+                o = p;
+                p = q;
+            }
+        }
+    }
+
+    /**
+     * Guarantees that any node which was unlinked before a call to
+     * this method will be unreachable from head after it returns.
+     * Does not guarantee to eliminate slack, only that head will
+     * point to a node that was active while this method was running.
+     */
+    private final void updateHead() {
+        // Either head already points to an active node, or we keep
+        // trying to cas it to the first node until it does.
+        Node<E> h, p, q;
+        restartFromHead:
+        while ((h = head).item == null && (p = h.prev) != null) {
+            for (;;) {
+                if ((q = p.prev) == null ||
+                    (q = (p = q).prev) == null) {
+                    // It is possible that p is PREV_TERMINATOR,
+                    // but if so, the CAS is guaranteed to fail.
+                    if (casHead(h, p))
+                        return;
+                    else
+                        continue restartFromHead;
+                }
+                else if (h != head)
+                    continue restartFromHead;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    /**
+     * Guarantees that any node which was unlinked before a call to
+     * this method will be unreachable from tail after it returns.
+     * Does not guarantee to eliminate slack, only that tail will
+     * point to a node that was active while this method was running.
+     */
+    private final void updateTail() {
+        // Either tail already points to an active node, or we keep
+        // trying to cas it to the last node until it does.
+        Node<E> t, p, q;
+        restartFromTail:
+        while ((t = tail).item == null && (p = t.next) != null) {
+            for (;;) {
+                if ((q = p.next) == null ||
+                    (q = (p = q).next) == null) {
+                    // It is possible that p is NEXT_TERMINATOR,
+                    // but if so, the CAS is guaranteed to fail.
+                    if (casTail(t, p))
+                        return;
+                    else
+                        continue restartFromTail;
+                }
+                else if (t != tail)
+                    continue restartFromTail;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    private void skipDeletedPredecessors(Node<E> x) {
+        whileActive:
+        do {
+            Node<E> prev = x.prev;
+            // assert prev != null;
+            // assert x != NEXT_TERMINATOR;
+            // assert x != PREV_TERMINATOR;
+            Node<E> p = prev;
+            findActive:
+            for (;;) {
+                if (p.item != null)
+                    break findActive;
+                Node<E> q = p.prev;
+                if (q == null) {
+                    if (p.next == p)
+                        continue whileActive;
+                    break findActive;
+                }
+                else if (p == q)
+                    continue whileActive;
+                else
+                    p = q;
+            }
+
+            // found active CAS target
+            if (prev == p || x.casPrev(prev, p))
+                return;
+
+        } while (x.item != null || x.next == null);
+    }
+
+    private void skipDeletedSuccessors(Node<E> x) {
+        whileActive:
+        do {
+            Node<E> next = x.next;
+            // assert next != null;
+            // assert x != NEXT_TERMINATOR;
+            // assert x != PREV_TERMINATOR;
+            Node<E> p = next;
+            findActive:
+            for (;;) {
+                if (p.item != null)
+                    break findActive;
+                Node<E> q = p.next;
+                if (q == null) {
+                    if (p.prev == p)
+                        continue whileActive;
+                    break findActive;
+                }
+                else if (p == q)
+                    continue whileActive;
+                else
+                    p = q;
+            }
+
+            // found active CAS target
+            if (next == p || x.casNext(next, p))
+                return;
+
+        } while (x.item != null || x.prev == null);
+    }
+
+    /**
+     * Returns the successor of p, or the first node if p.next has been
+     * linked to self, which will only be true if traversing with a
+     * stale pointer that is now off the list.
+     */
+    final Node<E> succ(Node<E> p) {
+        // TODO: should we skip deleted nodes here?
+        Node<E> q = p.next;
+        return (p == q) ? first() : q;
+    }
+
+    /**
+     * Returns the predecessor of p, or the last node if p.prev has been
+     * linked to self, which will only be true if traversing with a
+     * stale pointer that is now off the list.
+     */
+    final Node<E> pred(Node<E> p) {
+        Node<E> q = p.prev;
+        return (p == q) ? last() : q;
+    }
+
+    /**
+     * Returns the first node, the unique node p for which:
+     *     p.prev == null && p.next != p
+     * The returned node may or may not be logically deleted.
+     * Guarantees that head is set to the returned node.
+     */
+    Node<E> first() {
+        restartFromHead:
+        for (;;)
+            for (Node<E> h = head, p = h, q;;) {
+                if ((q = p.prev) != null &&
+                    (q = (p = q).prev) != null)
+                    // Check for head updates every other hop.
+                    // If p == q, we are sure to follow head instead.
+                    p = (h != (h = head)) ? h : q;
+                else if (p == h
+                         // It is possible that p is PREV_TERMINATOR,
+                         // but if so, the CAS is guaranteed to fail.
+                         || casHead(h, p))
+                    return p;
+                else
+                    continue restartFromHead;
+            }
+    }
+
+    /**
+     * Returns the last node, the unique node p for which:
+     *     p.next == null && p.prev != p
+     * The returned node may or may not be logically deleted.
+     * Guarantees that tail is set to the returned node.
+     */
+    Node<E> last() {
+        restartFromTail:
+        for (;;)
+            for (Node<E> t = tail, p = t, q;;) {
+                if ((q = p.next) != null &&
+                    (q = (p = q).next) != null)
+                    // Check for tail updates every other hop.
+                    // If p == q, we are sure to follow tail instead.
+                    p = (t != (t = tail)) ? t : q;
+                else if (p == t
+                         // It is possible that p is NEXT_TERMINATOR,
+                         // but if so, the CAS is guaranteed to fail.
+                         || casTail(t, p))
+                    return p;
+                else
+                    continue restartFromTail;
+            }
+    }
+
+    // Minor convenience utilities
+
+    /**
+     * Returns element unless it is null, in which case throws
+     * NoSuchElementException.
+     *
+     * @param v the element
+     * @return the element
+     */
+    private E screenNullResult(E v) {
+        if (v == null)
+            throw new NoSuchElementException();
+        return v;
+    }
+
+    /**
+     * Constructs an empty deque.
+     */
+    public ConcurrentLinkedDeque() {
+        head = tail = new Node<E>(null);
+    }
+
+    /**
+     * Constructs a deque initially containing the elements of
+     * the given collection, added in traversal order of the
+     * collection's iterator.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public ConcurrentLinkedDeque(Collection<? extends E> c) {
+        // Copy c into a private chain of Nodes
+        Node<E> h = null, t = null;
+        for (E e : c) {
+            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            if (h == null)
+                h = t = newNode;
+            else {
+                t.lazySetNext(newNode);
+                newNode.lazySetPrev(t);
+                t = newNode;
+            }
+        }
+        initHeadTail(h, t);
+    }
+
+    /**
+     * Initializes head and tail, ensuring invariants hold.
+     */
+    private void initHeadTail(Node<E> h, Node<E> t) {
+        if (h == t) {
+            if (h == null)
+                h = t = new Node<E>(null);
+            else {
+                // Avoid edge case of a single Node with non-null item.
+                Node<E> newNode = new Node<E>(null);
+                t.lazySetNext(newNode);
+                newNode.lazySetPrev(t);
+                t = newNode;
+            }
+        }
+        head = h;
+        tail = t;
+    }
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     * As the deque is unbounded, this method will never throw
+     * {@link IllegalStateException}.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addFirst(E e) {
+        linkFirst(e);
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     * As the deque is unbounded, this method will never throw
+     * {@link IllegalStateException}.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addLast(E e) {
+        linkLast(e);
+    }
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     * As the deque is unbounded, this method will never return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Deque#offerFirst})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerFirst(E e) {
+        linkFirst(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     * As the deque is unbounded, this method will never return {@code false}.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @return {@code true} (as specified by {@link Deque#offerLast})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerLast(E e) {
+        linkLast(e);
+        return true;
+    }
+
+    public E peekFirst() {
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            E item = p.item;
+            if (item != null)
+                return item;
+        }
+        return null;
+    }
+
+    public E peekLast() {
+        for (Node<E> p = last(); p != null; p = pred(p)) {
+            E item = p.item;
+            if (item != null)
+                return item;
+        }
+        return null;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getFirst() {
+        return screenNullResult(peekFirst());
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getLast() {
+        return screenNullResult(peekLast());
+    }
+
+    public E pollFirst() {
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            E item = p.item;
+            if (item != null && p.casItem(item, null)) {
+                unlink(p);
+                return item;
+            }
+        }
+        return null;
+    }
+
+    public E pollLast() {
+        for (Node<E> p = last(); p != null; p = pred(p)) {
+            E item = p.item;
+            if (item != null && p.casItem(item, null)) {
+                unlink(p);
+                return item;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeFirst() {
+        return screenNullResult(pollFirst());
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeLast() {
+        return screenNullResult(pollLast());
+    }
+
+    // *** Queue and stack methods ***
+
+    /**
+     * Inserts the specified element at the tail of this deque.
+     * As the deque is unbounded, this method will never return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        return offerLast(e);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this deque.
+     * As the deque is unbounded, this method will never throw
+     * {@link IllegalStateException} or return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offerLast(e);
+    }
+
+    public E poll()           { return pollFirst(); }
+    public E peek()           { return peekFirst(); }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E remove()         { return removeFirst(); }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E pop()            { return removeFirst(); }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E element()        { return getFirst(); }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void push(E e)     { addFirst(e); }
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean removeFirstOccurrence(Object o) {
+        Objects.requireNonNull(o);
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            E item = p.item;
+            if (item != null && o.equals(item) && p.casItem(item, null)) {
+                unlink(p);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes the last occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean removeLastOccurrence(Object o) {
+        Objects.requireNonNull(o);
+        for (Node<E> p = last(); p != null; p = pred(p)) {
+            E item = p.item;
+            if (item != null && o.equals(item) && p.casItem(item, null)) {
+                unlink(p);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o element whose presence in this deque is to be tested
+     * @return {@code true} if this deque contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o != null) {
+            for (Node<E> p = first(); p != null; p = succ(p)) {
+                E item = p.item;
+                if (item != null && o.equals(item))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this collection contains no elements.
+     *
+     * @return {@code true} if this collection contains no elements
+     */
+    public boolean isEmpty() {
+        return peekFirst() == null;
+    }
+
+    /**
+     * Returns the number of elements in this deque.  If this deque
+     * contains more than {@code Integer.MAX_VALUE} elements, it
+     * returns {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these deques, determining the current
+     * number of elements requires traversing them all to count them.
+     * Additionally, it is possible for the size to change during
+     * execution of this method, in which case the returned result
+     * will be inaccurate. Thus, this method is typically not very
+     * useful in concurrent applications.
+     *
+     * @return the number of elements in this deque
+     */
+    public int size() {
+        restartFromHead: for (;;) {
+            int count = 0;
+            for (Node<E> p = first(); p != null;) {
+                if (p.item != null)
+                    if (++count == Integer.MAX_VALUE)
+                        break;  // @see Collection.size()
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return count;
+        }
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean remove(Object o) {
+        return removeFirstOccurrence(o);
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this deque, in the order that they are returned by the specified
+     * collection's iterator.  Attempts to {@code addAll} of a deque to
+     * itself result in {@code IllegalArgumentException}.
+     *
+     * @param c the elements to be inserted into this deque
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     * @throws IllegalArgumentException if the collection is this deque
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (c == this)
+            // As historically specified in AbstractQueue#addAll
+            throw new IllegalArgumentException();
+
+        // Copy c into a private chain of Nodes
+        Node<E> beginningOfTheEnd = null, last = null;
+        for (E e : c) {
+            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            if (beginningOfTheEnd == null)
+                beginningOfTheEnd = last = newNode;
+            else {
+                last.lazySetNext(newNode);
+                newNode.lazySetPrev(last);
+                last = newNode;
+            }
+        }
+        if (beginningOfTheEnd == null)
+            return false;
+
+        // Atomically append the chain at the tail of this collection
+        restartFromTail:
+        for (;;)
+            for (Node<E> t = tail, p = t, q;;) {
+                if ((q = p.next) != null &&
+                    (q = (p = q).next) != null)
+                    // Check for tail updates every other hop.
+                    // If p == q, we are sure to follow tail instead.
+                    p = (t != (t = tail)) ? t : q;
+                else if (p.prev == p) // NEXT_TERMINATOR
+                    continue restartFromTail;
+                else {
+                    // p is last node
+                    beginningOfTheEnd.lazySetPrev(p); // CAS piggyback
+                    if (p.casNext(null, beginningOfTheEnd)) {
+                        // Successful CAS is the linearization point
+                        // for all elements to be added to this deque.
+                        if (!casTail(t, last)) {
+                            // Try a little harder to update tail,
+                            // since we may be adding many elements.
+                            t = tail;
+                            if (last.next == null)
+                                casTail(t, last);
+                        }
+                        return true;
+                    }
+                    // Lost CAS race to another thread; re-read next
+                }
+            }
+    }
+
+    /**
+     * Removes all of the elements from this deque.
+     */
+    public void clear() {
+        while (pollFirst() != null)
+            ;
+    }
+
+    public String toString() {
+        String[] a = null;
+        restartFromHead: for (;;) {
+            int charLength = 0;
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                E item = p.item;
+                if (item != null) {
+                    if (a == null)
+                        a = new String[4];
+                    else if (size == a.length)
+                        a = Arrays.copyOf(a, 2 * size);
+                    String s = item.toString();
+                    a[size++] = s;
+                    charLength += s.length();
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+
+            if (size == 0)
+                return "[]";
+
+            return Helpers.toString(a, size, charLength);
+        }
+    }
+
+    private Object[] toArrayInternal(Object[] a) {
+        Object[] x = a;
+        restartFromHead: for (;;) {
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                E item = p.item;
+                if (item != null) {
+                    if (x == null)
+                        x = new Object[4];
+                    else if (size == x.length)
+                        x = Arrays.copyOf(x, 2 * (size + 4));
+                    x[size++] = item;
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            if (x == null)
+                return new Object[0];
+            else if (a != null && size <= a.length) {
+                if (a != x)
+                    System.arraycopy(x, 0, a, 0, size);
+                if (size < a.length)
+                    a[size] = null;
+                return a;
+            }
+            return (size == x.length) ? x : Arrays.copyOf(x, size);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque, in
+     * proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this deque.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this deque
+     */
+    public Object[] toArray() {
+        return toArrayInternal(null);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque,
+     * in proper sequence (from first to last element); the runtime
+     * type of the returned array is that of the specified array.  If
+     * the deque fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of
+     * the specified array and the size of this deque.
+     *
+     * <p>If this deque fits in the specified array with room to spare
+     * (i.e., the array has more elements than this deque), the element in
+     * the array immediately following the end of the deque is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as
+     * bridge between array-based and collection-based APIs.  Further,
+     * this method allows precise control over the runtime type of the
+     * output array, and may, under certain circumstances, be used to
+     * save allocation costs.
+     *
+     * <p>Suppose {@code x} is a deque known to contain only strings.
+     * The following code can be used to dump the deque into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the deque are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this deque
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this deque
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a == null) throw new NullPointerException();
+        return (T[]) toArrayInternal(a);
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in reverse
+     * sequential order.  The elements will be returned in order from
+     * last (tail) to first (head).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in reverse order
+     */
+    public Iterator<E> descendingIterator() {
+        return new DescendingItr();
+    }
+
+    private abstract class AbstractItr implements Iterator<E> {
+        /**
+         * Next node to return item for.
+         */
+        private Node<E> nextNode;
+
+        /**
+         * nextItem holds on to item fields because once we claim
+         * that an element exists in hasNext(), we must return it in
+         * the following next() call even if it was in the process of
+         * being removed when hasNext() was called.
+         */
+        private E nextItem;
+
+        /**
+         * Node returned by most recent call to next. Needed by remove.
+         * Reset to null if this element is deleted by a call to remove.
+         */
+        private Node<E> lastRet;
+
+        abstract Node<E> startNode();
+        abstract Node<E> nextNode(Node<E> p);
+
+        AbstractItr() {
+            advance();
+        }
+
+        /**
+         * Sets nextNode and nextItem to next valid node, or to null
+         * if no such.
+         */
+        private void advance() {
+            lastRet = nextNode;
+
+            Node<E> p = (nextNode == null) ? startNode() : nextNode(nextNode);
+            for (;; p = nextNode(p)) {
+                if (p == null) {
+                    // might be at active end or TERMINATOR node; both are OK
+                    nextNode = null;
+                    nextItem = null;
+                    break;
+                }
+                E item = p.item;
+                if (item != null) {
+                    nextNode = p;
+                    nextItem = item;
+                    break;
+                }
+            }
+        }
+
+        public boolean hasNext() {
+            return nextItem != null;
+        }
+
+        public E next() {
+            E item = nextItem;
+            if (item == null) throw new NoSuchElementException();
+            advance();
+            return item;
+        }
+
+        public void remove() {
+            Node<E> l = lastRet;
+            if (l == null) throw new IllegalStateException();
+            l.item = null;
+            unlink(l);
+            lastRet = null;
+        }
+    }
+
+    /** Forward iterator */
+    private class Itr extends AbstractItr {
+        Node<E> startNode() { return first(); }
+        Node<E> nextNode(Node<E> p) { return succ(p); }
+    }
+
+    /** Descending iterator */
+    private class DescendingItr extends AbstractItr {
+        Node<E> startNode() { return last(); }
+        Node<E> nextNode(Node<E> p) { return pred(p); }
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class CLDSpliterator<E> implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final ConcurrentLinkedDeque<E> queue;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        CLDSpliterator(ConcurrentLinkedDeque<E> queue) {
+            this.queue = queue;
+        }
+
+        public Spliterator<E> trySplit() {
+            Node<E> p;
+            final ConcurrentLinkedDeque<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
+                if (p.item == null && p == (p = p.next))
+                    current = p = q.first();
+                if (p != null && p.next != null) {
+                    Object[] a = new Object[n];
+                    int i = 0;
+                    do {
+                        if ((a[i] = p.item) != null)
+                            ++i;
+                        if (p == (p = p.next))
+                            p = q.first();
+                    } while (p != null && i < n);
+                    if ((current = p) == null)
+                        exhausted = true;
+                    if (i > 0) {
+                        batch = i;
+                        return Spliterators.spliterator
+                            (a, 0, i, (Spliterator.ORDERED |
+                                       Spliterator.NONNULL |
+                                       Spliterator.CONCURRENT));
+                    }
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedDeque<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
+                exhausted = true;
+                do {
+                    E e = p.item;
+                    if (p == (p = p.next))
+                        p = q.first();
+                    if (e != null)
+                        action.accept(e);
+                } while (p != null);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedDeque<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
+                E e;
+                do {
+                    e = p.item;
+                    if (p == (p = p.next))
+                        p = q.first();
+                } while (e == null && p != null);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public long estimateSize() { return Long.MAX_VALUE; }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this deque.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new CLDSpliterator<E>(this);
+    }
+
+    /**
+     * Saves this deque to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData All of the elements (each an {@code E}) in
+     * the proper order, followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        // Write out any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out all elements in the proper order.
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            E item = p.item;
+            if (item != null)
+                s.writeObject(item);
+        }
+
+        // Use trailing null as sentinel
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this deque from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+
+        // Read in elements until trailing null sentinel found
+        Node<E> h = null, t = null;
+        for (Object item; (item = s.readObject()) != null; ) {
+            @SuppressWarnings("unchecked")
+            Node<E> newNode = new Node<E>((E) item);
+            if (h == null)
+                h = t = newNode;
+            else {
+                t.lazySetNext(newNode);
+                newNode.lazySetPrev(t);
+                t = newNode;
+            }
+        }
+        initHeadTail(h, t);
+    }
+
+    private boolean casHead(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
+    }
+
+    private boolean casTail(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, TAIL, cmp, val);
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
+    private static final long TAIL;
+    static {
+        PREV_TERMINATOR = new Node<Object>();
+        PREV_TERMINATOR.next = PREV_TERMINATOR;
+        NEXT_TERMINATOR = new Node<Object>();
+        NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
+        try {
+            HEAD = U.objectFieldOffset
+                (ConcurrentLinkedDeque.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (ConcurrentLinkedDeque.class.getDeclaredField("tail"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/ConcurrentLinkedQueue.java b/java/util/concurrent/ConcurrentLinkedQueue.java
new file mode 100644
index 0000000..7997c60
--- /dev/null
+++ b/java/util/concurrent/ConcurrentLinkedQueue.java
@@ -0,0 +1,951 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from members of
+ * JCP JSR-166 Expert Group and released to the public domain, as explained
+ * at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An unbounded thread-safe {@linkplain Queue queue} based on linked nodes.
+ * This queue orders elements FIFO (first-in-first-out).
+ * The <em>head</em> of the queue is that element that has been on the
+ * queue the longest time.
+ * The <em>tail</em> of the queue is that element that has been on the
+ * queue the shortest time. New elements
+ * are inserted at the tail of the queue, and the queue retrieval
+ * operations obtain elements at the head of the queue.
+ * A {@code ConcurrentLinkedQueue} is an appropriate choice when
+ * many threads will share access to a common collection.
+ * Like most other concurrent collection implementations, this class
+ * does not permit the use of {@code null} elements.
+ *
+ * <p>This implementation employs an efficient <em>non-blocking</em>
+ * algorithm based on one described in
+ * <a href="http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf">
+ * Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue
+ * Algorithms</a> by Maged M. Michael and Michael L. Scott.
+ *
+ * <p>Iterators are <i>weakly consistent</i>, returning elements
+ * reflecting the state of the queue at some point at or since the
+ * creation of the iterator.  They do <em>not</em> throw {@link
+ * java.util.ConcurrentModificationException}, and may proceed concurrently
+ * with other operations.  Elements contained in the queue since the creation
+ * of the iterator will be returned exactly once.
+ *
+ * <p>Beware that, unlike in most collections, the {@code size} method
+ * is <em>NOT</em> a constant-time operation. Because of the
+ * asynchronous nature of these queues, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Queue} and {@link Iterator} interfaces.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code ConcurrentLinkedQueue}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code ConcurrentLinkedQueue} in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
+        implements Queue<E>, java.io.Serializable {
+    private static final long serialVersionUID = 196745693267521676L;
+
+    /*
+     * This is a modification of the Michael & Scott algorithm,
+     * adapted for a garbage-collected environment, with support for
+     * interior node deletion (to support remove(Object)).  For
+     * explanation, read the paper.
+     *
+     * Note that like most non-blocking algorithms in this package,
+     * this implementation relies on the fact that in garbage
+     * collected systems, there is no possibility of ABA problems due
+     * to recycled nodes, so there is no need to use "counted
+     * pointers" or related techniques seen in versions used in
+     * non-GC'ed settings.
+     *
+     * The fundamental invariants are:
+     * - There is exactly one (last) Node with a null next reference,
+     *   which is CASed when enqueueing.  This last Node can be
+     *   reached in O(1) time from tail, but tail is merely an
+     *   optimization - it can always be reached in O(N) time from
+     *   head as well.
+     * - The elements contained in the queue are the non-null items in
+     *   Nodes that are reachable from head.  CASing the item
+     *   reference of a Node to null atomically removes it from the
+     *   queue.  Reachability of all elements from head must remain
+     *   true even in the case of concurrent modifications that cause
+     *   head to advance.  A dequeued Node may remain in use
+     *   indefinitely due to creation of an Iterator or simply a
+     *   poll() that has lost its time slice.
+     *
+     * The above might appear to imply that all Nodes are GC-reachable
+     * from a predecessor dequeued Node.  That would cause two problems:
+     * - allow a rogue Iterator to cause unbounded memory retention
+     * - cause cross-generational linking of old Nodes to new Nodes if
+     *   a Node was tenured while live, which generational GCs have a
+     *   hard time dealing with, causing repeated major collections.
+     * However, only non-deleted Nodes need to be reachable from
+     * dequeued Nodes, and reachability does not necessarily have to
+     * be of the kind understood by the GC.  We use the trick of
+     * linking a Node that has just been dequeued to itself.  Such a
+     * self-link implicitly means to advance to head.
+     *
+     * Both head and tail are permitted to lag.  In fact, failing to
+     * update them every time one could is a significant optimization
+     * (fewer CASes). As with LinkedTransferQueue (see the internal
+     * documentation for that class), we use a slack threshold of two;
+     * that is, we update head/tail when the current pointer appears
+     * to be two or more steps away from the first/last node.
+     *
+     * Since head and tail are updated concurrently and independently,
+     * it is possible for tail to lag behind head (why not)?
+     *
+     * CASing a Node's item reference to null atomically removes the
+     * element from the queue.  Iterators skip over Nodes with null
+     * items.  Prior implementations of this class had a race between
+     * poll() and remove(Object) where the same element would appear
+     * to be successfully removed by two concurrent operations.  The
+     * method remove(Object) also lazily unlinks deleted Nodes, but
+     * this is merely an optimization.
+     *
+     * When constructing a Node (before enqueuing it) we avoid paying
+     * for a volatile write to item by using Unsafe.putObject instead
+     * of a normal write.  This allows the cost of enqueue to be
+     * "one-and-a-half" CASes.
+     *
+     * Both head and tail may or may not point to a Node with a
+     * non-null item.  If the queue is empty, all items must of course
+     * be null.  Upon creation, both head and tail refer to a dummy
+     * Node with null item.  Both head and tail are only updated using
+     * CAS, so they never regress, although again this is merely an
+     * optimization.
+     */
+
+    private static class Node<E> {
+        volatile E item;
+        volatile Node<E> next;
+    }
+
+    /**
+     * Returns a new node holding item.  Uses relaxed write because item
+     * can only be seen after piggy-backing publication via casNext.
+     */
+    static <E> Node<E> newNode(E item) {
+        Node<E> node = new Node<E>();
+        U.putObject(node, ITEM, item);
+        return node;
+    }
+
+    static <E> boolean casItem(Node<E> node, E cmp, E val) {
+        return U.compareAndSwapObject(node, ITEM, cmp, val);
+    }
+
+    static <E> void lazySetNext(Node<E> node, Node<E> val) {
+        U.putOrderedObject(node, NEXT, val);
+    }
+
+    static <E> boolean casNext(Node<E> node, Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(node, NEXT, cmp, val);
+    }
+
+    /**
+     * A node from which the first live (non-deleted) node (if any)
+     * can be reached in O(1) time.
+     * Invariants:
+     * - all live nodes are reachable from head via succ()
+     * - head != null
+     * - (tmp = head).next != tmp || tmp != head
+     * Non-invariants:
+     * - head.item may or may not be null.
+     * - it is permitted for tail to lag behind head, that is, for tail
+     *   to not be reachable from head!
+     */
+    transient volatile Node<E> head;
+
+    /**
+     * A node from which the last node on list (that is, the unique
+     * node with node.next == null) can be reached in O(1) time.
+     * Invariants:
+     * - the last node is always reachable from tail via succ()
+     * - tail != null
+     * Non-invariants:
+     * - tail.item may or may not be null.
+     * - it is permitted for tail to lag behind head, that is, for tail
+     *   to not be reachable from head!
+     * - tail.next may or may not be self-pointing to tail.
+     */
+    private transient volatile Node<E> tail;
+
+    /**
+     * Creates a {@code ConcurrentLinkedQueue} that is initially empty.
+     */
+    public ConcurrentLinkedQueue() {
+        head = tail = newNode(null);
+    }
+
+    /**
+     * Creates a {@code ConcurrentLinkedQueue}
+     * initially containing the elements of the given collection,
+     * added in traversal order of the collection's iterator.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public ConcurrentLinkedQueue(Collection<? extends E> c) {
+        Node<E> h = null, t = null;
+        for (E e : c) {
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
+            if (h == null)
+                h = t = newNode;
+            else {
+                lazySetNext(t, newNode);
+                t = newNode;
+            }
+        }
+        if (h == null)
+            h = t = newNode(null);
+        head = h;
+        tail = t;
+    }
+
+    // Have to override just to update the javadoc
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never throw
+     * {@link IllegalStateException} or return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * Tries to CAS head to p. If successful, repoint old head to itself
+     * as sentinel for succ(), below.
+     */
+    final void updateHead(Node<E> h, Node<E> p) {
+        // assert h != null && p != null && (h == p || h.item == null);
+        if (h != p && casHead(h, p))
+            lazySetNext(h, h);
+    }
+
+    /**
+     * Returns the successor of p, or the head node if p.next has been
+     * linked to self, which will only be true if traversing with a
+     * stale pointer that is now off the list.
+     */
+    final Node<E> succ(Node<E> p) {
+        Node<E> next = p.next;
+        return (p == next) ? head : next;
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        final Node<E> newNode = newNode(Objects.requireNonNull(e));
+
+        for (Node<E> t = tail, p = t;;) {
+            Node<E> q = p.next;
+            if (q == null) {
+                // p is last node
+                if (casNext(p, null, newNode)) {
+                    // Successful CAS is the linearization point
+                    // for e to become an element of this queue,
+                    // and for newNode to become "live".
+                    if (p != t) // hop two nodes at a time
+                        casTail(t, newNode);  // Failure is OK.
+                    return true;
+                }
+                // Lost CAS race to another thread; re-read next
+            }
+            else if (p == q)
+                // We have fallen off list.  If tail is unchanged, it
+                // will also be off-list, in which case we need to
+                // jump to head, from which all live nodes are always
+                // reachable.  Else the new tail is a better bet.
+                p = (t != (t = tail)) ? t : head;
+            else
+                // Check for tail updates after two hops.
+                p = (p != t && t != (t = tail)) ? t : q;
+        }
+    }
+
+    public E poll() {
+        restartFromHead:
+        for (;;) {
+            for (Node<E> h = head, p = h, q;;) {
+                E item = p.item;
+
+                if (item != null && casItem(p, item, null)) {
+                    // Successful CAS is the linearization point
+                    // for item to be removed from this queue.
+                    if (p != h) // hop two nodes at a time
+                        updateHead(h, ((q = p.next) != null) ? q : p);
+                    return item;
+                }
+                else if ((q = p.next) == null) {
+                    updateHead(h, p);
+                    return null;
+                }
+                else if (p == q)
+                    continue restartFromHead;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    public E peek() {
+        restartFromHead:
+        for (;;) {
+            for (Node<E> h = head, p = h, q;;) {
+                E item = p.item;
+                if (item != null || (q = p.next) == null) {
+                    updateHead(h, p);
+                    return item;
+                }
+                else if (p == q)
+                    continue restartFromHead;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    /**
+     * Returns the first live (non-deleted) node on list, or null if none.
+     * This is yet another variant of poll/peek; here returning the
+     * first node, not element.  We could make peek() a wrapper around
+     * first(), but that would cost an extra volatile read of item,
+     * and the need to add a retry loop to deal with the possibility
+     * of losing a race to a concurrent poll().
+     */
+    Node<E> first() {
+        restartFromHead:
+        for (;;) {
+            for (Node<E> h = head, p = h, q;;) {
+                boolean hasItem = (p.item != null);
+                if (hasItem || (q = p.next) == null) {
+                    updateHead(h, p);
+                    return hasItem ? p : null;
+                }
+                else if (p == q)
+                    continue restartFromHead;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains no elements.
+     *
+     * @return {@code true} if this queue contains no elements
+     */
+    public boolean isEmpty() {
+        return first() == null;
+    }
+
+    /**
+     * Returns the number of elements in this queue.  If this queue
+     * contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these queues, determining the current
+     * number of elements requires an O(n) traversal.
+     * Additionally, if elements are added or removed during execution
+     * of this method, the returned result may be inaccurate.  Thus,
+     * this method is typically not very useful in concurrent
+     * applications.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        restartFromHead: for (;;) {
+            int count = 0;
+            for (Node<E> p = first(); p != null;) {
+                if (p.item != null)
+                    if (++count == Integer.MAX_VALUE)
+                        break;  // @see Collection.size()
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return count;
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o != null) {
+            for (Node<E> p = first(); p != null; p = succ(p)) {
+                E item = p.item;
+                if (item != null && o.equals(item))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.
+     * Returns {@code true} if this queue contained the specified element
+     * (or equivalently, if this queue changed as a result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        if (o != null) {
+            Node<E> next, pred = null;
+            for (Node<E> p = first(); p != null; pred = p, p = next) {
+                boolean removed = false;
+                E item = p.item;
+                if (item != null) {
+                    if (!o.equals(item)) {
+                        next = succ(p);
+                        continue;
+                    }
+                    removed = casItem(p, item, null);
+                }
+
+                next = succ(p);
+                if (pred != null && next != null) // unlink
+                    casNext(pred, p, next);
+                if (removed)
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this queue, in the order that they are returned by the specified
+     * collection's iterator.  Attempts to {@code addAll} of a queue to
+     * itself result in {@code IllegalArgumentException}.
+     *
+     * @param c the elements to be inserted into this queue
+     * @return {@code true} if this queue changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     * @throws IllegalArgumentException if the collection is this queue
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (c == this)
+            // As historically specified in AbstractQueue#addAll
+            throw new IllegalArgumentException();
+
+        // Copy c into a private chain of Nodes
+        Node<E> beginningOfTheEnd = null, last = null;
+        for (E e : c) {
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
+            if (beginningOfTheEnd == null)
+                beginningOfTheEnd = last = newNode;
+            else {
+                lazySetNext(last, newNode);
+                last = newNode;
+            }
+        }
+        if (beginningOfTheEnd == null)
+            return false;
+
+        // Atomically append the chain at the tail of this collection
+        for (Node<E> t = tail, p = t;;) {
+            Node<E> q = p.next;
+            if (q == null) {
+                // p is last node
+                if (casNext(p, null, beginningOfTheEnd)) {
+                    // Successful CAS is the linearization point
+                    // for all elements to be added to this queue.
+                    if (!casTail(t, last)) {
+                        // Try a little harder to update tail,
+                        // since we may be adding many elements.
+                        t = tail;
+                        if (last.next == null)
+                            casTail(t, last);
+                    }
+                    return true;
+                }
+                // Lost CAS race to another thread; re-read next
+            }
+            else if (p == q)
+                // We have fallen off list.  If tail is unchanged, it
+                // will also be off-list, in which case we need to
+                // jump to head, from which all live nodes are always
+                // reachable.  Else the new tail is a better bet.
+                p = (t != (t = tail)) ? t : head;
+            else
+                // Check for tail updates after two hops.
+                p = (p != t && t != (t = tail)) ? t : q;
+        }
+    }
+
+    public String toString() {
+        String[] a = null;
+        restartFromHead: for (;;) {
+            int charLength = 0;
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                E item = p.item;
+                if (item != null) {
+                    if (a == null)
+                        a = new String[4];
+                    else if (size == a.length)
+                        a = Arrays.copyOf(a, 2 * size);
+                    String s = item.toString();
+                    a[size++] = s;
+                    charLength += s.length();
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+
+            if (size == 0)
+                return "[]";
+
+            return Helpers.toString(a, size, charLength);
+        }
+    }
+
+    private Object[] toArrayInternal(Object[] a) {
+        Object[] x = a;
+        restartFromHead: for (;;) {
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                E item = p.item;
+                if (item != null) {
+                    if (x == null)
+                        x = new Object[4];
+                    else if (size == x.length)
+                        x = Arrays.copyOf(x, 2 * (size + 4));
+                    x[size++] = item;
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            if (x == null)
+                return new Object[0];
+            else if (a != null && size <= a.length) {
+                if (a != x)
+                    System.arraycopy(x, 0, a, 0, size);
+                if (size < a.length)
+                    a[size] = null;
+                return a;
+            }
+            return (size == x.length) ? x : Arrays.copyOf(x, size);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        return toArrayInternal(null);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a == null) throw new NullPointerException();
+        return (T[]) toArrayInternal(a);
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    private class Itr implements Iterator<E> {
+        /**
+         * Next node to return item for.
+         */
+        private Node<E> nextNode;
+
+        /**
+         * nextItem holds on to item fields because once we claim
+         * that an element exists in hasNext(), we must return it in
+         * the following next() call even if it was in the process of
+         * being removed when hasNext() was called.
+         */
+        private E nextItem;
+
+        /**
+         * Node of the last returned item, to support remove.
+         */
+        private Node<E> lastRet;
+
+        Itr() {
+            restartFromHead: for (;;) {
+                Node<E> h, p, q;
+                for (p = h = head;; p = q) {
+                    E item;
+                    if ((item = p.item) != null) {
+                        nextNode = p;
+                        nextItem = item;
+                        break;
+                    }
+                    else if ((q = p.next) == null)
+                        break;
+                    else if (p == q)
+                        continue restartFromHead;
+                }
+                updateHead(h, p);
+                return;
+            }
+        }
+
+        public boolean hasNext() {
+            return nextItem != null;
+        }
+
+        public E next() {
+            final Node<E> pred = nextNode;
+            if (pred == null) throw new NoSuchElementException();
+            // assert nextItem != null;
+            lastRet = pred;
+            E item = null;
+
+            for (Node<E> p = succ(pred), q;; p = q) {
+                if (p == null || (item = p.item) != null) {
+                    nextNode = p;
+                    E x = nextItem;
+                    nextItem = item;
+                    return x;
+                }
+                // unlink deleted nodes
+                if ((q = succ(p)) != null)
+                    casNext(pred, p, q);
+            }
+        }
+
+        public void remove() {
+            Node<E> l = lastRet;
+            if (l == null) throw new IllegalStateException();
+            // rely on a future traversal to relink.
+            l.item = null;
+            lastRet = null;
+        }
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData All of the elements (each an {@code E}) in
+     * the proper order, followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        // Write out any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out all elements in the proper order.
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            Object item = p.item;
+            if (item != null)
+                s.writeObject(item);
+        }
+
+        // Use trailing null as sentinel
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+
+        // Read in elements until trailing null sentinel found
+        Node<E> h = null, t = null;
+        for (Object item; (item = s.readObject()) != null; ) {
+            @SuppressWarnings("unchecked")
+            Node<E> newNode = newNode((E) item);
+            if (h == null)
+                h = t = newNode;
+            else {
+                lazySetNext(t, newNode);
+                t = newNode;
+            }
+        }
+        if (h == null)
+            h = t = newNode(null);
+        head = h;
+        tail = t;
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class CLQSpliterator<E> implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final ConcurrentLinkedQueue<E> queue;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        CLQSpliterator(ConcurrentLinkedQueue<E> queue) {
+            this.queue = queue;
+        }
+
+        public Spliterator<E> trySplit() {
+            Node<E> p;
+            final ConcurrentLinkedQueue<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null) &&
+                p.next != null) {
+                Object[] a = new Object[n];
+                int i = 0;
+                do {
+                    if ((a[i] = p.item) != null)
+                        ++i;
+                    if (p == (p = p.next))
+                        p = q.first();
+                } while (p != null && i < n);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (i > 0) {
+                    batch = i;
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedQueue<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
+                exhausted = true;
+                do {
+                    E e = p.item;
+                    if (p == (p = p.next))
+                        p = q.first();
+                    if (e != null)
+                        action.accept(e);
+                } while (p != null);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedQueue<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
+                E e;
+                do {
+                    e = p.item;
+                    if (p == (p = p.next))
+                        p = q.first();
+                } while (e == null && p != null);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public long estimateSize() { return Long.MAX_VALUE; }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new CLQSpliterator<E>(this);
+    }
+
+    private boolean casTail(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, TAIL, cmp, val);
+    }
+
+    private boolean casHead(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
+    private static final long TAIL;
+    private static final long ITEM;
+    private static final long NEXT;
+    static {
+        try {
+            HEAD = U.objectFieldOffset
+                (ConcurrentLinkedQueue.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (ConcurrentLinkedQueue.class.getDeclaredField("tail"));
+            ITEM = U.objectFieldOffset
+                (Node.class.getDeclaredField("item"));
+            NEXT = U.objectFieldOffset
+                (Node.class.getDeclaredField("next"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/ConcurrentMap.java b/java/util/concurrent/ConcurrentMap.java
new file mode 100644
index 0000000..69dae6f
--- /dev/null
+++ b/java/util/concurrent/ConcurrentMap.java
@@ -0,0 +1,502 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
+/**
+ * A {@link java.util.Map} providing thread safety and atomicity
+ * guarantees.
+ *
+ * <p>To maintain the specified guarantees, default implementations of
+ * methods including {@link #putIfAbsent} inherited from {@link Map}
+ * must be overridden by implementations of this interface. Similarly,
+ * implementations of the collections returned by methods {@link
+ * #keySet}, {@link #values}, and {@link #entrySet} must override
+ * methods such as {@code removeIf} when necessary to
+ * preserve atomicity guarantees.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code ConcurrentMap} as a key or value
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that object from
+ * the {@code ConcurrentMap} in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ */
+public interface ConcurrentMap<K,V> extends Map<K,V> {
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote This implementation assumes that the ConcurrentMap cannot
+     * contain null values and {@code get()} returning null unambiguously means
+     * the key is absent. Implementations which support null values
+     * <strong>must</strong> override this default implementation.
+     *
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return ((v = get(key)) != null) ? v : defaultValue;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec The default implementation is equivalent to, for this
+     * {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K,V> entry : map.entrySet()) {
+     *   action.accept(entry.getKey(), entry.getValue());
+     * }}</pre>
+     *
+     * @implNote The default implementation assumes that
+     * {@code IllegalStateException} thrown by {@code getKey()} or
+     * {@code getValue()} indicates that the entry has been removed and cannot
+     * be processed. Operation continues for subsequent entries.
+     *
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        for (Map.Entry<K,V> entry : entrySet()) {
+            K k;
+            V v;
+            try {
+                k = entry.getKey();
+                v = entry.getValue();
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                continue;
+            }
+            action.accept(k, v);
+        }
+    }
+
+    /**
+     * If the specified key is not already associated
+     * with a value, associates it with the given value.
+     * This is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * if (!map.containsKey(key))
+     *   return map.put(key, value);
+     * else
+     *   return map.get(key);}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     */
+    V putIfAbsent(K key, V value);
+
+    /**
+     * Removes the entry for a key only if currently mapped to a given value.
+     * This is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * if (map.containsKey(key)
+     *     && Objects.equals(map.get(key), value)) {
+     *   map.remove(key);
+     *   return true;
+     * } else {
+     *   return false;
+     * }}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value expected to be associated with the specified key
+     * @return {@code true} if the value was removed
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the key or value is of an inappropriate
+     *         type for this map
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean remove(Object key, Object value);
+
+    /**
+     * Replaces the entry for a key only if currently mapped to a given value.
+     * This is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * if (map.containsKey(key)
+     *     && Objects.equals(map.get(key), oldValue)) {
+     *   map.put(key, newValue);
+     *   return true;
+     * } else {
+     *   return false;
+     * }}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is associated
+     * @param oldValue value expected to be associated with the specified key
+     * @param newValue value to be associated with the specified key
+     * @return {@code true} if the value was replaced
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of a specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if a specified key or value is null,
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of a specified key
+     *         or value prevents it from being stored in this map
+     */
+    boolean replace(K key, V oldValue, V newValue);
+
+    /**
+     * Replaces the entry for a key only if currently mapped to some value.
+     * This is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * if (map.containsKey(key))
+     *   return map.put(key, value);
+     * else
+     *   return null;}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     */
+    V replace(K key, V value);
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * <p>The default implementation is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K,V> entry : map.entrySet()) {
+     *   K k;
+     *   V v;
+     *   do {
+     *     k = entry.getKey();
+     *     v = entry.getValue();
+     *   } while (!map.replace(k, v, function.apply(k, v)));
+     * }}</pre>
+     *
+     * The default implementation may retry these steps when multiple
+     * threads attempt updates including potentially calling the function
+     * repeatedly for a given key.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        forEach((k,v) -> {
+            while (!replace(k, v, function.apply(k, v))) {
+                // v changed or k is gone
+                if ( (v = get(k)) == null) {
+                    // k is no longer in the map.
+                    break;
+                }
+            }
+        });
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to the following steps for this
+     * {@code map}:
+     *
+     * <pre> {@code
+     * V oldValue, newValue;
+     * return ((oldValue = map.get(key)) == null
+     *         && (newValue = mappingFunction.apply(key)) != null
+     *         && (oldValue = map.putIfAbsent(key, newValue)) == null)
+     *   ? newValue
+     *   : oldValue;}</pre>
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V computeIfAbsent(K key,
+            Function<? super K, ? extends V> mappingFunction) {
+        Objects.requireNonNull(mappingFunction);
+        V oldValue, newValue;
+        return ((oldValue = get(key)) == null
+                && (newValue = mappingFunction.apply(key)) != null
+                && (oldValue = putIfAbsent(key, newValue)) == null)
+            ? newValue
+            : oldValue;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}:
+     *
+     * <pre> {@code
+     * for (V oldValue; (oldValue = map.get(key)) != null; ) {
+     *   V newValue = remappingFunction.apply(key, oldValue);
+     *   if ((newValue == null)
+     *       ? map.remove(key, oldValue)
+     *       : map.replace(key, oldValue, newValue))
+     *     return newValue;
+     * }
+     * return null;}</pre>
+     * When multiple threads attempt updates, map operations and the
+     * remapping function may be called multiple times.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V computeIfPresent(K key,
+            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        for (V oldValue; (oldValue = get(key)) != null; ) {
+            V newValue = remappingFunction.apply(key, oldValue);
+            if ((newValue == null)
+                ? remove(key, oldValue)
+                : replace(key, oldValue, newValue))
+                return newValue;
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}:
+     *
+     * <pre> {@code
+     * for (;;) {
+     *   V oldValue = map.get(key);
+     *   V newValue = remappingFunction.apply(key, oldValue);
+     *   if (newValue != null) {
+     *     if ((oldValue != null)
+     *       ? map.replace(key, oldValue, newValue)
+     *       : map.putIfAbsent(key, newValue) == null)
+     *       return newValue;
+     *   } else if (oldValue == null || map.remove(key, oldValue)) {
+     *     return null;
+     *   }
+     * }}</pre>
+     * When multiple threads attempt updates, map operations and the
+     * remapping function may be called multiple times.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V compute(K key,
+                      BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        retry: for (;;) {
+            V oldValue = get(key);
+            // if putIfAbsent fails, opportunistically use its return value
+            haveOldValue: for (;;) {
+                V newValue = remappingFunction.apply(key, oldValue);
+                if (newValue != null) {
+                    if (oldValue != null) {
+                        if (replace(key, oldValue, newValue))
+                            return newValue;
+                    }
+                    else if ((oldValue = putIfAbsent(key, newValue)) == null)
+                        return newValue;
+                    else continue haveOldValue;
+                } else if (oldValue == null || remove(key, oldValue)) {
+                    return null;
+                }
+                continue retry;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}:
+     *
+     * <pre> {@code
+     * for (;;) {
+     *   V oldValue = map.get(key);
+     *   if (oldValue != null) {
+     *     V newValue = remappingFunction.apply(oldValue, value);
+     *     if (newValue != null) {
+     *       if (map.replace(key, oldValue, newValue))
+     *         return newValue;
+     *     } else if (map.remove(key, oldValue)) {
+     *       return null;
+     *     }
+     *   } else if (map.putIfAbsent(key, value) == null) {
+     *     return value;
+     *   }
+     * }}</pre>
+     * When multiple threads attempt updates, map operations and the
+     * remapping function may be called multiple times.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V merge(K key, V value,
+            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        Objects.requireNonNull(value);
+        retry: for (;;) {
+            V oldValue = get(key);
+            // if putIfAbsent fails, opportunistically use its return value
+            haveOldValue: for (;;) {
+                if (oldValue != null) {
+                    V newValue = remappingFunction.apply(oldValue, value);
+                    if (newValue != null) {
+                        if (replace(key, oldValue, newValue))
+                            return newValue;
+                    } else if (remove(key, oldValue)) {
+                        return null;
+                    }
+                    continue retry;
+                } else {
+                    if ((oldValue = putIfAbsent(key, value)) == null)
+                        return value;
+                    continue haveOldValue;
+                }
+            }
+        }
+    }
+}
diff --git a/java/util/concurrent/ConcurrentNavigableMap.java b/java/util/concurrent/ConcurrentNavigableMap.java
new file mode 100644
index 0000000..94a90cd
--- /dev/null
+++ b/java/util/concurrent/ConcurrentNavigableMap.java
@@ -0,0 +1,169 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A {@link ConcurrentMap} supporting {@link NavigableMap} operations,
+ * and recursively so for its navigable sub-maps.
+ *
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 1.6
+ */
+public interface ConcurrentNavigableMap<K,V>
+    extends ConcurrentMap<K,V>, NavigableMap<K,V>
+{
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                       K toKey,   boolean toInclusive);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> headMap(K toKey, boolean inclusive);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> headMap(K toKey);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> tailMap(K fromKey);
+
+    /**
+     * Returns a reverse order view of the mappings contained in this map.
+     * The descending map is backed by this map, so changes to the map are
+     * reflected in the descending map, and vice-versa.
+     *
+     * <p>The returned map has an ordering equivalent to
+     * {@link java.util.Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code m.descendingMap().descendingMap()} returns a
+     * view of {@code m} essentially equivalent to {@code m}.
+     *
+     * @return a reverse order view of this map
+     */
+    ConcurrentNavigableMap<K,V> descendingMap();
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    NavigableSet<K> navigableKeySet();
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>This method is equivalent to method {@code navigableKeySet}.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    NavigableSet<K> keySet();
+
+    /**
+     * Returns a reverse order {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in descending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return a reverse order navigable set view of the keys in this map
+     */
+    NavigableSet<K> descendingKeySet();
+}
diff --git a/java/util/concurrent/ConcurrentSkipListMap.java b/java/util/concurrent/ConcurrentSkipListMap.java
new file mode 100644
index 0000000..583244b
--- /dev/null
+++ b/java/util/concurrent/ConcurrentSkipListMap.java
@@ -0,0 +1,3609 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.Spliterator;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A scalable concurrent {@link ConcurrentNavigableMap} implementation.
+ * The map is sorted according to the {@linkplain Comparable natural
+ * ordering} of its keys, or by a {@link Comparator} provided at map
+ * creation time, depending on which constructor is used.
+ *
+ * <p>This class implements a concurrent variant of <a
+ * href="http://en.wikipedia.org/wiki/Skip_list" target="_top">SkipLists</a>
+ * providing expected average <i>log(n)</i> time cost for the
+ * {@code containsKey}, {@code get}, {@code put} and
+ * {@code remove} operations and their variants.  Insertion, removal,
+ * update, and access operations safely execute concurrently by
+ * multiple threads.
+ *
+ * <p>Iterators and spliterators are
+ * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ *
+ * <p>Ascending key ordered views and their iterators are faster than
+ * descending ones.
+ *
+ * <p>All {@code Map.Entry} pairs returned by methods in this class
+ * and its views represent snapshots of mappings at the time they were
+ * produced. They do <em>not</em> support the {@code Entry.setValue}
+ * method. (Note however that it is possible to change mappings in the
+ * associated map using {@code put}, {@code putIfAbsent}, or
+ * {@code replace}, depending on exactly which effect you need.)
+ *
+ * <p>Beware that, unlike in most collections, the {@code size}
+ * method is <em>not</em> a constant-time operation. Because of the
+ * asynchronous nature of these maps, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code putAll}, {@code equals},
+ * {@code toArray}, {@code containsValue}, and {@code clear} are
+ * <em>not</em> guaranteed to be performed atomically. For example, an
+ * iterator operating concurrently with a {@code putAll} operation
+ * might view only some of the added elements.
+ *
+ * <p>This class and its views and iterators implement all of the
+ * <em>optional</em> methods of the {@link Map} and {@link Iterator}
+ * interfaces. Like most other concurrent collections, this class does
+ * <em>not</em> permit the use of {@code null} keys or values because some
+ * null return values cannot be reliably distinguished from the absence of
+ * elements.
+ *
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 1.6
+ */
+public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
+    implements ConcurrentNavigableMap<K,V>, Cloneable, Serializable {
+    /*
+     * This class implements a tree-like two-dimensionally linked skip
+     * list in which the index levels are represented in separate
+     * nodes from the base nodes holding data.  There are two reasons
+     * for taking this approach instead of the usual array-based
+     * structure: 1) Array based implementations seem to encounter
+     * more complexity and overhead 2) We can use cheaper algorithms
+     * for the heavily-traversed index lists than can be used for the
+     * base lists.  Here's a picture of some of the basics for a
+     * possible list with 2 levels of index:
+     *
+     * Head nodes          Index nodes
+     * +-+    right        +-+                      +-+
+     * |2|---------------->| |--------------------->| |->null
+     * +-+                 +-+                      +-+
+     *  | down              |                        |
+     *  v                   v                        v
+     * +-+            +-+  +-+       +-+            +-+       +-+
+     * |1|----------->| |->| |------>| |----------->| |------>| |->null
+     * +-+            +-+  +-+       +-+            +-+       +-+
+     *  v              |    |         |              |         |
+     * Nodes  next     v    v         v              v         v
+     * +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+
+     * | |->|A|->|B|->|C|->|D|->|E|->|F|->|G|->|H|->|I|->|J|->|K|->null
+     * +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+
+     *
+     * The base lists use a variant of the HM linked ordered set
+     * algorithm. See Tim Harris, "A pragmatic implementation of
+     * non-blocking linked lists"
+     * http://www.cl.cam.ac.uk/~tlh20/publications.html and Maged
+     * Michael "High Performance Dynamic Lock-Free Hash Tables and
+     * List-Based Sets"
+     * http://www.research.ibm.com/people/m/michael/pubs.htm.  The
+     * basic idea in these lists is to mark the "next" pointers of
+     * deleted nodes when deleting to avoid conflicts with concurrent
+     * insertions, and when traversing to keep track of triples
+     * (predecessor, node, successor) in order to detect when and how
+     * to unlink these deleted nodes.
+     *
+     * Rather than using mark-bits to mark list deletions (which can
+     * be slow and space-intensive using AtomicMarkedReference), nodes
+     * use direct CAS'able next pointers.  On deletion, instead of
+     * marking a pointer, they splice in another node that can be
+     * thought of as standing for a marked pointer (indicating this by
+     * using otherwise impossible field values).  Using plain nodes
+     * acts roughly like "boxed" implementations of marked pointers,
+     * but uses new nodes only when nodes are deleted, not for every
+     * link.  This requires less space and supports faster
+     * traversal. Even if marked references were better supported by
+     * JVMs, traversal using this technique might still be faster
+     * because any search need only read ahead one more node than
+     * otherwise required (to check for trailing marker) rather than
+     * unmasking mark bits or whatever on each read.
+     *
+     * This approach maintains the essential property needed in the HM
+     * algorithm of changing the next-pointer of a deleted node so
+     * that any other CAS of it will fail, but implements the idea by
+     * changing the pointer to point to a different node, not by
+     * marking it.  While it would be possible to further squeeze
+     * space by defining marker nodes not to have key/value fields, it
+     * isn't worth the extra type-testing overhead.  The deletion
+     * markers are rarely encountered during traversal and are
+     * normally quickly garbage collected. (Note that this technique
+     * would not work well in systems without garbage collection.)
+     *
+     * In addition to using deletion markers, the lists also use
+     * nullness of value fields to indicate deletion, in a style
+     * similar to typical lazy-deletion schemes.  If a node's value is
+     * null, then it is considered logically deleted and ignored even
+     * though it is still reachable. This maintains proper control of
+     * concurrent replace vs delete operations -- an attempted replace
+     * must fail if a delete beat it by nulling field, and a delete
+     * must return the last non-null value held in the field. (Note:
+     * Null, rather than some special marker, is used for value fields
+     * here because it just so happens to mesh with the Map API
+     * requirement that method get returns null if there is no
+     * mapping, which allows nodes to remain concurrently readable
+     * even when deleted. Using any other marker value here would be
+     * messy at best.)
+     *
+     * Here's the sequence of events for a deletion of node n with
+     * predecessor b and successor f, initially:
+     *
+     *        +------+       +------+      +------+
+     *   ...  |   b  |------>|   n  |----->|   f  | ...
+     *        +------+       +------+      +------+
+     *
+     * 1. CAS n's value field from non-null to null.
+     *    From this point on, no public operations encountering
+     *    the node consider this mapping to exist. However, other
+     *    ongoing insertions and deletions might still modify
+     *    n's next pointer.
+     *
+     * 2. CAS n's next pointer to point to a new marker node.
+     *    From this point on, no other nodes can be appended to n.
+     *    which avoids deletion errors in CAS-based linked lists.
+     *
+     *        +------+       +------+      +------+       +------+
+     *   ...  |   b  |------>|   n  |----->|marker|------>|   f  | ...
+     *        +------+       +------+      +------+       +------+
+     *
+     * 3. CAS b's next pointer over both n and its marker.
+     *    From this point on, no new traversals will encounter n,
+     *    and it can eventually be GCed.
+     *        +------+                                    +------+
+     *   ...  |   b  |----------------------------------->|   f  | ...
+     *        +------+                                    +------+
+     *
+     * A failure at step 1 leads to simple retry due to a lost race
+     * with another operation. Steps 2-3 can fail because some other
+     * thread noticed during a traversal a node with null value and
+     * helped out by marking and/or unlinking.  This helping-out
+     * ensures that no thread can become stuck waiting for progress of
+     * the deleting thread.  The use of marker nodes slightly
+     * complicates helping-out code because traversals must track
+     * consistent reads of up to four nodes (b, n, marker, f), not
+     * just (b, n, f), although the next field of a marker is
+     * immutable, and once a next field is CAS'ed to point to a
+     * marker, it never again changes, so this requires less care.
+     *
+     * Skip lists add indexing to this scheme, so that the base-level
+     * traversals start close to the locations being found, inserted
+     * or deleted -- usually base level traversals only traverse a few
+     * nodes. This doesn't change the basic algorithm except for the
+     * need to make sure base traversals start at predecessors (here,
+     * b) that are not (structurally) deleted, otherwise retrying
+     * after processing the deletion.
+     *
+     * Index levels are maintained as lists with volatile next fields,
+     * using CAS to link and unlink.  Races are allowed in index-list
+     * operations that can (rarely) fail to link in a new index node
+     * or delete one. (We can't do this of course for data nodes.)
+     * However, even when this happens, the index lists remain sorted,
+     * so correctly serve as indices.  This can impact performance,
+     * but since skip lists are probabilistic anyway, the net result
+     * is that under contention, the effective "p" value may be lower
+     * than its nominal value. And race windows are kept small enough
+     * that in practice these failures are rare, even under a lot of
+     * contention.
+     *
+     * The fact that retries (for both base and index lists) are
+     * relatively cheap due to indexing allows some minor
+     * simplifications of retry logic. Traversal restarts are
+     * performed after most "helping-out" CASes. This isn't always
+     * strictly necessary, but the implicit backoffs tend to help
+     * reduce other downstream failed CAS's enough to outweigh restart
+     * cost.  This worsens the worst case, but seems to improve even
+     * highly contended cases.
+     *
+     * Unlike most skip-list implementations, index insertion and
+     * deletion here require a separate traversal pass occurring after
+     * the base-level action, to add or remove index nodes.  This adds
+     * to single-threaded overhead, but improves contended
+     * multithreaded performance by narrowing interference windows,
+     * and allows deletion to ensure that all index nodes will be made
+     * unreachable upon return from a public remove operation, thus
+     * avoiding unwanted garbage retention. This is more important
+     * here than in some other data structures because we cannot null
+     * out node fields referencing user keys since they might still be
+     * read by other ongoing traversals.
+     *
+     * Indexing uses skip list parameters that maintain good search
+     * performance while using sparser-than-usual indices: The
+     * hardwired parameters k=1, p=0.5 (see method doPut) mean
+     * that about one-quarter of the nodes have indices. Of those that
+     * do, half have one level, a quarter have two, and so on (see
+     * Pugh's Skip List Cookbook, sec 3.4).  The expected total space
+     * requirement for a map is slightly less than for the current
+     * implementation of java.util.TreeMap.
+     *
+     * Changing the level of the index (i.e, the height of the
+     * tree-like structure) also uses CAS. The head index has initial
+     * level/height of one. Creation of an index with height greater
+     * than the current level adds a level to the head index by
+     * CAS'ing on a new top-most head. To maintain good performance
+     * after a lot of removals, deletion methods heuristically try to
+     * reduce the height if the topmost levels appear to be empty.
+     * This may encounter races in which it possible (but rare) to
+     * reduce and "lose" a level just as it is about to contain an
+     * index (that will then never be encountered). This does no
+     * structural harm, and in practice appears to be a better option
+     * than allowing unrestrained growth of levels.
+     *
+     * The code for all this is more verbose than you'd like. Most
+     * operations entail locating an element (or position to insert an
+     * element). The code to do this can't be nicely factored out
+     * because subsequent uses require a snapshot of predecessor
+     * and/or successor and/or value fields which can't be returned
+     * all at once, at least not without creating yet another object
+     * to hold them -- creating such little objects is an especially
+     * bad idea for basic internal search operations because it adds
+     * to GC overhead.  (This is one of the few times I've wished Java
+     * had macros.) Instead, some traversal code is interleaved within
+     * insertion and removal operations.  The control logic to handle
+     * all the retry conditions is sometimes twisty. Most search is
+     * broken into 2 parts. findPredecessor() searches index nodes
+     * only, returning a base-level predecessor of the key. findNode()
+     * finishes out the base-level search. Even with this factoring,
+     * there is a fair amount of near-duplication of code to handle
+     * variants.
+     *
+     * To produce random values without interference across threads,
+     * we use within-JDK thread local random support (via the
+     * "secondary seed", to avoid interference with user-level
+     * ThreadLocalRandom.)
+     *
+     * A previous version of this class wrapped non-comparable keys
+     * with their comparators to emulate Comparables when using
+     * comparators vs Comparables.  However, JVMs now appear to better
+     * handle infusing comparator-vs-comparable choice into search
+     * loops. Static method cpr(comparator, x, y) is used for all
+     * comparisons, which works well as long as the comparator
+     * argument is set up outside of loops (thus sometimes passed as
+     * an argument to internal methods) to avoid field re-reads.
+     *
+     * For explanation of algorithms sharing at least a couple of
+     * features with this one, see Mikhail Fomitchev's thesis
+     * (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis
+     * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's
+     * thesis (http://www.cs.chalmers.se/~phs/).
+     *
+     * Given the use of tree-like index nodes, you might wonder why
+     * this doesn't use some kind of search tree instead, which would
+     * support somewhat faster search operations. The reason is that
+     * there are no known efficient lock-free insertion and deletion
+     * algorithms for search trees. The immutability of the "down"
+     * links of index nodes (as opposed to mutable "left" fields in
+     * true trees) makes this tractable using only CAS operations.
+     *
+     * Notation guide for local variables
+     * Node:         b, n, f    for  predecessor, node, successor
+     * Index:        q, r, d    for index node, right, down.
+     *               t          for another index node
+     * Head:         h
+     * Levels:       j
+     * Keys:         k, key
+     * Values:       v, value
+     * Comparisons:  c
+     */
+
+    private static final long serialVersionUID = -8627078645895051609L;
+
+    /**
+     * Special value used to identify base-level header.
+     */
+    static final Object BASE_HEADER = new Object();
+
+    /**
+     * The topmost head index of the skiplist.
+     */
+    private transient volatile HeadIndex<K,V> head;
+
+    /**
+     * The comparator used to maintain order in this map, or null if
+     * using natural ordering.  (Non-private to simplify access in
+     * nested classes.)
+     * @serial
+     */
+    final Comparator<? super K> comparator;
+
+    /** Lazily initialized key set */
+    private transient KeySet<K,V> keySet;
+    /** Lazily initialized entry set */
+    private transient EntrySet<K,V> entrySet;
+    /** Lazily initialized values collection */
+    private transient Values<K,V> values;
+    /** Lazily initialized descending key set */
+    private transient ConcurrentNavigableMap<K,V> descendingMap;
+
+    /**
+     * Initializes or resets state. Needed by constructors, clone,
+     * clear, readObject. and ConcurrentSkipListSet.clone.
+     * (Note that comparator must be separately initialized.)
+     */
+    private void initialize() {
+        keySet = null;
+        entrySet = null;
+        values = null;
+        descendingMap = null;
+        head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null),
+                                  null, null, 1);
+    }
+
+    /**
+     * compareAndSet head node.
+     */
+    private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
+    }
+
+    /* ---------------- Nodes -------------- */
+
+    /**
+     * Nodes hold keys and values, and are singly linked in sorted
+     * order, possibly with some intervening marker nodes. The list is
+     * headed by a dummy node accessible as head.node. The value field
+     * is declared only as Object because it takes special non-V
+     * values for marker and header nodes.
+     */
+    static final class Node<K,V> {
+        final K key;
+        volatile Object value;
+        volatile Node<K,V> next;
+
+        /**
+         * Creates a new regular node.
+         */
+        Node(K key, Object value, Node<K,V> next) {
+            this.key = key;
+            this.value = value;
+            this.next = next;
+        }
+
+        /**
+         * Creates a new marker node. A marker is distinguished by
+         * having its value field point to itself.  Marker nodes also
+         * have null keys, a fact that is exploited in a few places,
+         * but this doesn't distinguish markers from the base-level
+         * header node (head.node), which also has a null key.
+         */
+        Node(Node<K,V> next) {
+            this.key = null;
+            this.value = this;
+            this.next = next;
+        }
+
+        /**
+         * compareAndSet value field.
+         */
+        boolean casValue(Object cmp, Object val) {
+            return U.compareAndSwapObject(this, VALUE, cmp, val);
+        }
+
+        /**
+         * compareAndSet next field.
+         */
+        boolean casNext(Node<K,V> cmp, Node<K,V> val) {
+            return U.compareAndSwapObject(this, NEXT, cmp, val);
+        }
+
+        /**
+         * Returns true if this node is a marker. This method isn't
+         * actually called in any current code checking for markers
+         * because callers will have already read value field and need
+         * to use that read (not another done here) and so directly
+         * test if value points to node.
+         *
+         * @return true if this node is a marker node
+         */
+        boolean isMarker() {
+            return value == this;
+        }
+
+        /**
+         * Returns true if this node is the header of base-level list.
+         * @return true if this node is header node
+         */
+        boolean isBaseHeader() {
+            return value == BASE_HEADER;
+        }
+
+        /**
+         * Tries to append a deletion marker to this node.
+         * @param f the assumed current successor of this node
+         * @return true if successful
+         */
+        boolean appendMarker(Node<K,V> f) {
+            return casNext(f, new Node<K,V>(f));
+        }
+
+        /**
+         * Helps out a deletion by appending marker or unlinking from
+         * predecessor. This is called during traversals when value
+         * field seen to be null.
+         * @param b predecessor
+         * @param f successor
+         */
+        void helpDelete(Node<K,V> b, Node<K,V> f) {
+            /*
+             * Rechecking links and then doing only one of the
+             * help-out stages per call tends to minimize CAS
+             * interference among helping threads.
+             */
+            if (f == next && this == b.next) {
+                if (f == null || f.value != f) // not already marked
+                    casNext(f, new Node<K,V>(f));
+                else
+                    b.casNext(this, f.next);
+            }
+        }
+
+        /**
+         * Returns value if this node contains a valid key-value pair,
+         * else null.
+         * @return this node's value if it isn't a marker or header or
+         * is deleted, else null
+         */
+        V getValidValue() {
+            Object v = value;
+            if (v == this || v == BASE_HEADER)
+                return null;
+            @SuppressWarnings("unchecked") V vv = (V)v;
+            return vv;
+        }
+
+        /**
+         * Creates and returns a new SimpleImmutableEntry holding current
+         * mapping if this node holds a valid value, else null.
+         * @return new entry or null
+         */
+        AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() {
+            Object v = value;
+            if (v == null || v == this || v == BASE_HEADER)
+                return null;
+            @SuppressWarnings("unchecked") V vv = (V)v;
+            return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
+        }
+
+        // Unsafe mechanics
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long VALUE;
+        private static final long NEXT;
+
+        static {
+            try {
+                VALUE = U.objectFieldOffset
+                    (Node.class.getDeclaredField("value"));
+                NEXT = U.objectFieldOffset
+                    (Node.class.getDeclaredField("next"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /* ---------------- Indexing -------------- */
+
+    /**
+     * Index nodes represent the levels of the skip list.  Note that
+     * even though both Nodes and Indexes have forward-pointing
+     * fields, they have different types and are handled in different
+     * ways, that can't nicely be captured by placing field in a
+     * shared abstract class.
+     */
+    static class Index<K,V> {
+        final Node<K,V> node;
+        final Index<K,V> down;
+        volatile Index<K,V> right;
+
+        /**
+         * Creates index node with given values.
+         */
+        Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) {
+            this.node = node;
+            this.down = down;
+            this.right = right;
+        }
+
+        /**
+         * compareAndSet right field.
+         */
+        final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
+            return U.compareAndSwapObject(this, RIGHT, cmp, val);
+        }
+
+        /**
+         * Returns true if the node this indexes has been deleted.
+         * @return true if indexed node is known to be deleted
+         */
+        final boolean indexesDeletedNode() {
+            return node.value == null;
+        }
+
+        /**
+         * Tries to CAS newSucc as successor.  To minimize races with
+         * unlink that may lose this index node, if the node being
+         * indexed is known to be deleted, it doesn't try to link in.
+         * @param succ the expected current successor
+         * @param newSucc the new successor
+         * @return true if successful
+         */
+        final boolean link(Index<K,V> succ, Index<K,V> newSucc) {
+            Node<K,V> n = node;
+            newSucc.right = succ;
+            return n.value != null && casRight(succ, newSucc);
+        }
+
+        /**
+         * Tries to CAS right field to skip over apparent successor
+         * succ.  Fails (forcing a retraversal by caller) if this node
+         * is known to be deleted.
+         * @param succ the expected current successor
+         * @return true if successful
+         */
+        final boolean unlink(Index<K,V> succ) {
+            return node.value != null && casRight(succ, succ.right);
+        }
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long RIGHT;
+        static {
+            try {
+                RIGHT = U.objectFieldOffset
+                    (Index.class.getDeclaredField("right"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /* ---------------- Head nodes -------------- */
+
+    /**
+     * Nodes heading each level keep track of their level.
+     */
+    static final class HeadIndex<K,V> extends Index<K,V> {
+        final int level;
+        HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) {
+            super(node, down, right);
+            this.level = level;
+        }
+    }
+
+    /* ---------------- Comparison utilities -------------- */
+
+    /**
+     * Compares using comparator or natural ordering if null.
+     * Called only by methods that have performed required type checks.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    static final int cpr(Comparator c, Object x, Object y) {
+        return (c != null) ? c.compare(x, y) : ((Comparable)x).compareTo(y);
+    }
+
+    /* ---------------- Traversal -------------- */
+
+    /**
+     * Returns a base-level node with key strictly less than given key,
+     * or the base-level header if there is no such node.  Also
+     * unlinks indexes to deleted nodes found along the way.  Callers
+     * rely on this side-effect of clearing indices to deleted nodes.
+     * @param key the key
+     * @return a predecessor of key
+     */
+    private Node<K,V> findPredecessor(Object key, Comparator<? super K> cmp) {
+        if (key == null)
+            throw new NullPointerException(); // don't postpone errors
+        for (;;) {
+            for (Index<K,V> q = head, r = q.right, d;;) {
+                if (r != null) {
+                    Node<K,V> n = r.node;
+                    K k = n.key;
+                    if (n.value == null) {
+                        if (!q.unlink(r))
+                            break;           // restart
+                        r = q.right;         // reread r
+                        continue;
+                    }
+                    if (cpr(cmp, key, k) > 0) {
+                        q = r;
+                        r = r.right;
+                        continue;
+                    }
+                }
+                if ((d = q.down) == null)
+                    return q.node;
+                q = d;
+                r = d.right;
+            }
+        }
+    }
+
+    /**
+     * Returns node holding key or null if no such, clearing out any
+     * deleted nodes seen along the way.  Repeatedly traverses at
+     * base-level looking for key starting at predecessor returned
+     * from findPredecessor, processing base-level deletions as
+     * encountered. Some callers rely on this side-effect of clearing
+     * deleted nodes.
+     *
+     * Restarts occur, at traversal step centered on node n, if:
+     *
+     *   (1) After reading n's next field, n is no longer assumed
+     *       predecessor b's current successor, which means that
+     *       we don't have a consistent 3-node snapshot and so cannot
+     *       unlink any subsequent deleted nodes encountered.
+     *
+     *   (2) n's value field is null, indicating n is deleted, in
+     *       which case we help out an ongoing structural deletion
+     *       before retrying.  Even though there are cases where such
+     *       unlinking doesn't require restart, they aren't sorted out
+     *       here because doing so would not usually outweigh cost of
+     *       restarting.
+     *
+     *   (3) n is a marker or n's predecessor's value field is null,
+     *       indicating (among other possibilities) that
+     *       findPredecessor returned a deleted node. We can't unlink
+     *       the node because we don't know its predecessor, so rely
+     *       on another call to findPredecessor to notice and return
+     *       some earlier predecessor, which it will do. This check is
+     *       only strictly needed at beginning of loop, (and the
+     *       b.value check isn't strictly needed at all) but is done
+     *       each iteration to help avoid contention with other
+     *       threads by callers that will fail to be able to change
+     *       links, and so will retry anyway.
+     *
+     * The traversal loops in doPut, doRemove, and findNear all
+     * include the same three kinds of checks. And specialized
+     * versions appear in findFirst, and findLast and their variants.
+     * They can't easily share code because each uses the reads of
+     * fields held in locals occurring in the orders they were
+     * performed.
+     *
+     * @param key the key
+     * @return node holding key, or null if no such
+     */
+    private Node<K,V> findNode(Object key) {
+        if (key == null)
+            throw new NullPointerException(); // don't postpone errors
+        Comparator<? super K> cmp = comparator;
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v; int c;
+                if (n == null)
+                    break outer;
+                Node<K,V> f = n.next;
+                if (n != b.next)                // inconsistent read
+                    break;
+                if ((v = n.value) == null) {    // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)  // b is deleted
+                    break;
+                if ((c = cpr(cmp, key, n.key)) == 0)
+                    return n;
+                if (c < 0)
+                    break outer;
+                b = n;
+                n = f;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets value for key. Almost the same as findNode, but returns
+     * the found value (to avoid retries during re-reads)
+     *
+     * @param key the key
+     * @return the value, or null if absent
+     */
+    private V doGet(Object key) {
+        if (key == null)
+            throw new NullPointerException();
+        Comparator<? super K> cmp = comparator;
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v; int c;
+                if (n == null)
+                    break outer;
+                Node<K,V> f = n.next;
+                if (n != b.next)                // inconsistent read
+                    break;
+                if ((v = n.value) == null) {    // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)  // b is deleted
+                    break;
+                if ((c = cpr(cmp, key, n.key)) == 0) {
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    return vv;
+                }
+                if (c < 0)
+                    break outer;
+                b = n;
+                n = f;
+            }
+        }
+        return null;
+    }
+
+    /* ---------------- Insertion -------------- */
+
+    /**
+     * Main insertion method.  Adds element if not present, or
+     * replaces value if present and onlyIfAbsent is false.
+     * @param key the key
+     * @param value the value that must be associated with key
+     * @param onlyIfAbsent if should not insert if already present
+     * @return the old value, or null if newly inserted
+     */
+    private V doPut(K key, V value, boolean onlyIfAbsent) {
+        Node<K,V> z;             // added node
+        if (key == null)
+            throw new NullPointerException();
+        Comparator<? super K> cmp = comparator;
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                if (n != null) {
+                    Object v; int c;
+                    Node<K,V> f = n.next;
+                    if (n != b.next)               // inconsistent read
+                        break;
+                    if ((v = n.value) == null) {   // n is deleted
+                        n.helpDelete(b, f);
+                        break;
+                    }
+                    if (b.value == null || v == n) // b is deleted
+                        break;
+                    if ((c = cpr(cmp, key, n.key)) > 0) {
+                        b = n;
+                        n = f;
+                        continue;
+                    }
+                    if (c == 0) {
+                        if (onlyIfAbsent || n.casValue(v, value)) {
+                            @SuppressWarnings("unchecked") V vv = (V)v;
+                            return vv;
+                        }
+                        break; // restart if lost race to replace value
+                    }
+                    // else c < 0; fall through
+                }
+
+                z = new Node<K,V>(key, value, n);
+                if (!b.casNext(n, z))
+                    break;         // restart if lost race to append to b
+                break outer;
+            }
+        }
+
+        int rnd = ThreadLocalRandom.nextSecondarySeed();
+        if ((rnd & 0x80000001) == 0) { // test highest and lowest bits
+            int level = 1, max;
+            while (((rnd >>>= 1) & 1) != 0)
+                ++level;
+            Index<K,V> idx = null;
+            HeadIndex<K,V> h = head;
+            if (level <= (max = h.level)) {
+                for (int i = 1; i <= level; ++i)
+                    idx = new Index<K,V>(z, idx, null);
+            }
+            else { // try to grow by one level
+                level = max + 1; // hold in array and later pick the one to use
+                @SuppressWarnings("unchecked")Index<K,V>[] idxs =
+                    (Index<K,V>[])new Index<?,?>[level+1];
+                for (int i = 1; i <= level; ++i)
+                    idxs[i] = idx = new Index<K,V>(z, idx, null);
+                for (;;) {
+                    h = head;
+                    int oldLevel = h.level;
+                    if (level <= oldLevel) // lost race to add level
+                        break;
+                    HeadIndex<K,V> newh = h;
+                    Node<K,V> oldbase = h.node;
+                    for (int j = oldLevel+1; j <= level; ++j)
+                        newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);
+                    if (casHead(h, newh)) {
+                        h = newh;
+                        idx = idxs[level = oldLevel];
+                        break;
+                    }
+                }
+            }
+            // find insertion points and splice in
+            splice: for (int insertionLevel = level;;) {
+                int j = h.level;
+                for (Index<K,V> q = h, r = q.right, t = idx;;) {
+                    if (q == null || t == null)
+                        break splice;
+                    if (r != null) {
+                        Node<K,V> n = r.node;
+                        // compare before deletion check avoids needing recheck
+                        int c = cpr(cmp, key, n.key);
+                        if (n.value == null) {
+                            if (!q.unlink(r))
+                                break;
+                            r = q.right;
+                            continue;
+                        }
+                        if (c > 0) {
+                            q = r;
+                            r = r.right;
+                            continue;
+                        }
+                    }
+
+                    if (j == insertionLevel) {
+                        if (!q.link(r, t))
+                            break; // restart
+                        if (t.node.value == null) {
+                            findNode(key);
+                            break splice;
+                        }
+                        if (--insertionLevel == 0)
+                            break splice;
+                    }
+
+                    if (--j >= insertionLevel && j < level)
+                        t = t.down;
+                    q = q.down;
+                    r = q.right;
+                }
+            }
+        }
+        return null;
+    }
+
+    /* ---------------- Deletion -------------- */
+
+    /**
+     * Main deletion method. Locates node, nulls value, appends a
+     * deletion marker, unlinks predecessor, removes associated index
+     * nodes, and possibly reduces head index level.
+     *
+     * Index nodes are cleared out simply by calling findPredecessor.
+     * which unlinks indexes to deleted nodes found along path to key,
+     * which will include the indexes to this node.  This is done
+     * unconditionally. We can't check beforehand whether there are
+     * index nodes because it might be the case that some or all
+     * indexes hadn't been inserted yet for this node during initial
+     * search for it, and we'd like to ensure lack of garbage
+     * retention, so must call to be sure.
+     *
+     * @param key the key
+     * @param value if non-null, the value that must be
+     * associated with key
+     * @return the node, or null if not found
+     */
+    final V doRemove(Object key, Object value) {
+        if (key == null)
+            throw new NullPointerException();
+        Comparator<? super K> cmp = comparator;
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v; int c;
+                if (n == null)
+                    break outer;
+                Node<K,V> f = n.next;
+                if (n != b.next)                    // inconsistent read
+                    break;
+                if ((v = n.value) == null) {        // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)      // b is deleted
+                    break;
+                if ((c = cpr(cmp, key, n.key)) < 0)
+                    break outer;
+                if (c > 0) {
+                    b = n;
+                    n = f;
+                    continue;
+                }
+                if (value != null && !value.equals(v))
+                    break outer;
+                if (!n.casValue(v, null))
+                    break;
+                if (!n.appendMarker(f) || !b.casNext(n, f))
+                    findNode(key);                  // retry via findNode
+                else {
+                    findPredecessor(key, cmp);      // clean index
+                    if (head.right == null)
+                        tryReduceLevel();
+                }
+                @SuppressWarnings("unchecked") V vv = (V)v;
+                return vv;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Possibly reduce head level if it has no nodes.  This method can
+     * (rarely) make mistakes, in which case levels can disappear even
+     * though they are about to contain index nodes. This impacts
+     * performance, not correctness.  To minimize mistakes as well as
+     * to reduce hysteresis, the level is reduced by one only if the
+     * topmost three levels look empty. Also, if the removed level
+     * looks non-empty after CAS, we try to change it back quick
+     * before anyone notices our mistake! (This trick works pretty
+     * well because this method will practically never make mistakes
+     * unless current thread stalls immediately before first CAS, in
+     * which case it is very unlikely to stall again immediately
+     * afterwards, so will recover.)
+     *
+     * We put up with all this rather than just let levels grow
+     * because otherwise, even a small map that has undergone a large
+     * number of insertions and removals will have a lot of levels,
+     * slowing down access more than would an occasional unwanted
+     * reduction.
+     */
+    private void tryReduceLevel() {
+        HeadIndex<K,V> h = head;
+        HeadIndex<K,V> d;
+        HeadIndex<K,V> e;
+        if (h.level > 3 &&
+            (d = (HeadIndex<K,V>)h.down) != null &&
+            (e = (HeadIndex<K,V>)d.down) != null &&
+            e.right == null &&
+            d.right == null &&
+            h.right == null &&
+            casHead(h, d) && // try to set
+            h.right != null) // recheck
+            casHead(d, h);   // try to backout
+    }
+
+    /* ---------------- Finding and removing first element -------------- */
+
+    /**
+     * Specialized variant of findNode to get first valid node.
+     * @return first node or null if empty
+     */
+    final Node<K,V> findFirst() {
+        for (Node<K,V> b, n;;) {
+            if ((n = (b = head.node).next) == null)
+                return null;
+            if (n.value != null)
+                return n;
+            n.helpDelete(b, n.next);
+        }
+    }
+
+    /**
+     * Removes first entry; returns its snapshot.
+     * @return null if empty, else snapshot of first entry
+     */
+    private Map.Entry<K,V> doRemoveFirstEntry() {
+        for (Node<K,V> b, n;;) {
+            if ((n = (b = head.node).next) == null)
+                return null;
+            Node<K,V> f = n.next;
+            if (n != b.next)
+                continue;
+            Object v = n.value;
+            if (v == null) {
+                n.helpDelete(b, f);
+                continue;
+            }
+            if (!n.casValue(v, null))
+                continue;
+            if (!n.appendMarker(f) || !b.casNext(n, f))
+                findFirst(); // retry
+            clearIndexToFirst();
+            @SuppressWarnings("unchecked") V vv = (V)v;
+            return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, vv);
+        }
+    }
+
+    /**
+     * Clears out index nodes associated with deleted first entry.
+     */
+    private void clearIndexToFirst() {
+        for (;;) {
+            for (Index<K,V> q = head;;) {
+                Index<K,V> r = q.right;
+                if (r != null && r.indexesDeletedNode() && !q.unlink(r))
+                    break;
+                if ((q = q.down) == null) {
+                    if (head.right == null)
+                        tryReduceLevel();
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes last entry; returns its snapshot.
+     * Specialized variant of doRemove.
+     * @return null if empty, else snapshot of last entry
+     */
+    private Map.Entry<K,V> doRemoveLastEntry() {
+        for (;;) {
+            Node<K,V> b = findPredecessorOfLast();
+            Node<K,V> n = b.next;
+            if (n == null) {
+                if (b.isBaseHeader())               // empty
+                    return null;
+                else
+                    continue; // all b's successors are deleted; retry
+            }
+            for (;;) {
+                Node<K,V> f = n.next;
+                if (n != b.next)                    // inconsistent read
+                    break;
+                Object v = n.value;
+                if (v == null) {                    // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)      // b is deleted
+                    break;
+                if (f != null) {
+                    b = n;
+                    n = f;
+                    continue;
+                }
+                if (!n.casValue(v, null))
+                    break;
+                K key = n.key;
+                if (!n.appendMarker(f) || !b.casNext(n, f))
+                    findNode(key);                  // retry via findNode
+                else {                              // clean index
+                    findPredecessor(key, comparator);
+                    if (head.right == null)
+                        tryReduceLevel();
+                }
+                @SuppressWarnings("unchecked") V vv = (V)v;
+                return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
+            }
+        }
+    }
+
+    /* ---------------- Finding and removing last element -------------- */
+
+    /**
+     * Specialized version of find to get last valid node.
+     * @return last node or null if empty
+     */
+    final Node<K,V> findLast() {
+        /*
+         * findPredecessor can't be used to traverse index level
+         * because this doesn't use comparisons.  So traversals of
+         * both levels are folded together.
+         */
+        Index<K,V> q = head;
+        for (;;) {
+            Index<K,V> d, r;
+            if ((r = q.right) != null) {
+                if (r.indexesDeletedNode()) {
+                    q.unlink(r);
+                    q = head; // restart
+                }
+                else
+                    q = r;
+            } else if ((d = q.down) != null) {
+                q = d;
+            } else {
+                for (Node<K,V> b = q.node, n = b.next;;) {
+                    if (n == null)
+                        return b.isBaseHeader() ? null : b;
+                    Node<K,V> f = n.next;            // inconsistent read
+                    if (n != b.next)
+                        break;
+                    Object v = n.value;
+                    if (v == null) {                 // n is deleted
+                        n.helpDelete(b, f);
+                        break;
+                    }
+                    if (b.value == null || v == n)      // b is deleted
+                        break;
+                    b = n;
+                    n = f;
+                }
+                q = head; // restart
+            }
+        }
+    }
+
+    /**
+     * Specialized variant of findPredecessor to get predecessor of last
+     * valid node.  Needed when removing the last entry.  It is possible
+     * that all successors of returned node will have been deleted upon
+     * return, in which case this method can be retried.
+     * @return likely predecessor of last node
+     */
+    private Node<K,V> findPredecessorOfLast() {
+        for (;;) {
+            for (Index<K,V> q = head;;) {
+                Index<K,V> d, r;
+                if ((r = q.right) != null) {
+                    if (r.indexesDeletedNode()) {
+                        q.unlink(r);
+                        break;    // must restart
+                    }
+                    // proceed as far across as possible without overshooting
+                    if (r.node.next != null) {
+                        q = r;
+                        continue;
+                    }
+                }
+                if ((d = q.down) != null)
+                    q = d;
+                else
+                    return q.node;
+            }
+        }
+    }
+
+    /* ---------------- Relational operations -------------- */
+
+    // Control values OR'ed as arguments to findNear
+
+    private static final int EQ = 1;
+    private static final int LT = 2;
+    private static final int GT = 0; // Actually checked as !LT
+
+    /**
+     * Utility for ceiling, floor, lower, higher methods.
+     * @param key the key
+     * @param rel the relation -- OR'ed combination of EQ, LT, GT
+     * @return nearest node fitting relation, or null if no such
+     */
+    final Node<K,V> findNear(K key, int rel, Comparator<? super K> cmp) {
+        if (key == null)
+            throw new NullPointerException();
+        for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v;
+                if (n == null)
+                    return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;
+                Node<K,V> f = n.next;
+                if (n != b.next)                  // inconsistent read
+                    break;
+                if ((v = n.value) == null) {      // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)      // b is deleted
+                    break;
+                int c = cpr(cmp, key, n.key);
+                if ((c == 0 && (rel & EQ) != 0) ||
+                    (c <  0 && (rel & LT) == 0))
+                    return n;
+                if ( c <= 0 && (rel & LT) != 0)
+                    return b.isBaseHeader() ? null : b;
+                b = n;
+                n = f;
+            }
+        }
+    }
+
+    /**
+     * Returns SimpleImmutableEntry for results of findNear.
+     * @param key the key
+     * @param rel the relation -- OR'ed combination of EQ, LT, GT
+     * @return Entry fitting relation, or null if no such
+     */
+    final AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) {
+        Comparator<? super K> cmp = comparator;
+        for (;;) {
+            Node<K,V> n = findNear(key, rel, cmp);
+            if (n == null)
+                return null;
+            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+            if (e != null)
+                return e;
+        }
+    }
+
+    /* ---------------- Constructors -------------- */
+
+    /**
+     * Constructs a new, empty map, sorted according to the
+     * {@linkplain Comparable natural ordering} of the keys.
+     */
+    public ConcurrentSkipListMap() {
+        this.comparator = null;
+        initialize();
+    }
+
+    /**
+     * Constructs a new, empty map, sorted according to the specified
+     * comparator.
+     *
+     * @param comparator the comparator that will be used to order this map.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the keys will be used.
+     */
+    public ConcurrentSkipListMap(Comparator<? super K> comparator) {
+        this.comparator = comparator;
+        initialize();
+    }
+
+    /**
+     * Constructs a new map containing the same mappings as the given map,
+     * sorted according to the {@linkplain Comparable natural ordering} of
+     * the keys.
+     *
+     * @param  m the map whose mappings are to be placed in this map
+     * @throws ClassCastException if the keys in {@code m} are not
+     *         {@link Comparable}, or are not mutually comparable
+     * @throws NullPointerException if the specified map or any of its keys
+     *         or values are null
+     */
+    public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) {
+        this.comparator = null;
+        initialize();
+        putAll(m);
+    }
+
+    /**
+     * Constructs a new map containing the same mappings and using the
+     * same ordering as the specified sorted map.
+     *
+     * @param m the sorted map whose mappings are to be placed in this
+     *        map, and whose comparator is to be used to sort this map
+     * @throws NullPointerException if the specified sorted map or any of
+     *         its keys or values are null
+     */
+    public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) {
+        this.comparator = m.comparator();
+        initialize();
+        buildFromSorted(m);
+    }
+
+    /**
+     * Returns a shallow copy of this {@code ConcurrentSkipListMap}
+     * instance. (The keys and values themselves are not cloned.)
+     *
+     * @return a shallow copy of this map
+     */
+    public ConcurrentSkipListMap<K,V> clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            ConcurrentSkipListMap<K,V> clone =
+                (ConcurrentSkipListMap<K,V>) super.clone();
+            clone.initialize();
+            clone.buildFromSorted(this);
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+    /**
+     * Streamlined bulk insertion to initialize from elements of
+     * given sorted map.  Call only from constructor or clone
+     * method.
+     */
+    private void buildFromSorted(SortedMap<K, ? extends V> map) {
+        if (map == null)
+            throw new NullPointerException();
+
+        HeadIndex<K,V> h = head;
+        Node<K,V> basepred = h.node;
+
+        // Track the current rightmost node at each level. Uses an
+        // ArrayList to avoid committing to initial or maximum level.
+        ArrayList<Index<K,V>> preds = new ArrayList<>();
+
+        // initialize
+        for (int i = 0; i <= h.level; ++i)
+            preds.add(null);
+        Index<K,V> q = h;
+        for (int i = h.level; i > 0; --i) {
+            preds.set(i, q);
+            q = q.down;
+        }
+
+        Iterator<? extends Map.Entry<? extends K, ? extends V>> it =
+            map.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<? extends K, ? extends V> e = it.next();
+            int rnd = ThreadLocalRandom.current().nextInt();
+            int j = 0;
+            if ((rnd & 0x80000001) == 0) {
+                do {
+                    ++j;
+                } while (((rnd >>>= 1) & 1) != 0);
+                if (j > h.level) j = h.level + 1;
+            }
+            K k = e.getKey();
+            V v = e.getValue();
+            if (k == null || v == null)
+                throw new NullPointerException();
+            Node<K,V> z = new Node<K,V>(k, v, null);
+            basepred.next = z;
+            basepred = z;
+            if (j > 0) {
+                Index<K,V> idx = null;
+                for (int i = 1; i <= j; ++i) {
+                    idx = new Index<K,V>(z, idx, null);
+                    if (i > h.level)
+                        h = new HeadIndex<K,V>(h.node, h, idx, i);
+
+                    if (i < preds.size()) {
+                        preds.get(i).right = idx;
+                        preds.set(i, idx);
+                    } else
+                        preds.add(idx);
+                }
+            }
+        }
+        head = h;
+    }
+
+    /* ---------------- Serialization -------------- */
+
+    /**
+     * Saves this map to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The key (Object) and value (Object) for each
+     * key-value mapping represented by the map, followed by
+     * {@code null}. The key-value mappings are emitted in key-order
+     * (as determined by the Comparator, or by the keys' natural
+     * ordering if no Comparator).
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out the Comparator and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out keys and values (alternating)
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v = n.getValidValue();
+            if (v != null) {
+                s.writeObject(n.key);
+                s.writeObject(v);
+            }
+        }
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this map from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    @SuppressWarnings("unchecked")
+    private void readObject(final java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in the Comparator and any hidden stuff
+        s.defaultReadObject();
+        // Reset transients
+        initialize();
+
+        /*
+         * This is nearly identical to buildFromSorted, but is
+         * distinct because readObject calls can't be nicely adapted
+         * as the kind of iterator needed by buildFromSorted. (They
+         * can be, but doing so requires type cheats and/or creation
+         * of adapter classes.) It is simpler to just adapt the code.
+         */
+
+        HeadIndex<K,V> h = head;
+        Node<K,V> basepred = h.node;
+        ArrayList<Index<K,V>> preds = new ArrayList<>();
+        for (int i = 0; i <= h.level; ++i)
+            preds.add(null);
+        Index<K,V> q = h;
+        for (int i = h.level; i > 0; --i) {
+            preds.set(i, q);
+            q = q.down;
+        }
+
+        for (;;) {
+            Object k = s.readObject();
+            if (k == null)
+                break;
+            Object v = s.readObject();
+            if (v == null)
+                throw new NullPointerException();
+            K key = (K) k;
+            V val = (V) v;
+            int rnd = ThreadLocalRandom.current().nextInt();
+            int j = 0;
+            if ((rnd & 0x80000001) == 0) {
+                do {
+                    ++j;
+                } while (((rnd >>>= 1) & 1) != 0);
+                if (j > h.level) j = h.level + 1;
+            }
+            Node<K,V> z = new Node<K,V>(key, val, null);
+            basepred.next = z;
+            basepred = z;
+            if (j > 0) {
+                Index<K,V> idx = null;
+                for (int i = 1; i <= j; ++i) {
+                    idx = new Index<K,V>(z, idx, null);
+                    if (i > h.level)
+                        h = new HeadIndex<K,V>(h.node, h, idx, i);
+
+                    if (i < preds.size()) {
+                        preds.get(i).right = idx;
+                        preds.set(i, idx);
+                    } else
+                        preds.add(idx);
+                }
+            }
+        }
+        head = h;
+    }
+
+    /* ------ Map API methods ------ */
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the specified
+     * key.
+     *
+     * @param key key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the specified key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean containsKey(Object key) {
+        return doGet(key) != null;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code key} compares
+     * equal to {@code k} according to the map's ordering, then this
+     * method returns {@code v}; otherwise it returns {@code null}.
+     * (There can be at most one such mapping.)
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public V get(Object key) {
+        return doGet(key);
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or the given defaultValue if this map contains no mapping for the key.
+     *
+     * @param key the key
+     * @param defaultValue the value to return if this map contains
+     * no mapping for the given key
+     * @return the mapping for the key, if present; else the defaultValue
+     * @throws NullPointerException if the specified key is null
+     * @since 1.8
+     */
+    public V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return (v = doGet(key)) == null ? defaultValue : v;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for the 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 the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V put(K key, V value) {
+        if (value == null)
+            throw new NullPointerException();
+        return doPut(key, value, false);
+    }
+
+    /**
+     * Removes the mapping for the specified key from this map if present.
+     *
+     * @param  key key for which mapping should be removed
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public V remove(Object key) {
+        return doRemove(key, null);
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.  This operation requires time linear in the
+     * map size. Additionally, it is possible for the map to change
+     * during execution of this method, in which case the returned
+     * result may be inaccurate.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if a mapping to {@code value} exists;
+     *         {@code false} otherwise
+     * @throws NullPointerException if the specified value is null
+     */
+    public boolean containsValue(Object value) {
+        if (value == null)
+            throw new NullPointerException();
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v = n.getValidValue();
+            if (v != null && value.equals(v))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the number of key-value mappings in this map.  If this map
+     * contains more than {@code Integer.MAX_VALUE} elements, it
+     * returns {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these maps, determining the current
+     * number of elements requires traversing them all to count them.
+     * Additionally, it is possible for the size to change during
+     * execution of this method, in which case the returned result
+     * will be inaccurate. Thus, this method is typically not very
+     * useful in concurrent applications.
+     *
+     * @return the number of elements in this map
+     */
+    public int size() {
+        long count = 0;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            if (n.getValidValue() != null)
+                ++count;
+        }
+        return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;
+    }
+
+    /**
+     * Returns {@code true} if this map contains no key-value mappings.
+     * @return {@code true} if this map contains no key-value mappings
+     */
+    public boolean isEmpty() {
+        return findFirst() == null;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     */
+    public void clear() {
+        initialize();
+    }
+
+    /**
+     * If the specified key is not already associated with a value,
+     * attempts to compute its value using the given mapping function
+     * and enters it into this map unless {@code null}.  The function
+     * is <em>NOT</em> guaranteed to be applied once atomically only
+     * if the value is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param mappingFunction the function to compute a value
+     * @return the current (existing or computed) value associated with
+     *         the specified key, or null if the computed value is null
+     * @throws NullPointerException if the specified key is null
+     *         or the mappingFunction is null
+     * @since 1.8
+     */
+    public V computeIfAbsent(K key,
+                             Function<? super K, ? extends V> mappingFunction) {
+        if (key == null || mappingFunction == null)
+            throw new NullPointerException();
+        V v, p, r;
+        if ((v = doGet(key)) == null &&
+            (r = mappingFunction.apply(key)) != null)
+            v = (p = doPut(key, r, true)) == null ? r : p;
+        return v;
+    }
+
+    /**
+     * If the value for the specified key is present, attempts to
+     * compute a new mapping given the key and its current mapped
+     * value. The function is <em>NOT</em> guaranteed to be applied
+     * once atomically.
+     *
+     * @param key key with which a value may be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null
+     *         or the remappingFunction is null
+     * @since 1.8
+     */
+    public V computeIfPresent(K key,
+                              BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        Node<K,V> n; Object v;
+        while ((n = findNode(key)) != null) {
+            if ((v = n.value) != null) {
+                @SuppressWarnings("unchecked") V vv = (V) v;
+                V r = remappingFunction.apply(key, vv);
+                if (r != null) {
+                    if (n.casValue(vv, r))
+                        return r;
+                }
+                else if (doRemove(key, vv) != null)
+                    break;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Attempts to compute a mapping for the specified key and its
+     * current mapped value (or {@code null} if there is no current
+     * mapping). The function is <em>NOT</em> guaranteed to be applied
+     * once atomically.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null
+     *         or the remappingFunction is null
+     * @since 1.8
+     */
+    public V compute(K key,
+                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; Object v; V r;
+            if ((n = findNode(key)) == null) {
+                if ((r = remappingFunction.apply(key, null)) == null)
+                    break;
+                if (doPut(key, r, true) == null)
+                    return r;
+            }
+            else if ((v = n.value) != null) {
+                @SuppressWarnings("unchecked") V vv = (V) v;
+                if ((r = remappingFunction.apply(key, vv)) != null) {
+                    if (n.casValue(vv, r))
+                        return r;
+                }
+                else if (doRemove(key, vv) != null)
+                    break;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * If the specified key is not already associated with a value,
+     * associates it with the given value.  Otherwise, replaces the
+     * value with the results of the given remapping function, or
+     * removes if {@code null}. The function is <em>NOT</em>
+     * guaranteed to be applied once atomically.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value the value to use if absent
+     * @param remappingFunction the function to recompute a value if present
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or value is null
+     *         or the remappingFunction is null
+     * @since 1.8
+     */
+    public V merge(K key, V value,
+                   BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        if (key == null || value == null || remappingFunction == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; Object v; V r;
+            if ((n = findNode(key)) == null) {
+                if (doPut(key, value, true) == null)
+                    return value;
+            }
+            else if ((v = n.value) != null) {
+                @SuppressWarnings("unchecked") V vv = (V) v;
+                if ((r = remappingFunction.apply(vv, value)) != null) {
+                    if (n.casValue(vv, r))
+                        return r;
+                }
+                else if (doRemove(key, vv) != null)
+                    return null;
+            }
+        }
+    }
+
+    /* ---------------- View methods -------------- */
+
+    /*
+     * Note: Lazy initialization works for views because view classes
+     * are stateless/immutable so it doesn't matter wrt correctness if
+     * more than one is created (which will only rarely happen).  Even
+     * so, the following idiom conservatively ensures that the method
+     * returns the one it created if it does so, not one created by
+     * another racing thread.
+     */
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     *
+     * <p>The set's iterator returns the keys in ascending order.
+     * The set's spliterator additionally reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#SORTED} and
+     * {@link Spliterator#ORDERED}, with an encounter order that is ascending
+     * key order.  The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the map's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the map's comparator.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>This method is equivalent to method {@code navigableKeySet}.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    public NavigableSet<K> keySet() {
+        KeySet<K,V> ks = keySet;
+        return (ks != null) ? ks : (keySet = new KeySet<>(this));
+    }
+
+    public NavigableSet<K> navigableKeySet() {
+        KeySet<K,V> ks = keySet;
+        return (ks != null) ? ks : (keySet = new KeySet<>(this));
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * <p>The collection's iterator returns the values in ascending order
+     * of the corresponding keys. The collections's spliterator additionally
+     * reports {@link Spliterator#CONCURRENT}, {@link Spliterator#NONNULL} and
+     * {@link Spliterator#ORDERED}, with an encounter order that is ascending
+     * order of the corresponding keys.
+     *
+     * <p>The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     */
+    public Collection<V> values() {
+        Values<K,V> vs = values;
+        return (vs != null) ? vs : (values = new Values<>(this));
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     *
+     * <p>The set's iterator returns the entries in ascending key order.  The
+     * set's spliterator additionally reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#SORTED} and
+     * {@link Spliterator#ORDERED}, with an encounter order that is ascending
+     * key order.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll} and {@code clear}
+     * operations.  It does not support the {@code add} or
+     * {@code addAll} operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Map.Entry} elements traversed by the {@code iterator}
+     * or {@code spliterator} do <em>not</em> support the {@code setValue}
+     * operation.
+     *
+     * @return a set view of the mappings contained in this map,
+     *         sorted in ascending key order
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        EntrySet<K,V> es = entrySet;
+        return (es != null) ? es : (entrySet = new EntrySet<K,V>(this));
+    }
+
+    public ConcurrentNavigableMap<K,V> descendingMap() {
+        ConcurrentNavigableMap<K,V> dm = descendingMap;
+        return (dm != null) ? dm : (descendingMap = new SubMap<K,V>
+                                    (this, null, false, null, false, true));
+    }
+
+    public NavigableSet<K> descendingKeySet() {
+        return descendingMap().navigableKeySet();
+    }
+
+    /* ---------------- AbstractMap Overrides -------------- */
+
+    /**
+     * Compares the specified object with this map for equality.
+     * Returns {@code true} if the given object is also a map and the
+     * two maps represent the same mappings.  More formally, two maps
+     * {@code m1} and {@code m2} represent the same mappings if
+     * {@code m1.entrySet().equals(m2.entrySet())}.  This
+     * operation may return misleading results if either map is
+     * concurrently modified during execution of this method.
+     *
+     * @param o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+        if (!(o instanceof Map))
+            return false;
+        Map<?,?> m = (Map<?,?>) o;
+        try {
+            for (Map.Entry<K,V> e : this.entrySet())
+                if (! e.getValue().equals(m.get(e.getKey())))
+                    return false;
+            for (Map.Entry<?,?> e : m.entrySet()) {
+                Object k = e.getKey();
+                Object v = e.getValue();
+                if (k == null || v == null || !v.equals(get(k)))
+                    return false;
+            }
+            return true;
+        } catch (ClassCastException unused) {
+            return false;
+        } catch (NullPointerException unused) {
+            return false;
+        }
+    }
+
+    /* ------ ConcurrentMap API methods ------ */
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V putIfAbsent(K key, V value) {
+        if (value == null)
+            throw new NullPointerException();
+        return doPut(key, value, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean remove(Object key, Object value) {
+        if (key == null)
+            throw new NullPointerException();
+        return value != null && doRemove(key, value) != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if any of the arguments are null
+     */
+    public boolean replace(K key, V oldValue, V newValue) {
+        if (key == null || oldValue == null || newValue == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; Object v;
+            if ((n = findNode(key)) == null)
+                return false;
+            if ((v = n.value) != null) {
+                if (!oldValue.equals(v))
+                    return false;
+                if (n.casValue(v, newValue))
+                    return true;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V replace(K key, V value) {
+        if (key == null || value == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; Object v;
+            if ((n = findNode(key)) == null)
+                return null;
+            if ((v = n.value) != null && n.casValue(v, value)) {
+                @SuppressWarnings("unchecked") V vv = (V)v;
+                return vv;
+            }
+        }
+    }
+
+    /* ------ SortedMap API methods ------ */
+
+    public Comparator<? super K> comparator() {
+        return comparator;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K firstKey() {
+        Node<K,V> n = findFirst();
+        if (n == null)
+            throw new NoSuchElementException();
+        return n.key;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K lastKey() {
+        Node<K,V> n = findLast();
+        if (n == null)
+            throw new NoSuchElementException();
+        return n.key;
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> subMap(K fromKey,
+                                              boolean fromInclusive,
+                                              K toKey,
+                                              boolean toInclusive) {
+        if (fromKey == null || toKey == null)
+            throw new NullPointerException();
+        return new SubMap<K,V>
+            (this, fromKey, fromInclusive, toKey, toInclusive, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> headMap(K toKey,
+                                               boolean inclusive) {
+        if (toKey == null)
+            throw new NullPointerException();
+        return new SubMap<K,V>
+            (this, null, false, toKey, inclusive, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> tailMap(K fromKey,
+                                               boolean inclusive) {
+        if (fromKey == null)
+            throw new NullPointerException();
+        return new SubMap<K,V>
+            (this, fromKey, inclusive, null, false, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey) {
+        return subMap(fromKey, true, toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> headMap(K toKey) {
+        return headMap(toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> tailMap(K fromKey) {
+        return tailMap(fromKey, true);
+    }
+
+    /* ---------------- Relational operations -------------- */
+
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * strictly less than the given key, or {@code null} if there is
+     * no such key. The returned entry does <em>not</em> support the
+     * {@code Entry.setValue} method.
+     *
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> lowerEntry(K key) {
+        return getNear(key, LT);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K lowerKey(K key) {
+        Node<K,V> n = findNear(key, LT, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * less than or equal to the given key, or {@code null} if there
+     * is no such key. The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     *
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> floorEntry(K key) {
+        return getNear(key, LT|EQ);
+    }
+
+    /**
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K floorKey(K key) {
+        Node<K,V> n = findNear(key, LT|EQ, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * greater than or equal to the given key, or {@code null} if
+     * there is no such entry. The returned entry does <em>not</em>
+     * support the {@code Entry.setValue} method.
+     *
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> ceilingEntry(K key) {
+        return getNear(key, GT|EQ);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K ceilingKey(K key) {
+        Node<K,V> n = findNear(key, GT|EQ, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * strictly greater than the given key, or {@code null} if there
+     * is no such key. The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     *
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> higherEntry(K key) {
+        return getNear(key, GT);
+    }
+
+    /**
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K higherKey(K key) {
+        Node<K,V> n = findNear(key, GT, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the least
+     * key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> firstEntry() {
+        for (;;) {
+            Node<K,V> n = findFirst();
+            if (n == null)
+                return null;
+            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+            if (e != null)
+                return e;
+        }
+    }
+
+    /**
+     * Returns a key-value mapping associated with the greatest
+     * key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> lastEntry() {
+        for (;;) {
+            Node<K,V> n = findLast();
+            if (n == null)
+                return null;
+            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+            if (e != null)
+                return e;
+        }
+    }
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the least key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> pollFirstEntry() {
+        return doRemoveFirstEntry();
+    }
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the greatest key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> pollLastEntry() {
+        return doRemoveLastEntry();
+    }
+
+
+    /* ---------------- Iterators -------------- */
+
+    /**
+     * Base of iterator classes:
+     */
+    abstract class Iter<T> implements Iterator<T> {
+        /** the last node returned by next() */
+        Node<K,V> lastReturned;
+        /** the next node to return from next(); */
+        Node<K,V> next;
+        /** Cache of next value field to maintain weak consistency */
+        V nextValue;
+
+        /** Initializes ascending iterator for entire range. */
+        Iter() {
+            while ((next = findFirst()) != null) {
+                Object x = next.value;
+                if (x != null && x != next) {
+                    @SuppressWarnings("unchecked") V vv = (V)x;
+                    nextValue = vv;
+                    break;
+                }
+            }
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        /** Advances next to higher entry. */
+        final void advance() {
+            if (next == null)
+                throw new NoSuchElementException();
+            lastReturned = next;
+            while ((next = next.next) != null) {
+                Object x = next.value;
+                if (x != null && x != next) {
+                    @SuppressWarnings("unchecked") V vv = (V)x;
+                    nextValue = vv;
+                    break;
+                }
+            }
+        }
+
+        public void remove() {
+            Node<K,V> l = lastReturned;
+            if (l == null)
+                throw new IllegalStateException();
+            // It would not be worth all of the overhead to directly
+            // unlink from here. Using remove is fast enough.
+            ConcurrentSkipListMap.this.remove(l.key);
+            lastReturned = null;
+        }
+
+    }
+
+    final class ValueIterator extends Iter<V> {
+        public V next() {
+            V v = nextValue;
+            advance();
+            return v;
+        }
+    }
+
+    final class KeyIterator extends Iter<K> {
+        public K next() {
+            Node<K,V> n = next;
+            advance();
+            return n.key;
+        }
+    }
+
+    final class EntryIterator extends Iter<Map.Entry<K,V>> {
+        public Map.Entry<K,V> next() {
+            Node<K,V> n = next;
+            V v = nextValue;
+            advance();
+            return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+        }
+    }
+
+    /* ---------------- View Classes -------------- */
+
+    /*
+     * View classes are static, delegating to a ConcurrentNavigableMap
+     * to allow use by SubMaps, which outweighs the ugliness of
+     * needing type-tests for Iterator methods.
+     */
+
+    static final <E> List<E> toList(Collection<E> c) {
+        // Using size() here would be a pessimization.
+        ArrayList<E> list = new ArrayList<E>();
+        for (E e : c)
+            list.add(e);
+        return list;
+    }
+
+    static final class KeySet<K,V>
+            extends AbstractSet<K> implements NavigableSet<K> {
+        final ConcurrentNavigableMap<K,V> m;
+        KeySet(ConcurrentNavigableMap<K,V> map) { m = map; }
+        public int size() { return m.size(); }
+        public boolean isEmpty() { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsKey(o); }
+        public boolean remove(Object o) { return m.remove(o) != null; }
+        public void clear() { m.clear(); }
+        public K lower(K e) { return m.lowerKey(e); }
+        public K floor(K e) { return m.floorKey(e); }
+        public K ceiling(K e) { return m.ceilingKey(e); }
+        public K higher(K e) { return m.higherKey(e); }
+        public Comparator<? super K> comparator() { return m.comparator(); }
+        public K first() { return m.firstKey(); }
+        public K last() { return m.lastKey(); }
+        public K pollFirst() {
+            Map.Entry<K,V> e = m.pollFirstEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public K pollLast() {
+            Map.Entry<K,V> e = m.pollLastEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public Iterator<K> iterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).new KeyIterator()
+                : ((SubMap<K,V>)m).new SubMapKeyIterator();
+        }
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (!(o instanceof Set))
+                return false;
+            Collection<?> c = (Collection<?>) o;
+            try {
+                return containsAll(c) && c.containsAll(this);
+            } catch (ClassCastException unused) {
+                return false;
+            } catch (NullPointerException unused) {
+                return false;
+            }
+        }
+        public Object[] toArray()     { return toList(this).toArray();  }
+        public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+        public Iterator<K> descendingIterator() {
+            return descendingSet().iterator();
+        }
+        public NavigableSet<K> subSet(K fromElement,
+                                      boolean fromInclusive,
+                                      K toElement,
+                                      boolean toInclusive) {
+            return new KeySet<>(m.subMap(fromElement, fromInclusive,
+                                         toElement,   toInclusive));
+        }
+        public NavigableSet<K> headSet(K toElement, boolean inclusive) {
+            return new KeySet<>(m.headMap(toElement, inclusive));
+        }
+        public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
+            return new KeySet<>(m.tailMap(fromElement, inclusive));
+        }
+        public NavigableSet<K> subSet(K fromElement, K toElement) {
+            return subSet(fromElement, true, toElement, false);
+        }
+        public NavigableSet<K> headSet(K toElement) {
+            return headSet(toElement, false);
+        }
+        public NavigableSet<K> tailSet(K fromElement) {
+            return tailSet(fromElement, true);
+        }
+        public NavigableSet<K> descendingSet() {
+            return new KeySet<>(m.descendingMap());
+        }
+
+        public Spliterator<K> spliterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).keySpliterator()
+                : ((SubMap<K,V>)m).new SubMapKeyIterator();
+        }
+    }
+
+    static final class Values<K,V> extends AbstractCollection<V> {
+        final ConcurrentNavigableMap<K,V> m;
+        Values(ConcurrentNavigableMap<K,V> map) {
+            m = map;
+        }
+        public Iterator<V> iterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).new ValueIterator()
+                : ((SubMap<K,V>)m).new SubMapValueIterator();
+        }
+        public int size() { return m.size(); }
+        public boolean isEmpty() { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsValue(o); }
+        public void clear() { m.clear(); }
+        public Object[] toArray()     { return toList(this).toArray();  }
+        public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+
+        public Spliterator<V> spliterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).valueSpliterator()
+                : ((SubMap<K,V>)m).new SubMapValueIterator();
+        }
+
+        public boolean removeIf(Predicate<? super V> filter) {
+            if (filter == null) throw new NullPointerException();
+            if (m instanceof ConcurrentSkipListMap)
+                return ((ConcurrentSkipListMap<K,V>)m).removeValueIf(filter);
+            // else use iterator
+            Iterator<Map.Entry<K,V>> it =
+                ((SubMap<K,V>)m).new SubMapEntryIterator();
+            boolean removed = false;
+            while (it.hasNext()) {
+                Map.Entry<K,V> e = it.next();
+                V v = e.getValue();
+                if (filter.test(v) && m.remove(e.getKey(), v))
+                    removed = true;
+            }
+            return removed;
+        }
+    }
+
+    static final class EntrySet<K,V> extends AbstractSet<Map.Entry<K,V>> {
+        final ConcurrentNavigableMap<K,V> m;
+        EntrySet(ConcurrentNavigableMap<K,V> map) {
+            m = map;
+        }
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).new EntryIterator()
+                : ((SubMap<K,V>)m).new SubMapEntryIterator();
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            V v = m.get(e.getKey());
+            return v != null && v.equals(e.getValue());
+        }
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            return m.remove(e.getKey(),
+                            e.getValue());
+        }
+        public boolean isEmpty() {
+            return m.isEmpty();
+        }
+        public int size() {
+            return m.size();
+        }
+        public void clear() {
+            m.clear();
+        }
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (!(o instanceof Set))
+                return false;
+            Collection<?> c = (Collection<?>) o;
+            try {
+                return containsAll(c) && c.containsAll(this);
+            } catch (ClassCastException unused) {
+                return false;
+            } catch (NullPointerException unused) {
+                return false;
+            }
+        }
+        public Object[] toArray()     { return toList(this).toArray();  }
+        public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).entrySpliterator()
+                : ((SubMap<K,V>)m).new SubMapEntryIterator();
+        }
+        public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
+            if (filter == null) throw new NullPointerException();
+            if (m instanceof ConcurrentSkipListMap)
+                return ((ConcurrentSkipListMap<K,V>)m).removeEntryIf(filter);
+            // else use iterator
+            Iterator<Map.Entry<K,V>> it =
+                ((SubMap<K,V>)m).new SubMapEntryIterator();
+            boolean removed = false;
+            while (it.hasNext()) {
+                Map.Entry<K,V> e = it.next();
+                if (filter.test(e) && m.remove(e.getKey(), e.getValue()))
+                    removed = true;
+            }
+            return removed;
+        }
+    }
+
+    /**
+     * Submaps returned by {@link ConcurrentSkipListMap} submap operations
+     * represent a subrange of mappings of their underlying maps.
+     * Instances of this class support all methods of their underlying
+     * maps, differing in that mappings outside their range are ignored,
+     * and attempts to add mappings outside their ranges result in {@link
+     * IllegalArgumentException}.  Instances of this class are constructed
+     * only using the {@code subMap}, {@code headMap}, and {@code tailMap}
+     * methods of their underlying maps.
+     *
+     * @serial include
+     */
+    static final class SubMap<K,V> extends AbstractMap<K,V>
+        implements ConcurrentNavigableMap<K,V>, Cloneable, Serializable {
+        private static final long serialVersionUID = -7647078645895051609L;
+
+        /** Underlying map */
+        final ConcurrentSkipListMap<K,V> m;
+        /** lower bound key, or null if from start */
+        private final K lo;
+        /** upper bound key, or null if to end */
+        private final K hi;
+        /** inclusion flag for lo */
+        private final boolean loInclusive;
+        /** inclusion flag for hi */
+        private final boolean hiInclusive;
+        /** direction */
+        final boolean isDescending;
+
+        // Lazily initialized view holders
+        private transient KeySet<K,V> keySetView;
+        private transient Set<Map.Entry<K,V>> entrySetView;
+        private transient Collection<V> valuesView;
+
+        /**
+         * Creates a new submap, initializing all fields.
+         */
+        SubMap(ConcurrentSkipListMap<K,V> map,
+               K fromKey, boolean fromInclusive,
+               K toKey, boolean toInclusive,
+               boolean isDescending) {
+            Comparator<? super K> cmp = map.comparator;
+            if (fromKey != null && toKey != null &&
+                cpr(cmp, fromKey, toKey) > 0)
+                throw new IllegalArgumentException("inconsistent range");
+            this.m = map;
+            this.lo = fromKey;
+            this.hi = toKey;
+            this.loInclusive = fromInclusive;
+            this.hiInclusive = toInclusive;
+            this.isDescending = isDescending;
+        }
+
+        /* ----------------  Utilities -------------- */
+
+        boolean tooLow(Object key, Comparator<? super K> cmp) {
+            int c;
+            return (lo != null && ((c = cpr(cmp, key, lo)) < 0 ||
+                                   (c == 0 && !loInclusive)));
+        }
+
+        boolean tooHigh(Object key, Comparator<? super K> cmp) {
+            int c;
+            return (hi != null && ((c = cpr(cmp, key, hi)) > 0 ||
+                                   (c == 0 && !hiInclusive)));
+        }
+
+        boolean inBounds(Object key, Comparator<? super K> cmp) {
+            return !tooLow(key, cmp) && !tooHigh(key, cmp);
+        }
+
+        void checkKeyBounds(K key, Comparator<? super K> cmp) {
+            if (key == null)
+                throw new NullPointerException();
+            if (!inBounds(key, cmp))
+                throw new IllegalArgumentException("key out of range");
+        }
+
+        /**
+         * Returns true if node key is less than upper bound of range.
+         */
+        boolean isBeforeEnd(ConcurrentSkipListMap.Node<K,V> n,
+                            Comparator<? super K> cmp) {
+            if (n == null)
+                return false;
+            if (hi == null)
+                return true;
+            K k = n.key;
+            if (k == null) // pass by markers and headers
+                return true;
+            int c = cpr(cmp, k, hi);
+            if (c > 0 || (c == 0 && !hiInclusive))
+                return false;
+            return true;
+        }
+
+        /**
+         * Returns lowest node. This node might not be in range, so
+         * most usages need to check bounds.
+         */
+        ConcurrentSkipListMap.Node<K,V> loNode(Comparator<? super K> cmp) {
+            if (lo == null)
+                return m.findFirst();
+            else if (loInclusive)
+                return m.findNear(lo, GT|EQ, cmp);
+            else
+                return m.findNear(lo, GT, cmp);
+        }
+
+        /**
+         * Returns highest node. This node might not be in range, so
+         * most usages need to check bounds.
+         */
+        ConcurrentSkipListMap.Node<K,V> hiNode(Comparator<? super K> cmp) {
+            if (hi == null)
+                return m.findLast();
+            else if (hiInclusive)
+                return m.findNear(hi, LT|EQ, cmp);
+            else
+                return m.findNear(hi, LT, cmp);
+        }
+
+        /**
+         * Returns lowest absolute key (ignoring directionality).
+         */
+        K lowestKey() {
+            Comparator<? super K> cmp = m.comparator;
+            ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+            if (isBeforeEnd(n, cmp))
+                return n.key;
+            else
+                throw new NoSuchElementException();
+        }
+
+        /**
+         * Returns highest absolute key (ignoring directionality).
+         */
+        K highestKey() {
+            Comparator<? super K> cmp = m.comparator;
+            ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
+            if (n != null) {
+                K last = n.key;
+                if (inBounds(last, cmp))
+                    return last;
+            }
+            throw new NoSuchElementException();
+        }
+
+        Map.Entry<K,V> lowestEntry() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                if (!isBeforeEnd(n, cmp))
+                    return null;
+                Map.Entry<K,V> e = n.createSnapshot();
+                if (e != null)
+                    return e;
+            }
+        }
+
+        Map.Entry<K,V> highestEntry() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
+                if (n == null || !inBounds(n.key, cmp))
+                    return null;
+                Map.Entry<K,V> e = n.createSnapshot();
+                if (e != null)
+                    return e;
+            }
+        }
+
+        Map.Entry<K,V> removeLowest() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                Node<K,V> n = loNode(cmp);
+                if (n == null)
+                    return null;
+                K k = n.key;
+                if (!inBounds(k, cmp))
+                    return null;
+                V v = m.doRemove(k, null);
+                if (v != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+            }
+        }
+
+        Map.Entry<K,V> removeHighest() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                Node<K,V> n = hiNode(cmp);
+                if (n == null)
+                    return null;
+                K k = n.key;
+                if (!inBounds(k, cmp))
+                    return null;
+                V v = m.doRemove(k, null);
+                if (v != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+            }
+        }
+
+        /**
+         * Submap version of ConcurrentSkipListMap.getNearEntry.
+         */
+        Map.Entry<K,V> getNearEntry(K key, int rel) {
+            Comparator<? super K> cmp = m.comparator;
+            if (isDescending) { // adjust relation for direction
+                if ((rel & LT) == 0)
+                    rel |= LT;
+                else
+                    rel &= ~LT;
+            }
+            if (tooLow(key, cmp))
+                return ((rel & LT) != 0) ? null : lowestEntry();
+            if (tooHigh(key, cmp))
+                return ((rel & LT) != 0) ? highestEntry() : null;
+            for (;;) {
+                Node<K,V> n = m.findNear(key, rel, cmp);
+                if (n == null || !inBounds(n.key, cmp))
+                    return null;
+                K k = n.key;
+                V v = n.getValidValue();
+                if (v != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+            }
+        }
+
+        // Almost the same as getNearEntry, except for keys
+        K getNearKey(K key, int rel) {
+            Comparator<? super K> cmp = m.comparator;
+            if (isDescending) { // adjust relation for direction
+                if ((rel & LT) == 0)
+                    rel |= LT;
+                else
+                    rel &= ~LT;
+            }
+            if (tooLow(key, cmp)) {
+                if ((rel & LT) == 0) {
+                    ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                    if (isBeforeEnd(n, cmp))
+                        return n.key;
+                }
+                return null;
+            }
+            if (tooHigh(key, cmp)) {
+                if ((rel & LT) != 0) {
+                    ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
+                    if (n != null) {
+                        K last = n.key;
+                        if (inBounds(last, cmp))
+                            return last;
+                    }
+                }
+                return null;
+            }
+            for (;;) {
+                Node<K,V> n = m.findNear(key, rel, cmp);
+                if (n == null || !inBounds(n.key, cmp))
+                    return null;
+                K k = n.key;
+                V v = n.getValidValue();
+                if (v != null)
+                    return k;
+            }
+        }
+
+        /* ----------------  Map API methods -------------- */
+
+        public boolean containsKey(Object key) {
+            if (key == null) throw new NullPointerException();
+            return inBounds(key, m.comparator) && m.containsKey(key);
+        }
+
+        public V get(Object key) {
+            if (key == null) throw new NullPointerException();
+            return (!inBounds(key, m.comparator)) ? null : m.get(key);
+        }
+
+        public V put(K key, V value) {
+            checkKeyBounds(key, m.comparator);
+            return m.put(key, value);
+        }
+
+        public V remove(Object key) {
+            return (!inBounds(key, m.comparator)) ? null : m.remove(key);
+        }
+
+        public int size() {
+            Comparator<? super K> cmp = m.comparator;
+            long count = 0;
+            for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                 isBeforeEnd(n, cmp);
+                 n = n.next) {
+                if (n.getValidValue() != null)
+                    ++count;
+            }
+            return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count;
+        }
+
+        public boolean isEmpty() {
+            Comparator<? super K> cmp = m.comparator;
+            return !isBeforeEnd(loNode(cmp), cmp);
+        }
+
+        public boolean containsValue(Object value) {
+            if (value == null)
+                throw new NullPointerException();
+            Comparator<? super K> cmp = m.comparator;
+            for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                 isBeforeEnd(n, cmp);
+                 n = n.next) {
+                V v = n.getValidValue();
+                if (v != null && value.equals(v))
+                    return true;
+            }
+            return false;
+        }
+
+        public void clear() {
+            Comparator<? super K> cmp = m.comparator;
+            for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                 isBeforeEnd(n, cmp);
+                 n = n.next) {
+                if (n.getValidValue() != null)
+                    m.remove(n.key);
+            }
+        }
+
+        /* ----------------  ConcurrentMap API methods -------------- */
+
+        public V putIfAbsent(K key, V value) {
+            checkKeyBounds(key, m.comparator);
+            return m.putIfAbsent(key, value);
+        }
+
+        public boolean remove(Object key, Object value) {
+            return inBounds(key, m.comparator) && m.remove(key, value);
+        }
+
+        public boolean replace(K key, V oldValue, V newValue) {
+            checkKeyBounds(key, m.comparator);
+            return m.replace(key, oldValue, newValue);
+        }
+
+        public V replace(K key, V value) {
+            checkKeyBounds(key, m.comparator);
+            return m.replace(key, value);
+        }
+
+        /* ----------------  SortedMap API methods -------------- */
+
+        public Comparator<? super K> comparator() {
+            Comparator<? super K> cmp = m.comparator();
+            if (isDescending)
+                return Collections.reverseOrder(cmp);
+            else
+                return cmp;
+        }
+
+        /**
+         * Utility to create submaps, where given bounds override
+         * unbounded(null) ones and/or are checked against bounded ones.
+         */
+        SubMap<K,V> newSubMap(K fromKey, boolean fromInclusive,
+                              K toKey, boolean toInclusive) {
+            Comparator<? super K> cmp = m.comparator;
+            if (isDescending) { // flip senses
+                K tk = fromKey;
+                fromKey = toKey;
+                toKey = tk;
+                boolean ti = fromInclusive;
+                fromInclusive = toInclusive;
+                toInclusive = ti;
+            }
+            if (lo != null) {
+                if (fromKey == null) {
+                    fromKey = lo;
+                    fromInclusive = loInclusive;
+                }
+                else {
+                    int c = cpr(cmp, fromKey, lo);
+                    if (c < 0 || (c == 0 && !loInclusive && fromInclusive))
+                        throw new IllegalArgumentException("key out of range");
+                }
+            }
+            if (hi != null) {
+                if (toKey == null) {
+                    toKey = hi;
+                    toInclusive = hiInclusive;
+                }
+                else {
+                    int c = cpr(cmp, toKey, hi);
+                    if (c > 0 || (c == 0 && !hiInclusive && toInclusive))
+                        throw new IllegalArgumentException("key out of range");
+                }
+            }
+            return new SubMap<K,V>(m, fromKey, fromInclusive,
+                                   toKey, toInclusive, isDescending);
+        }
+
+        public SubMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                  K toKey, boolean toInclusive) {
+            if (fromKey == null || toKey == null)
+                throw new NullPointerException();
+            return newSubMap(fromKey, fromInclusive, toKey, toInclusive);
+        }
+
+        public SubMap<K,V> headMap(K toKey, boolean inclusive) {
+            if (toKey == null)
+                throw new NullPointerException();
+            return newSubMap(null, false, toKey, inclusive);
+        }
+
+        public SubMap<K,V> tailMap(K fromKey, boolean inclusive) {
+            if (fromKey == null)
+                throw new NullPointerException();
+            return newSubMap(fromKey, inclusive, null, false);
+        }
+
+        public SubMap<K,V> subMap(K fromKey, K toKey) {
+            return subMap(fromKey, true, toKey, false);
+        }
+
+        public SubMap<K,V> headMap(K toKey) {
+            return headMap(toKey, false);
+        }
+
+        public SubMap<K,V> tailMap(K fromKey) {
+            return tailMap(fromKey, true);
+        }
+
+        public SubMap<K,V> descendingMap() {
+            return new SubMap<K,V>(m, lo, loInclusive,
+                                   hi, hiInclusive, !isDescending);
+        }
+
+        /* ----------------  Relational methods -------------- */
+
+        public Map.Entry<K,V> ceilingEntry(K key) {
+            return getNearEntry(key, GT|EQ);
+        }
+
+        public K ceilingKey(K key) {
+            return getNearKey(key, GT|EQ);
+        }
+
+        public Map.Entry<K,V> lowerEntry(K key) {
+            return getNearEntry(key, LT);
+        }
+
+        public K lowerKey(K key) {
+            return getNearKey(key, LT);
+        }
+
+        public Map.Entry<K,V> floorEntry(K key) {
+            return getNearEntry(key, LT|EQ);
+        }
+
+        public K floorKey(K key) {
+            return getNearKey(key, LT|EQ);
+        }
+
+        public Map.Entry<K,V> higherEntry(K key) {
+            return getNearEntry(key, GT);
+        }
+
+        public K higherKey(K key) {
+            return getNearKey(key, GT);
+        }
+
+        public K firstKey() {
+            return isDescending ? highestKey() : lowestKey();
+        }
+
+        public K lastKey() {
+            return isDescending ? lowestKey() : highestKey();
+        }
+
+        public Map.Entry<K,V> firstEntry() {
+            return isDescending ? highestEntry() : lowestEntry();
+        }
+
+        public Map.Entry<K,V> lastEntry() {
+            return isDescending ? lowestEntry() : highestEntry();
+        }
+
+        public Map.Entry<K,V> pollFirstEntry() {
+            return isDescending ? removeHighest() : removeLowest();
+        }
+
+        public Map.Entry<K,V> pollLastEntry() {
+            return isDescending ? removeLowest() : removeHighest();
+        }
+
+        /* ---------------- Submap Views -------------- */
+
+        public NavigableSet<K> keySet() {
+            KeySet<K,V> ks = keySetView;
+            return (ks != null) ? ks : (keySetView = new KeySet<>(this));
+        }
+
+        public NavigableSet<K> navigableKeySet() {
+            KeySet<K,V> ks = keySetView;
+            return (ks != null) ? ks : (keySetView = new KeySet<>(this));
+        }
+
+        public Collection<V> values() {
+            Collection<V> vs = valuesView;
+            return (vs != null) ? vs : (valuesView = new Values<>(this));
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            Set<Map.Entry<K,V>> es = entrySetView;
+            return (es != null) ? es : (entrySetView = new EntrySet<K,V>(this));
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            return descendingMap().navigableKeySet();
+        }
+
+        /**
+         * Variant of main Iter class to traverse through submaps.
+         * Also serves as back-up Spliterator for views.
+         */
+        abstract class SubMapIter<T> implements Iterator<T>, Spliterator<T> {
+            /** the last node returned by next() */
+            Node<K,V> lastReturned;
+            /** the next node to return from next(); */
+            Node<K,V> next;
+            /** Cache of next value field to maintain weak consistency */
+            V nextValue;
+
+            SubMapIter() {
+                Comparator<? super K> cmp = m.comparator;
+                for (;;) {
+                    next = isDescending ? hiNode(cmp) : loNode(cmp);
+                    if (next == null)
+                        break;
+                    Object x = next.value;
+                    if (x != null && x != next) {
+                        if (! inBounds(next.key, cmp))
+                            next = null;
+                        else {
+                            @SuppressWarnings("unchecked") V vv = (V)x;
+                            nextValue = vv;
+                        }
+                        break;
+                    }
+                }
+            }
+
+            public final boolean hasNext() {
+                return next != null;
+            }
+
+            final void advance() {
+                if (next == null)
+                    throw new NoSuchElementException();
+                lastReturned = next;
+                if (isDescending)
+                    descend();
+                else
+                    ascend();
+            }
+
+            private void ascend() {
+                Comparator<? super K> cmp = m.comparator;
+                for (;;) {
+                    next = next.next;
+                    if (next == null)
+                        break;
+                    Object x = next.value;
+                    if (x != null && x != next) {
+                        if (tooHigh(next.key, cmp))
+                            next = null;
+                        else {
+                            @SuppressWarnings("unchecked") V vv = (V)x;
+                            nextValue = vv;
+                        }
+                        break;
+                    }
+                }
+            }
+
+            private void descend() {
+                Comparator<? super K> cmp = m.comparator;
+                for (;;) {
+                    next = m.findNear(lastReturned.key, LT, cmp);
+                    if (next == null)
+                        break;
+                    Object x = next.value;
+                    if (x != null && x != next) {
+                        if (tooLow(next.key, cmp))
+                            next = null;
+                        else {
+                            @SuppressWarnings("unchecked") V vv = (V)x;
+                            nextValue = vv;
+                        }
+                        break;
+                    }
+                }
+            }
+
+            public void remove() {
+                Node<K,V> l = lastReturned;
+                if (l == null)
+                    throw new IllegalStateException();
+                m.remove(l.key);
+                lastReturned = null;
+            }
+
+            public Spliterator<T> trySplit() {
+                return null;
+            }
+
+            public boolean tryAdvance(Consumer<? super T> action) {
+                if (hasNext()) {
+                    action.accept(next());
+                    return true;
+                }
+                return false;
+            }
+
+            public void forEachRemaining(Consumer<? super T> action) {
+                while (hasNext())
+                    action.accept(next());
+            }
+
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+
+        }
+
+        final class SubMapValueIterator extends SubMapIter<V> {
+            public V next() {
+                V v = nextValue;
+                advance();
+                return v;
+            }
+            public int characteristics() {
+                return 0;
+            }
+        }
+
+        final class SubMapKeyIterator extends SubMapIter<K> {
+            public K next() {
+                Node<K,V> n = next;
+                advance();
+                return n.key;
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT | Spliterator.ORDERED |
+                    Spliterator.SORTED;
+            }
+            public final Comparator<? super K> getComparator() {
+                return SubMap.this.comparator();
+            }
+        }
+
+        final class SubMapEntryIterator extends SubMapIter<Map.Entry<K,V>> {
+            public Map.Entry<K,V> next() {
+                Node<K,V> n = next;
+                V v = nextValue;
+                advance();
+                return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT;
+            }
+        }
+    }
+
+    // default Map method overrides
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null) throw new NullPointerException();
+        V v;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            if ((v = n.getValidValue()) != null)
+                action.accept(n.key, v);
+        }
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        if (function == null) throw new NullPointerException();
+        V v;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            while ((v = n.getValidValue()) != null) {
+                V r = function.apply(n.key, v);
+                if (r == null) throw new NullPointerException();
+                if (n.casValue(v, r))
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Helper method for EntrySet.removeIf.
+     */
+    boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
+        if (function == null) throw new NullPointerException();
+        boolean removed = false;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v;
+            if ((v = n.getValidValue()) != null) {
+                K k = n.key;
+                Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
+                if (function.test(e) && remove(k, v))
+                    removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Helper method for Values.removeIf.
+     */
+    boolean removeValueIf(Predicate<? super V> function) {
+        if (function == null) throw new NullPointerException();
+        boolean removed = false;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v;
+            if ((v = n.getValidValue()) != null) {
+                K k = n.key;
+                if (function.test(v) && remove(k, v))
+                    removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Base class providing common structure for Spliterators.
+     * (Although not all that much common functionality; as usual for
+     * view classes, details annoyingly vary in key, value, and entry
+     * subclasses in ways that are not worth abstracting out for
+     * internal classes.)
+     *
+     * The basic split strategy is to recursively descend from top
+     * level, row by row, descending to next row when either split
+     * off, or the end of row is encountered. Control of the number of
+     * splits relies on some statistical estimation: The expected
+     * remaining number of elements of a skip list when advancing
+     * either across or down decreases by about 25%. To make this
+     * observation useful, we need to know initial size, which we
+     * don't. But we can just use Integer.MAX_VALUE so that we
+     * don't prematurely zero out while splitting.
+     */
+    abstract static class CSLMSpliterator<K,V> {
+        final Comparator<? super K> comparator;
+        final K fence;     // exclusive upper bound for keys, or null if to end
+        Index<K,V> row;    // the level to split out
+        Node<K,V> current; // current traversal node; initialize at origin
+        int est;           // pseudo-size estimate
+        CSLMSpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                        Node<K,V> origin, K fence, int est) {
+            this.comparator = comparator; this.row = row;
+            this.current = origin; this.fence = fence; this.est = est;
+        }
+
+        public final long estimateSize() { return (long)est; }
+    }
+
+    static final class KeySpliterator<K,V> extends CSLMSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                       Node<K,V> origin, K fence, int est) {
+            super(comparator, row, origin, fence, est);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            Node<K,V> e; K ek;
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            if ((e = current) != null && (ek = e.key) != null) {
+                for (Index<K,V> q = row; q != null; q = row = q.down) {
+                    Index<K,V> s; Node<K,V> b, n; K sk;
+                    if ((s = q.right) != null && (b = s.node) != null &&
+                        (n = b.next) != null && n.value != null &&
+                        (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
+                        (f == null || cpr(cmp, sk, f) < 0)) {
+                        current = n;
+                        Index<K,V> r = q.down;
+                        row = (s.right != null) ? s : s.down;
+                        est -= est >>> 2;
+                        return new KeySpliterator<K,V>(cmp, r, e, sk, est);
+                    }
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            current = null;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
+                    break;
+                if ((v = e.value) != null && v != e)
+                    action.accept(k);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
+                    e = null;
+                    break;
+                }
+                if ((v = e.value) != null && v != e) {
+                    current = e.next;
+                    action.accept(k);
+                    return true;
+                }
+            }
+            current = e;
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.SORTED |
+                Spliterator.ORDERED | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+
+        public final Comparator<? super K> getComparator() {
+            return comparator;
+        }
+    }
+    // factory method for KeySpliterator
+    final KeySpliterator<K,V> keySpliterator() {
+        Comparator<? super K> cmp = comparator;
+        for (;;) { // ensure h corresponds to origin p
+            HeadIndex<K,V> h; Node<K,V> p;
+            Node<K,V> b = (h = head).node;
+            if ((p = b.next) == null || p.value != null)
+                return new KeySpliterator<K,V>(cmp, h, p, null, (p == null) ?
+                                               0 : Integer.MAX_VALUE);
+            p.helpDelete(b, p.next);
+        }
+    }
+
+    static final class ValueSpliterator<K,V> extends CSLMSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                       Node<K,V> origin, K fence, int est) {
+            super(comparator, row, origin, fence, est);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            Node<K,V> e; K ek;
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            if ((e = current) != null && (ek = e.key) != null) {
+                for (Index<K,V> q = row; q != null; q = row = q.down) {
+                    Index<K,V> s; Node<K,V> b, n; K sk;
+                    if ((s = q.right) != null && (b = s.node) != null &&
+                        (n = b.next) != null && n.value != null &&
+                        (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
+                        (f == null || cpr(cmp, sk, f) < 0)) {
+                        current = n;
+                        Index<K,V> r = q.down;
+                        row = (s.right != null) ? s : s.down;
+                        est -= est >>> 2;
+                        return new ValueSpliterator<K,V>(cmp, r, e, sk, est);
+                    }
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            current = null;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
+                    break;
+                if ((v = e.value) != null && v != e) {
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    action.accept(vv);
+                }
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
+                    e = null;
+                    break;
+                }
+                if ((v = e.value) != null && v != e) {
+                    current = e.next;
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    action.accept(vv);
+                    return true;
+                }
+            }
+            current = e;
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.CONCURRENT | Spliterator.ORDERED |
+                Spliterator.NONNULL;
+        }
+    }
+
+    // Almost the same as keySpliterator()
+    final ValueSpliterator<K,V> valueSpliterator() {
+        Comparator<? super K> cmp = comparator;
+        for (;;) {
+            HeadIndex<K,V> h; Node<K,V> p;
+            Node<K,V> b = (h = head).node;
+            if ((p = b.next) == null || p.value != null)
+                return new ValueSpliterator<K,V>(cmp, h, p, null, (p == null) ?
+                                                 0 : Integer.MAX_VALUE);
+            p.helpDelete(b, p.next);
+        }
+    }
+
+    static final class EntrySpliterator<K,V> extends CSLMSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                         Node<K,V> origin, K fence, int est) {
+            super(comparator, row, origin, fence, est);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            Node<K,V> e; K ek;
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            if ((e = current) != null && (ek = e.key) != null) {
+                for (Index<K,V> q = row; q != null; q = row = q.down) {
+                    Index<K,V> s; Node<K,V> b, n; K sk;
+                    if ((s = q.right) != null && (b = s.node) != null &&
+                        (n = b.next) != null && n.value != null &&
+                        (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
+                        (f == null || cpr(cmp, sk, f) < 0)) {
+                        current = n;
+                        Index<K,V> r = q.down;
+                        row = (s.right != null) ? s : s.down;
+                        est -= est >>> 2;
+                        return new EntrySpliterator<K,V>(cmp, r, e, sk, est);
+                    }
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            current = null;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
+                    break;
+                if ((v = e.value) != null && v != e) {
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    action.accept
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+                }
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
+                    e = null;
+                    break;
+                }
+                if ((v = e.value) != null && v != e) {
+                    current = e.next;
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    action.accept
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+                    return true;
+                }
+            }
+            current = e;
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.SORTED |
+                Spliterator.ORDERED | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+
+        public final Comparator<Map.Entry<K,V>> getComparator() {
+            // Adapt or create a key-based comparator
+            if (comparator != null) {
+                return Map.Entry.comparingByKey(comparator);
+            }
+            else {
+                return (Comparator<Map.Entry<K,V>> & Serializable) (e1, e2) -> {
+                    @SuppressWarnings("unchecked")
+                    Comparable<? super K> k1 = (Comparable<? super K>) e1.getKey();
+                    return k1.compareTo(e2.getKey());
+                };
+            }
+        }
+    }
+
+    // Almost the same as keySpliterator()
+    final EntrySpliterator<K,V> entrySpliterator() {
+        Comparator<? super K> cmp = comparator;
+        for (;;) { // almost same as key version
+            HeadIndex<K,V> h; Node<K,V> p;
+            Node<K,V> b = (h = head).node;
+            if ((p = b.next) == null || p.value != null)
+                return new EntrySpliterator<K,V>(cmp, h, p, null, (p == null) ?
+                                                 0 : Integer.MAX_VALUE);
+            p.helpDelete(b, p.next);
+        }
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
+    static {
+        try {
+            HEAD = U.objectFieldOffset
+                (ConcurrentSkipListMap.class.getDeclaredField("head"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/ConcurrentSkipListSet.java b/java/util/concurrent/ConcurrentSkipListSet.java
new file mode 100644
index 0000000..2e11b17
--- /dev/null
+++ b/java/util/concurrent/ConcurrentSkipListSet.java
@@ -0,0 +1,524 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.Spliterator;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
+/**
+ * A scalable concurrent {@link NavigableSet} implementation based on
+ * a {@link ConcurrentSkipListMap}.  The elements of the set are kept
+ * sorted according to their {@linkplain Comparable natural ordering},
+ * or by a {@link Comparator} provided at set creation time, depending
+ * on which constructor is used.
+ *
+ * <p>This implementation provides expected average <i>log(n)</i> time
+ * cost for the {@code contains}, {@code add}, and {@code remove}
+ * operations and their variants.  Insertion, removal, and access
+ * operations safely execute concurrently by multiple threads.
+ *
+ * <p>Iterators and spliterators are
+ * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ *
+ * <p>Ascending ordered views and their iterators are faster than
+ * descending ones.
+ *
+ * <p>Beware that, unlike in most collections, the {@code size}
+ * method is <em>not</em> a constant-time operation. Because of the
+ * asynchronous nature of these sets, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
+ *
+ * <p>This class and its iterators implement all of the
+ * <em>optional</em> methods of the {@link Set} and {@link Iterator}
+ * interfaces. Like most other concurrent collection implementations,
+ * this class does not permit the use of {@code null} elements,
+ * because {@code null} arguments and return values cannot be reliably
+ * distinguished from the absence of elements.
+ *
+ * @author Doug Lea
+ * @param <E> the type of elements maintained by this set
+ * @since 1.6
+ */
+public class ConcurrentSkipListSet<E>
+    extends AbstractSet<E>
+    implements NavigableSet<E>, Cloneable, java.io.Serializable {
+
+    private static final long serialVersionUID = -2479143111061671589L;
+
+    /**
+     * The underlying map. Uses Boolean.TRUE as value for each
+     * element.  This field is declared final for the sake of thread
+     * safety, which entails some ugliness in clone().
+     */
+    private final ConcurrentNavigableMap<E,Object> m;
+
+    /**
+     * Constructs a new, empty set that orders its elements according to
+     * their {@linkplain Comparable natural ordering}.
+     */
+    public ConcurrentSkipListSet() {
+        m = new ConcurrentSkipListMap<E,Object>();
+    }
+
+    /**
+     * Constructs a new, empty set that orders its elements according to
+     * the specified comparator.
+     *
+     * @param comparator the comparator that will be used to order this set.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the elements will be used.
+     */
+    public ConcurrentSkipListSet(Comparator<? super E> comparator) {
+        m = new ConcurrentSkipListMap<E,Object>(comparator);
+    }
+
+    /**
+     * Constructs a new set containing the elements in the specified
+     * collection, that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     *
+     * @param c The elements that will comprise the new set
+     * @throws ClassCastException if the elements in {@code c} are
+     *         not {@link Comparable}, or are not mutually comparable
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public ConcurrentSkipListSet(Collection<? extends E> c) {
+        m = new ConcurrentSkipListMap<E,Object>();
+        addAll(c);
+    }
+
+    /**
+     * Constructs a new set containing the same elements and using the
+     * same ordering as the specified sorted set.
+     *
+     * @param s sorted set whose elements will comprise the new set
+     * @throws NullPointerException if the specified sorted set or any
+     *         of its elements are null
+     */
+    public ConcurrentSkipListSet(SortedSet<E> s) {
+        m = new ConcurrentSkipListMap<E,Object>(s.comparator());
+        addAll(s);
+    }
+
+    /**
+     * For use by submaps
+     */
+    ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) {
+        this.m = m;
+    }
+
+    /**
+     * Returns a shallow copy of this {@code ConcurrentSkipListSet}
+     * instance. (The elements themselves are not cloned.)
+     *
+     * @return a shallow copy of this set
+     */
+    public ConcurrentSkipListSet<E> clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            ConcurrentSkipListSet<E> clone =
+                (ConcurrentSkipListSet<E>) super.clone();
+            clone.setMap(new ConcurrentSkipListMap<E,Object>(m));
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+    /* ---------------- Set operations -------------- */
+
+    /**
+     * Returns the number of elements in this set.  If this set
+     * contains more than {@code Integer.MAX_VALUE} elements, it
+     * returns {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these sets, determining the current
+     * number of elements requires traversing them all to count them.
+     * Additionally, it is possible for the size to change during
+     * execution of this method, in which case the returned result
+     * will be inaccurate. Thus, this method is typically not very
+     * useful in concurrent applications.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return m.size();
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return m.isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this set
+     * @return {@code true} if this set contains the specified element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean contains(Object o) {
+        return m.containsKey(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element {@code e} to this set if
+     * the set contains no element {@code e2} such that {@code e.equals(e2)}.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the
+     *         specified element
+     * @throws ClassCastException if {@code e} cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return m.putIfAbsent(e, Boolean.TRUE) == null;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element {@code e} such that
+     * {@code o.equals(e)}, if this set contains such an element.
+     * Returns {@code true} if this set contained the element (or
+     * equivalently, if this set changed as a result of the call).
+     * (This set will not contain the element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     * @throws ClassCastException if {@code o} cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean remove(Object o) {
+        return m.remove(o, Boolean.TRUE);
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     */
+    public void clear() {
+        m.clear();
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in ascending order.
+     *
+     * @return an iterator over the elements in this set in ascending order
+     */
+    public Iterator<E> iterator() {
+        return m.navigableKeySet().iterator();
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in descending order.
+     *
+     * @return an iterator over the elements in this set in descending order
+     */
+    public Iterator<E> descendingIterator() {
+        return m.descendingKeySet().iterator();
+    }
+
+
+    /* ---------------- AbstractSet Overrides -------------- */
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * {@code true} if the specified object is also a set, the two sets
+     * have the same size, and every member of the specified set is
+     * contained in this set (or equivalently, every member of this set is
+     * contained in the specified set).  This definition ensures that the
+     * equals method works properly across different implementations of the
+     * set interface.
+     *
+     * @param o the object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        // Override AbstractSet version to avoid calling size()
+        if (o == this)
+            return true;
+        if (!(o instanceof Set))
+            return false;
+        Collection<?> c = (Collection<?>) o;
+        try {
+            return containsAll(c) && c.containsAll(this);
+        } catch (ClassCastException unused) {
+            return false;
+        } catch (NullPointerException unused) {
+            return false;
+        }
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in
+     * the specified collection.  If the specified collection is also
+     * a set, this operation effectively modifies this set so that its
+     * value is the <i>asymmetric set difference</i> of the two sets.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public boolean removeAll(Collection<?> c) {
+        // Override AbstractSet version to avoid unnecessary call to size()
+        boolean modified = false;
+        for (Object e : c)
+            if (remove(e))
+                modified = true;
+        return modified;
+    }
+
+    /* ---------------- Relational operations -------------- */
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E lower(E e) {
+        return m.lowerKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E floor(E e) {
+        return m.floorKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E ceiling(E e) {
+        return m.ceilingKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E higher(E e) {
+        return m.higherKey(e);
+    }
+
+    public E pollFirst() {
+        Map.Entry<E,Object> e = m.pollFirstEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+    public E pollLast() {
+        Map.Entry<E,Object> e = m.pollLastEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+
+    /* ---------------- SortedSet operations -------------- */
+
+    public Comparator<? super E> comparator() {
+        return m.comparator();
+    }
+
+    /**
+     * @throws java.util.NoSuchElementException {@inheritDoc}
+     */
+    public E first() {
+        return m.firstKey();
+    }
+
+    /**
+     * @throws java.util.NoSuchElementException {@inheritDoc}
+     */
+    public E last() {
+        return m.lastKey();
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> subSet(E fromElement,
+                                  boolean fromInclusive,
+                                  E toElement,
+                                  boolean toInclusive) {
+        return new ConcurrentSkipListSet<E>
+            (m.subMap(fromElement, fromInclusive,
+                      toElement,   toInclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+        return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+        return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> subSet(E fromElement, E toElement) {
+        return subSet(fromElement, true, toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> headSet(E toElement) {
+        return headSet(toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> tailSet(E fromElement) {
+        return tailSet(fromElement, true);
+    }
+
+    /**
+     * Returns a reverse order view of the elements contained in this set.
+     * The descending set is backed by this set, so changes to the set are
+     * reflected in the descending set, and vice-versa.
+     *
+     * <p>The returned set has an ordering equivalent to
+     * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code s.descendingSet().descendingSet()} returns a
+     * view of {@code s} essentially equivalent to {@code s}.
+     *
+     * @return a reverse order view of this set
+     */
+    public NavigableSet<E> descendingSet() {
+        return new ConcurrentSkipListSet<E>(m.descendingMap());
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#DISTINCT},
+     * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}, with an
+     * encounter order that is ascending order.  Overriding implementations
+     * should document the reporting of additional characteristic values.
+     *
+     * <p>The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the set's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the set's comparator.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return (m instanceof ConcurrentSkipListMap)
+            ? ((ConcurrentSkipListMap<E,?>)m).keySpliterator()
+            : ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
+    }
+
+    // Support for resetting map in clone
+    private void setMap(ConcurrentNavigableMap<E,Object> map) {
+        U.putObjectVolatile(this, MAP, map);
+    }
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long MAP;
+    static {
+        try {
+            MAP = U.objectFieldOffset
+                (ConcurrentSkipListSet.class.getDeclaredField("m"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/CopyOnWriteArrayList.annotated.java b/java/util/concurrent/CopyOnWriteArrayList.annotated.java
new file mode 100644
index 0000000..57ab75c
--- /dev/null
+++ b/java/util/concurrent/CopyOnWriteArrayList.annotated.java
@@ -0,0 +1,125 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group.  Adapted and released, under explicit permission,
+ * from JDK ArrayList.java which carries the following copyright:
+ *
+ * Copyright 1997 by Sun Microsystems, Inc.,
+ * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
+ * All rights reserved.
+ */
+
+
+package java.util.concurrent;
+
+import java.util.ConcurrentModificationException;
+import java.util.List;
+import java.util.Objects;
+import java.util.Collection;
+import java.util.Spliterator;
+import java.util.AbstractList;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class CopyOnWriteArrayList<E> implements java.util.List<E>, java.util.RandomAccess, java.lang.Cloneable, java.io.Serializable {
+
+public CopyOnWriteArrayList() { throw new RuntimeException("Stub!"); }
+
+public CopyOnWriteArrayList(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public CopyOnWriteArrayList(E @libcore.util.NonNull [] toCopyIn) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable E e, int index) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.Nullable E e, int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public E get(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean addIfAbsent(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public int addAllAbsent(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void forEach(@libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NullFromTypeParam E> action) { throw new RuntimeException("Stub!"); }
+
+public boolean removeIf(@libcore.util.NonNull java.util.function.Predicate<? super @libcore.util.NullFromTypeParam E> filter) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(@libcore.util.NonNull java.util.function.UnaryOperator<@libcore.util.NullFromTypeParam E> operator) { throw new RuntimeException("Stub!"); }
+
+public void sort(@libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/concurrent/CopyOnWriteArrayList.java b/java/util/concurrent/CopyOnWriteArrayList.java
new file mode 100644
index 0000000..ebcbbef
--- /dev/null
+++ b/java/util/concurrent/CopyOnWriteArrayList.java
@@ -0,0 +1,1555 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group.  Adapted and released, under explicit permission,
+ * from JDK ArrayList.java which carries the following copyright:
+ *
+ * Copyright 1997 by Sun Microsystems, Inc.,
+ * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
+ * All rights reserved.
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.RandomAccess;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+// Android-changed: Removed javadoc link to collections framework docs
+/**
+ * A thread-safe variant of {@link java.util.ArrayList} in which all mutative
+ * operations ({@code add}, {@code set}, and so on) are implemented by
+ * making a fresh copy of the underlying array.
+ *
+ * <p>This is ordinarily too costly, but may be <em>more</em> efficient
+ * than alternatives when traversal operations vastly outnumber
+ * mutations, and is useful when you cannot or don't want to
+ * synchronize traversals, yet need to preclude interference among
+ * concurrent threads.  The "snapshot" style iterator method uses a
+ * reference to the state of the array at the point that the iterator
+ * was created. This array never changes during the lifetime of the
+ * iterator, so interference is impossible and the iterator is
+ * guaranteed not to throw {@code ConcurrentModificationException}.
+ * The iterator will not reflect additions, removals, or changes to
+ * the list since the iterator was created.  Element-changing
+ * operations on iterators themselves ({@code remove}, {@code set}, and
+ * {@code add}) are not supported. These methods throw
+ * {@code UnsupportedOperationException}.
+ *
+ * <p>All elements are permitted, including {@code null}.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code CopyOnWriteArrayList}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code CopyOnWriteArrayList} in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this list
+ */
+public class CopyOnWriteArrayList<E>
+    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
+    private static final long serialVersionUID = 8673264195747942595L;
+
+    /**
+     * The lock protecting all mutators.  (We have a mild preference
+     * for builtin monitors over ReentrantLock when either will do.)
+     */
+    final transient Object lock = new Object();
+
+    /** The array, accessed only via getArray/setArray. */
+    private transient volatile Object[] array;
+
+    /**
+     * Gets the array.  Non-private so as to also be accessible
+     * from CopyOnWriteArraySet class.
+     */
+    final Object[] getArray() {
+        return array;
+    }
+
+    /**
+     * Sets the array.
+     */
+    final void setArray(Object[] a) {
+        array = a;
+    }
+
+    /**
+     * Creates an empty list.
+     */
+    public CopyOnWriteArrayList() {
+        setArray(new Object[0]);
+    }
+
+    /**
+     * Creates a list containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param c the collection of initially held elements
+     * @throws NullPointerException if the specified collection is null
+     */
+    public CopyOnWriteArrayList(Collection<? extends E> c) {
+        Object[] elements;
+        if (c.getClass() == CopyOnWriteArrayList.class)
+            elements = ((CopyOnWriteArrayList<?>)c).getArray();
+        else {
+            elements = c.toArray();
+            // defend against c.toArray (incorrectly) not returning Object[]
+            // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
+            if (elements.getClass() != Object[].class)
+                elements = Arrays.copyOf(elements, elements.length, Object[].class);
+        }
+        setArray(elements);
+    }
+
+    /**
+     * Creates a list holding a copy of the given array.
+     *
+     * @param toCopyIn the array (a copy of this array is used as the
+     *        internal array)
+     * @throws NullPointerException if the specified array is null
+     */
+    public CopyOnWriteArrayList(E[] toCopyIn) {
+        setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
+    }
+
+    /**
+     * Returns the number of elements in this list.
+     *
+     * @return the number of elements in this list
+     */
+    public int size() {
+        return getArray().length;
+    }
+
+    /**
+     * Returns {@code true} if this list contains no elements.
+     *
+     * @return {@code true} if this list contains no elements
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * static version of indexOf, to allow repeated calls without
+     * needing to re-acquire array each time.
+     * @param o element to search for
+     * @param elements the array
+     * @param index first index to search
+     * @param fence one past last index to search
+     * @return index of element, or -1 if absent
+     */
+    private static int indexOf(Object o, Object[] elements,
+                               int index, int fence) {
+        if (o == null) {
+            for (int i = index; i < fence; i++)
+                if (elements[i] == null)
+                    return i;
+        } else {
+            for (int i = index; i < fence; i++)
+                if (o.equals(elements[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * static version of lastIndexOf.
+     * @param o element to search for
+     * @param elements the array
+     * @param index first index to search
+     * @return index of element, or -1 if absent
+     */
+    private static int lastIndexOf(Object o, Object[] elements, int index) {
+        if (o == null) {
+            for (int i = index; i >= 0; i--)
+                if (elements[i] == null)
+                    return i;
+        } else {
+            for (int i = index; i >= 0; i--)
+                if (o.equals(elements[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * 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 {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this list is to be tested
+     * @return {@code true} if this list contains the specified element
+     */
+    public boolean contains(Object o) {
+        Object[] elements = getArray();
+        return indexOf(o, elements, 0, elements.length) >= 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int indexOf(Object o) {
+        Object[] elements = getArray();
+        return indexOf(o, elements, 0, elements.length);
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element in
+     * this list, searching forwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the lowest index {@code i} such that
+     * {@code i >= index && Objects.equals(get(i), e)},
+     * or -1 if there is no such index.
+     *
+     * @param e element to search for
+     * @param index index to start searching from
+     * @return the index of the first occurrence of the element in
+     *         this list at position {@code index} or later in the list;
+     *         {@code -1} if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     */
+    public int indexOf(E e, int index) {
+        Object[] elements = getArray();
+        return indexOf(e, elements, index, elements.length);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int lastIndexOf(Object o) {
+        Object[] elements = getArray();
+        return lastIndexOf(o, elements, elements.length - 1);
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element in
+     * this list, searching backwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the highest index {@code i} such that
+     * {@code i <= index && Objects.equals(get(i), e)},
+     * or -1 if there is no such index.
+     *
+     * @param e element to search for
+     * @param index index to start searching backwards from
+     * @return the index of the last occurrence of the element at position
+     *         less than or equal to {@code index} in this list;
+     *         -1 if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is greater
+     *         than or equal to the current size of this list
+     */
+    public int lastIndexOf(E e, int index) {
+        Object[] elements = getArray();
+        return lastIndexOf(e, elements, index);
+    }
+
+    /**
+     * Returns a shallow copy of this list.  (The elements themselves
+     * are not copied.)
+     *
+     * @return a clone of this list
+     */
+    public Object clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            CopyOnWriteArrayList<E> clone =
+                (CopyOnWriteArrayList<E>) super.clone();
+            clone.resetLock();
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all the elements in this list
+     */
+    public Object[] toArray() {
+        Object[] elements = getArray();
+        return Arrays.copyOf(elements, elements.length);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list in
+     * proper sequence (from first to last element); the runtime type of
+     * the returned array is that of the specified array.  If the list fits
+     * in the specified array, it is returned therein.  Otherwise, a new
+     * array is allocated with the runtime type of the specified array and
+     * the size of this list.
+     *
+     * <p>If this list fits in the specified array with room to spare
+     * (i.e., the array has more elements than this list), the element in
+     * the array immediately following the end of the list is set to
+     * {@code null}.  (This is useful in determining the length of this
+     * list <i>only</i> if the caller knows that this list does not contain
+     * any null elements.)
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <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 {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * 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
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing all the elements in this list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this list
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        Object[] elements = getArray();
+        int len = elements.length;
+        if (a.length < len)
+            return (T[]) Arrays.copyOf(elements, len, a.getClass());
+        else {
+            System.arraycopy(elements, 0, a, 0, len);
+            if (a.length > len)
+                a[len] = null;
+            return a;
+        }
+    }
+
+    // Positional Access Operations
+
+    @SuppressWarnings("unchecked")
+    private E get(Object[] a, int index) {
+        return (E) a[index];
+    }
+
+    static String outOfBounds(int index, int size) {
+        return "Index: " + index + ", Size: " + size;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        return get(getArray(), index);
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            E oldValue = get(elements, index);
+
+            if (oldValue != element) {
+                int len = elements.length;
+                Object[] newElements = Arrays.copyOf(elements, len);
+                newElements[index] = element;
+                setArray(newElements);
+            } else {
+                // Not quite a no-op; ensures volatile write semantics
+                setArray(elements);
+            }
+            return oldValue;
+        }
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     */
+    public boolean add(E e) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            Object[] newElements = Arrays.copyOf(elements, len + 1);
+            newElements[len] = e;
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this
+     * list. Shifts the element currently at that position (if any) and
+     * any subsequent elements to the right (adds one to their indices).
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (index > len || index < 0)
+                throw new IndexOutOfBoundsException(outOfBounds(index, len));
+            Object[] newElements;
+            int numMoved = len - index;
+            if (numMoved == 0)
+                newElements = Arrays.copyOf(elements, len + 1);
+            else {
+                newElements = new Object[len + 1];
+                System.arraycopy(elements, 0, newElements, 0, index);
+                System.arraycopy(elements, index, newElements, index + 1,
+                                 numMoved);
+            }
+            newElements[index] = element;
+            setArray(newElements);
+        }
+    }
+
+    /**
+     * Removes the element at the specified position in this list.
+     * Shifts any subsequent elements to the left (subtracts one from their
+     * indices).  Returns the element that was removed from the list.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E remove(int index) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            E oldValue = get(elements, index);
+            int numMoved = len - index - 1;
+            if (numMoved == 0)
+                setArray(Arrays.copyOf(elements, len - 1));
+            else {
+                Object[] newElements = new Object[len - 1];
+                System.arraycopy(elements, 0, newElements, 0, index);
+                System.arraycopy(elements, index + 1, newElements, index,
+                                 numMoved);
+                setArray(newElements);
+            }
+            return oldValue;
+        }
+    }
+
+    /**
+     * 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
+     * {@code i} such that {@code Objects.equals(o, get(i))}
+     * (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 {@code true} if this list contained the specified element
+     */
+    public boolean remove(Object o) {
+        Object[] snapshot = getArray();
+        int index = indexOf(o, snapshot, 0, snapshot.length);
+        return (index < 0) ? false : remove(o, snapshot, index);
+    }
+
+    /**
+     * A version of remove(Object) using the strong hint that given
+     * recent snapshot contains o at the given index.
+     */
+    private boolean remove(Object o, Object[] snapshot, int index) {
+        synchronized (lock) {
+            Object[] current = getArray();
+            int len = current.length;
+            if (snapshot != current) findIndex: {
+                int prefix = Math.min(index, len);
+                for (int i = 0; i < prefix; i++) {
+                    if (current[i] != snapshot[i]
+                        && Objects.equals(o, current[i])) {
+                        index = i;
+                        break findIndex;
+                    }
+                }
+                if (index >= len)
+                    return false;
+                if (current[index] == o)
+                    break findIndex;
+                index = indexOf(o, current, index, len);
+                if (index < 0)
+                    return false;
+            }
+            Object[] newElements = new Object[len - 1];
+            System.arraycopy(current, 0, newElements, 0, index);
+            System.arraycopy(current, index + 1,
+                             newElements, index,
+                             len - index - 1);
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     *
+     * @param fromIndex index of first element to be removed
+     * @param toIndex index after last element to be removed
+     * @throws IndexOutOfBoundsException if fromIndex or toIndex out of range
+     *         ({@code fromIndex < 0 || toIndex > size() || toIndex < fromIndex})
+     */
+    void removeRange(int fromIndex, int toIndex) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+
+            if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
+                throw new IndexOutOfBoundsException();
+            int newlen = len - (toIndex - fromIndex);
+            int numMoved = len - toIndex;
+            if (numMoved == 0)
+                setArray(Arrays.copyOf(elements, newlen));
+            else {
+                Object[] newElements = new Object[newlen];
+                System.arraycopy(elements, 0, newElements, 0, fromIndex);
+                System.arraycopy(elements, toIndex, newElements,
+                                 fromIndex, numMoved);
+                setArray(newElements);
+            }
+        }
+    }
+
+    /**
+     * Appends the element, if not present.
+     *
+     * @param e element to be added to this list, if absent
+     * @return {@code true} if the element was added
+     */
+    public boolean addIfAbsent(E e) {
+        Object[] snapshot = getArray();
+        return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
+            addIfAbsent(e, snapshot);
+    }
+
+    /**
+     * A version of addIfAbsent using the strong hint that given
+     * recent snapshot does not contain e.
+     */
+    private boolean addIfAbsent(E e, Object[] snapshot) {
+        synchronized (lock) {
+            Object[] current = getArray();
+            int len = current.length;
+            if (snapshot != current) {
+                // Optimize for lost race to another addXXX operation
+                int common = Math.min(snapshot.length, len);
+                for (int i = 0; i < common; i++)
+                    if (current[i] != snapshot[i]
+                        && Objects.equals(e, current[i]))
+                        return false;
+                if (indexOf(e, current, common, len) >= 0)
+                        return false;
+            }
+            Object[] newElements = Arrays.copyOf(current, len + 1);
+            newElements[len] = e;
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    /**
+     * Returns {@code true} if this list contains all of the elements of the
+     * specified collection.
+     *
+     * @param c collection to be checked for containment in this list
+     * @return {@code true} if this list contains all of the elements of the
+     *         specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @see #contains(Object)
+     */
+    public boolean containsAll(Collection<?> c) {
+        Object[] elements = getArray();
+        int len = elements.length;
+        for (Object e : c) {
+            if (indexOf(e, elements, 0, len) < 0)
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Removes from this list all of its elements that are contained in
+     * the specified collection. This is a particularly expensive operation
+     * in this class because of the need for an internal temporary array.
+     *
+     * @param c collection containing elements to be removed from this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="../Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        if (c == null) throw new NullPointerException();
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (len != 0) {
+                // temp array holds those elements we know we want to keep
+                int newlen = 0;
+                Object[] temp = new Object[len];
+                for (int i = 0; i < len; ++i) {
+                    Object element = elements[i];
+                    if (!c.contains(element))
+                        temp[newlen++] = element;
+                }
+                if (newlen != len) {
+                    setArray(Arrays.copyOf(temp, newlen));
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Retains only the elements in this list that are contained in the
+     * specified collection.  In other words, removes from this list all of
+     * its elements that are not contained in the specified collection.
+     *
+     * @param c collection containing elements to be retained in this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        if (c == null) throw new NullPointerException();
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (len != 0) {
+                // temp array holds those elements we know we want to keep
+                int newlen = 0;
+                Object[] temp = new Object[len];
+                for (int i = 0; i < len; ++i) {
+                    Object element = elements[i];
+                    if (c.contains(element))
+                        temp[newlen++] = element;
+                }
+                if (newlen != len) {
+                    setArray(Arrays.copyOf(temp, newlen));
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Appends all of the elements in the specified collection that
+     * are not already contained in this list, to the end of
+     * this list, in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @param c collection containing elements to be added to this list
+     * @return the number of elements added
+     * @throws NullPointerException if the specified collection is null
+     * @see #addIfAbsent(Object)
+     */
+    public int addAllAbsent(Collection<? extends E> c) {
+        Object[] cs = c.toArray();
+        if (cs.length == 0)
+            return 0;
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            int added = 0;
+            // uniquify and compact elements in cs
+            for (int i = 0; i < cs.length; ++i) {
+                Object e = cs[i];
+                if (indexOf(e, elements, 0, len) < 0 &&
+                    indexOf(e, cs, 0, added) < 0)
+                    cs[added++] = e;
+            }
+            if (added > 0) {
+                Object[] newElements = Arrays.copyOf(elements, len + added);
+                System.arraycopy(cs, 0, newElements, len, added);
+                setArray(newElements);
+            }
+            return added;
+        }
+    }
+
+    /**
+     * Removes all of the elements from this list.
+     * The list will be empty after this call returns.
+     */
+    public void clear() {
+        synchronized (lock) {
+            setArray(new Object[0]);
+        }
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end
+     * of this list, in the order that they are returned by the specified
+     * collection's iterator.
+     *
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ?
+            ((CopyOnWriteArrayList<?>)c).getArray() : c.toArray();
+        if (cs.length == 0)
+            return false;
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (len == 0 && cs.getClass() == Object[].class)
+                setArray(cs);
+            else {
+                Object[] newElements = Arrays.copyOf(elements, len + cs.length);
+                System.arraycopy(cs, 0, newElements, len, cs.length);
+                setArray(newElements);
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list, starting at the specified position.  Shifts the element
+     * currently at that position (if any) and any subsequent elements to
+     * the right (increases their indices).  The new elements will appear
+     * in this list in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @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 {@code true} if this list changed as a result of the call
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @throws NullPointerException if the specified collection is null
+     * @see #add(int,Object)
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        Object[] cs = c.toArray();
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (index > len || index < 0)
+                throw new IndexOutOfBoundsException(outOfBounds(index, len));
+            if (cs.length == 0)
+                return false;
+            int numMoved = len - index;
+            Object[] newElements;
+            if (numMoved == 0)
+                newElements = Arrays.copyOf(elements, len + cs.length);
+            else {
+                newElements = new Object[len + cs.length];
+                System.arraycopy(elements, 0, newElements, 0, index);
+                System.arraycopy(elements, index,
+                                 newElements, index + cs.length,
+                                 numMoved);
+            }
+            System.arraycopy(cs, 0, newElements, index, cs.length);
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    public void forEach(Consumer<? super E> action) {
+        if (action == null) throw new NullPointerException();
+        for (Object x : getArray()) {
+            @SuppressWarnings("unchecked") E e = (E) x;
+            action.accept(e);
+        }
+    }
+
+    public boolean removeIf(Predicate<? super E> filter) {
+        if (filter == null) throw new NullPointerException();
+        synchronized (lock) {
+            final Object[] elements = getArray();
+            final int len = elements.length;
+            int i;
+            for (i = 0; i < len; i++) {
+                @SuppressWarnings("unchecked") E e = (E) elements[i];
+                if (filter.test(e)) {
+                    int newlen = i;
+                    final Object[] newElements = new Object[len - 1];
+                    System.arraycopy(elements, 0, newElements, 0, newlen);
+                    for (i++; i < len; i++) {
+                        @SuppressWarnings("unchecked") E x = (E) elements[i];
+                        if (!filter.test(x))
+                            newElements[newlen++] = x;
+                    }
+                    setArray((newlen == len - 1)
+                             ? newElements // one match => one copy
+                             : Arrays.copyOf(newElements, newlen));
+                    return true;
+                }
+            }
+            return false;       // zero matches => zero copies
+        }
+    }
+
+    public void replaceAll(UnaryOperator<E> operator) {
+        if (operator == null) throw new NullPointerException();
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            Object[] newElements = Arrays.copyOf(elements, len);
+            for (int i = 0; i < len; ++i) {
+                @SuppressWarnings("unchecked") E e = (E) elements[i];
+                newElements[i] = operator.apply(e);
+            }
+            setArray(newElements);
+        }
+    }
+
+    public void sort(Comparator<? super E> c) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            Object[] newElements = Arrays.copyOf(elements, elements.length);
+            @SuppressWarnings("unchecked") E[] es = (E[])newElements;
+            Arrays.sort(es, c);
+            setArray(newElements);
+        }
+    }
+
+    /**
+     * Saves this list to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The length of the array backing the list is emitted
+     *               (int), followed by all of its elements (each an Object)
+     *               in the proper order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        s.defaultWriteObject();
+
+        Object[] elements = getArray();
+        // Write out array length
+        s.writeInt(elements.length);
+
+        // Write out all elements in the proper order.
+        for (Object element : elements)
+            s.writeObject(element);
+    }
+
+    /**
+     * Reconstitutes this list from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        s.defaultReadObject();
+
+        // bind to new lock
+        resetLock();
+
+        // Read in array length and allocate array
+        int len = s.readInt();
+        Object[] elements = new Object[len];
+
+        // Read in all elements in the proper order.
+        for (int i = 0; i < len; i++)
+            elements[i] = s.readObject();
+        setArray(elements);
+    }
+
+    /**
+     * Returns a string representation of this list.  The string
+     * representation consists of the string representations of the list's
+     * elements in the order they are returned by its iterator, enclosed in
+     * square brackets ({@code "[]"}).  Adjacent elements are separated by
+     * the characters {@code ", "} (comma and space).  Elements are
+     * converted to strings as by {@link String#valueOf(Object)}.
+     *
+     * @return a string representation of this list
+     */
+    public String toString() {
+        return Arrays.toString(getArray());
+    }
+
+    /**
+     * Compares the specified object with this list for equality.
+     * Returns {@code true} if the specified object is the same object
+     * as this object, or if it is also a {@link List} and the sequence
+     * of elements returned by an {@linkplain List#iterator() iterator}
+     * over the specified list is the same as the sequence returned by
+     * an iterator over this list.  The two sequences are considered to
+     * be the same if they have the same length and corresponding
+     * elements at the same position in the sequence are <em>equal</em>.
+     * Two elements {@code e1} and {@code e2} are considered
+     * <em>equal</em> if {@code Objects.equals(e1, e2)}.
+     *
+     * @param o the object to be compared for equality with this list
+     * @return {@code true} if the specified object is equal to this list
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+        if (!(o instanceof List))
+            return false;
+
+        List<?> list = (List<?>)o;
+        Iterator<?> it = list.iterator();
+        Object[] elements = getArray();
+        for (int i = 0, len = elements.length; i < len; i++)
+            if (!it.hasNext() || !Objects.equals(elements[i], it.next()))
+                return false;
+        if (it.hasNext())
+            return false;
+        return true;
+    }
+
+    /**
+     * Returns the hash code value for this list.
+     *
+     * <p>This implementation uses the definition in {@link List#hashCode}.
+     *
+     * @return the hash code value for this list
+     */
+    public int hashCode() {
+        int hashCode = 1;
+        for (Object x : getArray())
+            hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
+        return hashCode;
+    }
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * <p>The returned iterator provides a snapshot of the state of the list
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove} method.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new COWIterator<E>(getArray(), 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The returned iterator provides a snapshot of the state of the list
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove}, {@code set} or {@code add} methods.
+     */
+    public ListIterator<E> listIterator() {
+        return new COWIterator<E>(getArray(), 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The returned iterator provides a snapshot of the state of the list
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove}, {@code set} or {@code add} methods.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public ListIterator<E> listIterator(int index) {
+        Object[] elements = getArray();
+        int len = elements.length;
+        if (index < 0 || index > len)
+            throw new IndexOutOfBoundsException(outOfBounds(index, len));
+
+        return new COWIterator<E>(elements, index);
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#IMMUTABLE},
+     * {@link Spliterator#ORDERED}, {@link Spliterator#SIZED}, and
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * <p>The spliterator provides a snapshot of the state of the list
+     * when the spliterator was constructed. No synchronization is needed while
+     * operating on the spliterator.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator
+            (getArray(), Spliterator.IMMUTABLE | Spliterator.ORDERED);
+    }
+
+    static final class COWIterator<E> implements ListIterator<E> {
+        /** Snapshot of the array */
+        private final Object[] snapshot;
+        /** Index of element to be returned by subsequent call to next.  */
+        private int cursor;
+
+        COWIterator(Object[] elements, int initialCursor) {
+            cursor = initialCursor;
+            snapshot = elements;
+        }
+
+        public boolean hasNext() {
+            return cursor < snapshot.length;
+        }
+
+        public boolean hasPrevious() {
+            return cursor > 0;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (! hasNext())
+                throw new NoSuchElementException();
+            return (E) snapshot[cursor++];
+        }
+
+        @SuppressWarnings("unchecked")
+        public E previous() {
+            if (! hasPrevious())
+                throw new NoSuchElementException();
+            return (E) snapshot[--cursor];
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor-1;
+        }
+
+        /**
+         * Not supported. Always throws UnsupportedOperationException.
+         * @throws UnsupportedOperationException always; {@code remove}
+         *         is not supported by this iterator.
+         */
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Not supported. Always throws UnsupportedOperationException.
+         * @throws UnsupportedOperationException always; {@code set}
+         *         is not supported by this iterator.
+         */
+        public void set(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Not supported. Always throws UnsupportedOperationException.
+         * @throws UnsupportedOperationException always; {@code add}
+         *         is not supported by this iterator.
+         */
+        public void add(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final int size = snapshot.length;
+            for (int i = cursor; i < size; i++) {
+                action.accept((E) snapshot[i]);
+            }
+            cursor = size;
+        }
+    }
+
+    /**
+     * Returns a view of the portion of this list between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * The returned list is backed by this list, so changes in the
+     * returned list are reflected in this list.
+     *
+     * <p>The semantics of the list returned by this method become
+     * undefined if the backing list (i.e., this list) is modified in
+     * any way other than via the returned list.
+     *
+     * @param fromIndex low endpoint (inclusive) of the subList
+     * @param toIndex high endpoint (exclusive) of the subList
+     * @return a view of the specified range within this list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public List<E> subList(int fromIndex, int toIndex) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
+                throw new IndexOutOfBoundsException();
+            return new COWSubList<E>(this, fromIndex, toIndex);
+        }
+    }
+
+    /**
+     * Sublist for CopyOnWriteArrayList.
+     * This class extends AbstractList merely for convenience, to
+     * avoid having to define addAll, etc. This doesn't hurt, but
+     * is wasteful.  This class does not need or use modCount
+     * mechanics in AbstractList, but does need to check for
+     * concurrent modification using similar mechanics.  On each
+     * operation, the array that we expect the backing list to use
+     * is checked and updated.  Since we do this for all of the
+     * base operations invoked by those defined in AbstractList,
+     * all is well.  While inefficient, this is not worth
+     * improving.  The kinds of list operations inherited from
+     * AbstractList are already so slow on COW sublists that
+     * adding a bit more space/time doesn't seem even noticeable.
+     */
+    private static class COWSubList<E>
+        extends AbstractList<E>
+        implements RandomAccess
+    {
+        private final CopyOnWriteArrayList<E> l;
+        private final int offset;
+        private int size;
+        private Object[] expectedArray;
+
+        // only call this holding l's lock
+        COWSubList(CopyOnWriteArrayList<E> list,
+                   int fromIndex, int toIndex) {
+            // assert Thread.holdsLock(list.lock);
+            l = list;
+            expectedArray = l.getArray();
+            offset = fromIndex;
+            size = toIndex - fromIndex;
+        }
+
+        // only call this holding l's lock
+        private void checkForComodification() {
+            // assert Thread.holdsLock(l.lock);
+            if (l.getArray() != expectedArray)
+                throw new ConcurrentModificationException();
+        }
+
+        // only call this holding l's lock
+        private void rangeCheck(int index) {
+            // assert Thread.holdsLock(l.lock);
+            if (index < 0 || index >= size)
+                throw new IndexOutOfBoundsException(outOfBounds(index, size));
+        }
+
+        public E set(int index, E element) {
+            synchronized (l.lock) {
+                rangeCheck(index);
+                checkForComodification();
+                E x = l.set(index+offset, element);
+                expectedArray = l.getArray();
+                return x;
+            }
+        }
+
+        public E get(int index) {
+            synchronized (l.lock) {
+                rangeCheck(index);
+                checkForComodification();
+                return l.get(index+offset);
+            }
+        }
+
+        public int size() {
+            synchronized (l.lock) {
+                checkForComodification();
+                return size;
+            }
+        }
+
+        public void add(int index, E element) {
+            synchronized (l.lock) {
+                checkForComodification();
+                if (index < 0 || index > size)
+                    throw new IndexOutOfBoundsException
+                        (outOfBounds(index, size));
+                l.add(index+offset, element);
+                expectedArray = l.getArray();
+                size++;
+            }
+        }
+
+        public void clear() {
+            synchronized (l.lock) {
+                checkForComodification();
+                l.removeRange(offset, offset+size);
+                expectedArray = l.getArray();
+                size = 0;
+            }
+        }
+
+        public E remove(int index) {
+            synchronized (l.lock) {
+                rangeCheck(index);
+                checkForComodification();
+                E result = l.remove(index+offset);
+                expectedArray = l.getArray();
+                size--;
+                return result;
+            }
+        }
+
+        public boolean remove(Object o) {
+            int index = indexOf(o);
+            if (index == -1)
+                return false;
+            remove(index);
+            return true;
+        }
+
+        public Iterator<E> iterator() {
+            synchronized (l.lock) {
+                checkForComodification();
+                return new COWSubListIterator<E>(l, 0, offset, size);
+            }
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            synchronized (l.lock) {
+                checkForComodification();
+                if (index < 0 || index > size)
+                    throw new IndexOutOfBoundsException
+                        (outOfBounds(index, size));
+                return new COWSubListIterator<E>(l, index, offset, size);
+            }
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            synchronized (l.lock) {
+                checkForComodification();
+                if (fromIndex < 0 || toIndex > size || fromIndex > toIndex)
+                    throw new IndexOutOfBoundsException();
+                return new COWSubList<E>(l, fromIndex + offset,
+                                         toIndex + offset);
+            }
+        }
+
+        public void forEach(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            int lo = offset;
+            int hi = offset + size;
+            Object[] a = expectedArray;
+            if (l.getArray() != a)
+                throw new ConcurrentModificationException();
+            if (lo < 0 || hi > a.length)
+                throw new IndexOutOfBoundsException();
+            for (int i = lo; i < hi; ++i) {
+                @SuppressWarnings("unchecked") E e = (E) a[i];
+                action.accept(e);
+            }
+        }
+
+        public void replaceAll(UnaryOperator<E> operator) {
+            if (operator == null) throw new NullPointerException();
+            synchronized (l.lock) {
+                int lo = offset;
+                int hi = offset + size;
+                Object[] elements = expectedArray;
+                if (l.getArray() != elements)
+                    throw new ConcurrentModificationException();
+                int len = elements.length;
+                if (lo < 0 || hi > len)
+                    throw new IndexOutOfBoundsException();
+                Object[] newElements = Arrays.copyOf(elements, len);
+                for (int i = lo; i < hi; ++i) {
+                    @SuppressWarnings("unchecked") E e = (E) elements[i];
+                    newElements[i] = operator.apply(e);
+                }
+                l.setArray(expectedArray = newElements);
+            }
+        }
+
+        public void sort(Comparator<? super E> c) {
+            synchronized (l.lock) {
+                int lo = offset;
+                int hi = offset + size;
+                Object[] elements = expectedArray;
+                if (l.getArray() != elements)
+                    throw new ConcurrentModificationException();
+                int len = elements.length;
+                if (lo < 0 || hi > len)
+                    throw new IndexOutOfBoundsException();
+                Object[] newElements = Arrays.copyOf(elements, len);
+                @SuppressWarnings("unchecked") E[] es = (E[])newElements;
+                Arrays.sort(es, lo, hi, c);
+                l.setArray(expectedArray = newElements);
+            }
+        }
+
+        public boolean removeAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean removed = false;
+            synchronized (l.lock) {
+                int n = size;
+                if (n > 0) {
+                    int lo = offset;
+                    int hi = offset + n;
+                    Object[] elements = expectedArray;
+                    if (l.getArray() != elements)
+                        throw new ConcurrentModificationException();
+                    int len = elements.length;
+                    if (lo < 0 || hi > len)
+                        throw new IndexOutOfBoundsException();
+                    int newSize = 0;
+                    Object[] temp = new Object[n];
+                    for (int i = lo; i < hi; ++i) {
+                        Object element = elements[i];
+                        if (!c.contains(element))
+                            temp[newSize++] = element;
+                    }
+                    if (newSize != n) {
+                        Object[] newElements = new Object[len - n + newSize];
+                        System.arraycopy(elements, 0, newElements, 0, lo);
+                        System.arraycopy(temp, 0, newElements, lo, newSize);
+                        System.arraycopy(elements, hi, newElements,
+                                         lo + newSize, len - hi);
+                        size = newSize;
+                        removed = true;
+                        l.setArray(expectedArray = newElements);
+                    }
+                }
+            }
+            return removed;
+        }
+
+        public boolean retainAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean removed = false;
+            synchronized (l.lock) {
+                int n = size;
+                if (n > 0) {
+                    int lo = offset;
+                    int hi = offset + n;
+                    Object[] elements = expectedArray;
+                    if (l.getArray() != elements)
+                        throw new ConcurrentModificationException();
+                    int len = elements.length;
+                    if (lo < 0 || hi > len)
+                        throw new IndexOutOfBoundsException();
+                    int newSize = 0;
+                    Object[] temp = new Object[n];
+                    for (int i = lo; i < hi; ++i) {
+                        Object element = elements[i];
+                        if (c.contains(element))
+                            temp[newSize++] = element;
+                    }
+                    if (newSize != n) {
+                        Object[] newElements = new Object[len - n + newSize];
+                        System.arraycopy(elements, 0, newElements, 0, lo);
+                        System.arraycopy(temp, 0, newElements, lo, newSize);
+                        System.arraycopy(elements, hi, newElements,
+                                         lo + newSize, len - hi);
+                        size = newSize;
+                        removed = true;
+                        l.setArray(expectedArray = newElements);
+                    }
+                }
+            }
+            return removed;
+        }
+
+        public boolean removeIf(Predicate<? super E> filter) {
+            if (filter == null) throw new NullPointerException();
+            boolean removed = false;
+            synchronized (l.lock) {
+                int n = size;
+                if (n > 0) {
+                    int lo = offset;
+                    int hi = offset + n;
+                    Object[] elements = expectedArray;
+                    if (l.getArray() != elements)
+                        throw new ConcurrentModificationException();
+                    int len = elements.length;
+                    if (lo < 0 || hi > len)
+                        throw new IndexOutOfBoundsException();
+                    int newSize = 0;
+                    Object[] temp = new Object[n];
+                    for (int i = lo; i < hi; ++i) {
+                        @SuppressWarnings("unchecked") E e = (E) elements[i];
+                        if (!filter.test(e))
+                            temp[newSize++] = e;
+                    }
+                    if (newSize != n) {
+                        Object[] newElements = new Object[len - n + newSize];
+                        System.arraycopy(elements, 0, newElements, 0, lo);
+                        System.arraycopy(temp, 0, newElements, lo, newSize);
+                        System.arraycopy(elements, hi, newElements,
+                                         lo + newSize, len - hi);
+                        size = newSize;
+                        removed = true;
+                        l.setArray(expectedArray = newElements);
+                    }
+                }
+            }
+            return removed;
+        }
+
+        public Spliterator<E> spliterator() {
+            int lo = offset;
+            int hi = offset + size;
+            Object[] a = expectedArray;
+            if (l.getArray() != a)
+                throw new ConcurrentModificationException();
+            if (lo < 0 || hi > a.length)
+                throw new IndexOutOfBoundsException();
+            return Spliterators.spliterator
+                (a, lo, hi, Spliterator.IMMUTABLE | Spliterator.ORDERED);
+        }
+
+    }
+
+    private static class COWSubListIterator<E> implements ListIterator<E> {
+        private final ListIterator<E> it;
+        private final int offset;
+        private final int size;
+
+        COWSubListIterator(List<E> l, int index, int offset, int size) {
+            this.offset = offset;
+            this.size = size;
+            it = l.listIterator(index+offset);
+        }
+
+        public boolean hasNext() {
+            return nextIndex() < size;
+        }
+
+        public E next() {
+            if (hasNext())
+                return it.next();
+            else
+                throw new NoSuchElementException();
+        }
+
+        public boolean hasPrevious() {
+            return previousIndex() >= 0;
+        }
+
+        public E previous() {
+            if (hasPrevious())
+                return it.previous();
+            else
+                throw new NoSuchElementException();
+        }
+
+        public int nextIndex() {
+            return it.nextIndex() - offset;
+        }
+
+        public int previousIndex() {
+            return it.previousIndex() - offset;
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        public void set(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void add(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            while (nextIndex() < size) {
+                action.accept(it.next());
+            }
+        }
+    }
+
+    // Support for resetting lock while deserializing
+    private void resetLock() {
+        U.putObjectVolatile(this, LOCK, new Object());
+    }
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long LOCK;
+    static {
+        try {
+            LOCK = U.objectFieldOffset
+                (CopyOnWriteArrayList.class.getDeclaredField("lock"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/CopyOnWriteArraySet.java b/java/util/concurrent/CopyOnWriteArraySet.java
new file mode 100644
index 0000000..fb707dd
--- /dev/null
+++ b/java/util/concurrent/CopyOnWriteArraySet.java
@@ -0,0 +1,442 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
+/**
+ * A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList}
+ * for all of its operations.  Thus, it shares the same basic properties:
+ * <ul>
+ *  <li>It is best suited for applications in which set sizes generally
+ *       stay small, read-only operations
+ *       vastly outnumber mutative operations, and you need
+ *       to prevent interference among threads during traversal.
+ *  <li>It is thread-safe.
+ *  <li>Mutative operations ({@code add}, {@code set}, {@code remove}, etc.)
+ *      are expensive since they usually entail copying the entire underlying
+ *      array.
+ *  <li>Iterators do not support the mutative {@code remove} operation.
+ *  <li>Traversal via iterators is fast and cannot encounter
+ *      interference from other threads. Iterators rely on
+ *      unchanging snapshots of the array at the time the iterators were
+ *      constructed.
+ * </ul>
+ *
+ * <p><b>Sample Usage.</b> The following code sketch uses a
+ * copy-on-write set to maintain a set of Handler objects that
+ * perform some action upon state updates.
+ *
+ * <pre> {@code
+ * class Handler { void handle(); ... }
+ *
+ * class X {
+ *   private final CopyOnWriteArraySet<Handler> handlers
+ *     = new CopyOnWriteArraySet<>();
+ *   public void addHandler(Handler h) { handlers.add(h); }
+ *
+ *   private long internalState;
+ *   private synchronized void changeState() { internalState = ...; }
+ *
+ *   public void update() {
+ *     changeState();
+ *     for (Handler handler : handlers)
+ *       handler.handle();
+ *   }
+ * }}</pre>
+ *
+ * @see CopyOnWriteArrayList
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this set
+ */
+public class CopyOnWriteArraySet<E> extends AbstractSet<E>
+        implements java.io.Serializable {
+    private static final long serialVersionUID = 5457747651344034263L;
+
+    private final CopyOnWriteArrayList<E> al;
+
+    /**
+     * Creates an empty set.
+     */
+    public CopyOnWriteArraySet() {
+        al = new CopyOnWriteArrayList<E>();
+    }
+
+    /**
+     * Creates a set containing all of the elements of the specified
+     * collection.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection is null
+     */
+    public CopyOnWriteArraySet(Collection<? extends E> c) {
+        if (c.getClass() == CopyOnWriteArraySet.class) {
+            @SuppressWarnings("unchecked") CopyOnWriteArraySet<E> cc =
+                (CopyOnWriteArraySet<E>)c;
+            al = new CopyOnWriteArrayList<E>(cc.al);
+        }
+        else {
+            al = new CopyOnWriteArrayList<E>();
+            al.addAllAbsent(c);
+        }
+    }
+
+    /**
+     * Returns the number of elements in this set.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return al.size();
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return al.isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this set is to be tested
+     * @return {@code true} if this set contains the specified element
+     */
+    public boolean contains(Object o) {
+        return al.contains(o);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this set.
+     * If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the
+     * elements in the same order.
+     *
+     * <p>The returned array will be "safe" in that no references to it
+     * are maintained by this set.  (In other words, this method must
+     * allocate a new array even if this set is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all the elements in this set
+     */
+    public Object[] toArray() {
+        return al.toArray();
+    }
+
+    /**
+     * Returns an array containing all of the elements in this set; the
+     * runtime type of the returned array is that of the specified array.
+     * If the set fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this set.
+     *
+     * <p>If this set fits in the specified array with room to spare
+     * (i.e., the array has more elements than this set), the element in
+     * the array immediately following the end of the set is set to
+     * {@code null}.  (This is useful in determining the length of this
+     * set <i>only</i> if the caller knows that this set does not contain
+     * any null elements.)
+     *
+     * <p>If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements
+     * in the same order.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a set known to contain only strings.
+     * The following code can be used to dump the set into a newly allocated
+     * array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of this set are to be
+     *        stored, if it is big enough; otherwise, a new array of the same
+     *        runtime type is allocated for this purpose.
+     * @return an array containing all the elements in this set
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in this
+     *         set
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        return al.toArray(a);
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     * The set will be empty after this call returns.
+     */
+    public void clear() {
+        al.clear();
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element {@code e} such that
+     * {@code Objects.equals(o, e)}, if this set contains such an element.
+     * Returns {@code true} if this set contained the element (or
+     * equivalently, if this set changed as a result of the call).
+     * (This set will not contain the element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     */
+    public boolean remove(Object o) {
+        return al.remove(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element {@code e} to this set if
+     * the set contains no element {@code e2} such that
+     * {@code Objects.equals(e, e2)}.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the specified
+     *         element
+     */
+    public boolean add(E e) {
+        return al.addIfAbsent(e);
+    }
+
+    /**
+     * Returns {@code true} if this set contains all of the elements of the
+     * specified collection.  If the specified collection is also a set, this
+     * method returns {@code true} if it is a <i>subset</i> of this set.
+     *
+     * @param  c collection to be checked for containment in this set
+     * @return {@code true} if this set contains all of the elements of the
+     *         specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @see #contains(Object)
+     */
+    public boolean containsAll(Collection<?> c) {
+        return (c instanceof Set)
+            ? compareSets(al.getArray(), (Set<?>) c) >= 0
+            : al.containsAll(c);
+    }
+
+    /**
+     * Tells whether the objects in snapshot (regarded as a set) are a
+     * superset of the given set.
+     *
+     * @return -1 if snapshot is not a superset, 0 if the two sets
+     * contain precisely the same elements, and 1 if snapshot is a
+     * proper superset of the given set
+     */
+    private static int compareSets(Object[] snapshot, Set<?> set) {
+        // Uses O(n^2) algorithm, that is only appropriate for small
+        // sets, which CopyOnWriteArraySets should be.
+        //
+        // Optimize up to O(n) if the two sets share a long common prefix,
+        // as might happen if one set was created as a copy of the other set.
+
+        final int len = snapshot.length;
+        // Mark matched elements to avoid re-checking
+        final boolean[] matched = new boolean[len];
+
+        // j is the largest int with matched[i] true for { i | 0 <= i < j }
+        int j = 0;
+        outer: for (Object x : set) {
+            for (int i = j; i < len; i++) {
+                if (!matched[i] && Objects.equals(x, snapshot[i])) {
+                    matched[i] = true;
+                    if (i == j)
+                        do { j++; } while (j < len && matched[j]);
+                    continue outer;
+                }
+            }
+            return -1;
+        }
+        return (j == len) ? 0 : 1;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set if
+     * they're not already present.  If the specified collection is also a
+     * set, the {@code addAll} operation effectively modifies this set so
+     * that its value is the <i>union</i> of the two sets.  The behavior of
+     * this operation is undefined if the specified collection is modified
+     * while the operation is in progress.
+     *
+     * @param  c collection containing elements to be added to this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        return al.addAllAbsent(c) > 0;
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in the
+     * specified collection.  If the specified collection is also a set,
+     * this operation effectively modifies this set so that its value is the
+     * <i>asymmetric set difference</i> of the two sets.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="../Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        return al.removeAll(c);
+    }
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection.  In other words, removes from this set all of
+     * its elements that are not contained in the specified collection.  If
+     * the specified collection is also a set, this operation effectively
+     * modifies this set so that its value is the <i>intersection</i> of the
+     * two sets.
+     *
+     * @param  c collection containing elements to be retained in this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="../Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        return al.retainAll(c);
+    }
+
+    /**
+     * Returns an iterator over the elements contained in this set
+     * in the order in which these elements were added.
+     *
+     * <p>The returned iterator provides a snapshot of the state of the set
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove} method.
+     *
+     * @return an iterator over the elements in this set
+     */
+    public Iterator<E> iterator() {
+        return al.iterator();
+    }
+
+    /**
+     * Compares the specified object with this set for equality.
+     * Returns {@code true} if the specified object is the same object
+     * as this object, or if it is also a {@link Set} and the elements
+     * returned by an {@linkplain Set#iterator() iterator} over the
+     * specified set are the same as the elements returned by an
+     * iterator over this set.  More formally, the two iterators are
+     * considered to return the same elements if they return the same
+     * number of elements and for every element {@code e1} returned by
+     * the iterator over the specified set, there is an element
+     * {@code e2} returned by the iterator over this set such that
+     * {@code Objects.equals(e1, e2)}.
+     *
+     * @param o object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        return (o == this)
+            || ((o instanceof Set)
+                && compareSets(al.getArray(), (Set<?>) o) == 0);
+    }
+
+    public boolean removeIf(Predicate<? super E> filter) {
+        return al.removeIf(filter);
+    }
+
+    public void forEach(Consumer<? super E> action) {
+        al.forEach(action);
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this set in the order
+     * in which these elements were added.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#IMMUTABLE},
+     * {@link Spliterator#DISTINCT}, {@link Spliterator#SIZED}, and
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * <p>The spliterator provides a snapshot of the state of the set
+     * when the spliterator was constructed. No synchronization is needed while
+     * operating on the spliterator.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator
+            (al.getArray(), Spliterator.IMMUTABLE | Spliterator.DISTINCT);
+    }
+}
diff --git a/java/util/concurrent/CountDownLatch.java b/java/util/concurrent/CountDownLatch.java
new file mode 100644
index 0000000..8d85418
--- /dev/null
+++ b/java/util/concurrent/CountDownLatch.java
@@ -0,0 +1,316 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+/**
+ * A synchronization aid that allows one or more threads to wait until
+ * a set of operations being performed in other threads completes.
+ *
+ * <p>A {@code CountDownLatch} is initialized with a given <em>count</em>.
+ * The {@link #await await} methods block until the current count reaches
+ * zero due to invocations of the {@link #countDown} method, after which
+ * all waiting threads are released and any subsequent invocations of
+ * {@link #await await} return immediately.  This is a one-shot phenomenon
+ * -- the count cannot be reset.  If you need a version that resets the
+ * count, consider using a {@link CyclicBarrier}.
+ *
+ * <p>A {@code CountDownLatch} is a versatile synchronization tool
+ * and can be used for a number of purposes.  A
+ * {@code CountDownLatch} initialized with a count of one serves as a
+ * simple on/off latch, or gate: all threads invoking {@link #await await}
+ * wait at the gate until it is opened by a thread invoking {@link
+ * #countDown}.  A {@code CountDownLatch} initialized to <em>N</em>
+ * can be used to make one thread wait until <em>N</em> threads have
+ * completed some action, or some action has been completed N times.
+ *
+ * <p>A useful property of a {@code CountDownLatch} is that it
+ * doesn't require that threads calling {@code countDown} wait for
+ * the count to reach zero before proceeding, it simply prevents any
+ * thread from proceeding past an {@link #await await} until all
+ * threads could pass.
+ *
+ * <p><b>Sample usage:</b> Here is a pair of classes in which a group
+ * of worker threads use two countdown latches:
+ * <ul>
+ * <li>The first is a start signal that prevents any worker from proceeding
+ * until the driver is ready for them to proceed;
+ * <li>The second is a completion signal that allows the driver to wait
+ * until all workers have completed.
+ * </ul>
+ *
+ * <pre> {@code
+ * class Driver { // ...
+ *   void main() throws InterruptedException {
+ *     CountDownLatch startSignal = new CountDownLatch(1);
+ *     CountDownLatch doneSignal = new CountDownLatch(N);
+ *
+ *     for (int i = 0; i < N; ++i) // create and start threads
+ *       new Thread(new Worker(startSignal, doneSignal)).start();
+ *
+ *     doSomethingElse();            // don't let run yet
+ *     startSignal.countDown();      // let all threads proceed
+ *     doSomethingElse();
+ *     doneSignal.await();           // wait for all to finish
+ *   }
+ * }
+ *
+ * class Worker implements Runnable {
+ *   private final CountDownLatch startSignal;
+ *   private final CountDownLatch doneSignal;
+ *   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
+ *     this.startSignal = startSignal;
+ *     this.doneSignal = doneSignal;
+ *   }
+ *   public void run() {
+ *     try {
+ *       startSignal.await();
+ *       doWork();
+ *       doneSignal.countDown();
+ *     } catch (InterruptedException ex) {} // return;
+ *   }
+ *
+ *   void doWork() { ... }
+ * }}</pre>
+ *
+ * <p>Another typical usage would be to divide a problem into N parts,
+ * describe each part with a Runnable that executes that portion and
+ * counts down on the latch, and queue all the Runnables to an
+ * Executor.  When all sub-parts are complete, the coordinating thread
+ * will be able to pass through await. (When threads must repeatedly
+ * count down in this way, instead use a {@link CyclicBarrier}.)
+ *
+ * <pre> {@code
+ * class Driver2 { // ...
+ *   void main() throws InterruptedException {
+ *     CountDownLatch doneSignal = new CountDownLatch(N);
+ *     Executor e = ...
+ *
+ *     for (int i = 0; i < N; ++i) // create and start threads
+ *       e.execute(new WorkerRunnable(doneSignal, i));
+ *
+ *     doneSignal.await();           // wait for all to finish
+ *   }
+ * }
+ *
+ * class WorkerRunnable implements Runnable {
+ *   private final CountDownLatch doneSignal;
+ *   private final int i;
+ *   WorkerRunnable(CountDownLatch doneSignal, int i) {
+ *     this.doneSignal = doneSignal;
+ *     this.i = i;
+ *   }
+ *   public void run() {
+ *     try {
+ *       doWork(i);
+ *       doneSignal.countDown();
+ *     } catch (InterruptedException ex) {} // return;
+ *   }
+ *
+ *   void doWork() { ... }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: Until the count reaches
+ * zero, actions in a thread prior to calling
+ * {@code countDown()}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions following a successful return from a corresponding
+ * {@code await()} in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class CountDownLatch {
+    /**
+     * Synchronization control For CountDownLatch.
+     * Uses AQS state to represent count.
+     */
+    private static final class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = 4982264981922014374L;
+
+        Sync(int count) {
+            setState(count);
+        }
+
+        int getCount() {
+            return getState();
+        }
+
+        protected int tryAcquireShared(int acquires) {
+            return (getState() == 0) ? 1 : -1;
+        }
+
+        protected boolean tryReleaseShared(int releases) {
+            // Decrement count; signal when transition to zero
+            for (;;) {
+                int c = getState();
+                if (c == 0)
+                    return false;
+                int nextc = c - 1;
+                if (compareAndSetState(c, nextc))
+                    return nextc == 0;
+            }
+        }
+    }
+
+    private final Sync sync;
+
+    /**
+     * Constructs a {@code CountDownLatch} initialized with the given count.
+     *
+     * @param count the number of times {@link #countDown} must be invoked
+     *        before threads can pass through {@link #await}
+     * @throws IllegalArgumentException if {@code count} is negative
+     */
+    public CountDownLatch(int count) {
+        if (count < 0) throw new IllegalArgumentException("count < 0");
+        this.sync = new Sync(count);
+    }
+
+    /**
+     * Causes the current thread to wait until the latch has counted down to
+     * zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>If the current count is zero then this method returns immediately.
+     *
+     * <p>If the current count is greater than zero then the current
+     * thread becomes disabled for thread scheduling purposes and lies
+     * dormant until one of two things happen:
+     * <ul>
+     * <li>The count reaches zero due to invocations of the
+     * {@link #countDown} method; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     *         while waiting
+     */
+    public void await() throws InterruptedException {
+        sync.acquireSharedInterruptibly(1);
+    }
+
+    /**
+     * Causes the current thread to wait until the latch has counted down to
+     * zero, unless the thread is {@linkplain Thread#interrupt interrupted},
+     * or the specified waiting time elapses.
+     *
+     * <p>If the current count is zero then this method returns immediately
+     * with the value {@code true}.
+     *
+     * <p>If the current count is greater than zero then the current
+     * thread becomes disabled for thread scheduling purposes and lies
+     * dormant until one of three things happen:
+     * <ul>
+     * <li>The count reaches zero due to invocations of the
+     * {@link #countDown} method; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     *
+     * <p>If the count reaches zero then the method returns with the
+     * value {@code true}.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the {@code timeout} argument
+     * @return {@code true} if the count reached zero and {@code false}
+     *         if the waiting time elapsed before the count reached zero
+     * @throws InterruptedException if the current thread is interrupted
+     *         while waiting
+     */
+    public boolean await(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
+    }
+
+    /**
+     * Decrements the count of the latch, releasing all waiting threads if
+     * the count reaches zero.
+     *
+     * <p>If the current count is greater than zero then it is decremented.
+     * If the new count is zero then all waiting threads are re-enabled for
+     * thread scheduling purposes.
+     *
+     * <p>If the current count equals zero then nothing happens.
+     */
+    public void countDown() {
+        sync.releaseShared(1);
+    }
+
+    /**
+     * Returns the current count.
+     *
+     * <p>This method is typically used for debugging and testing purposes.
+     *
+     * @return the current count
+     */
+    public long getCount() {
+        return sync.getCount();
+    }
+
+    /**
+     * Returns a string identifying this latch, as well as its state.
+     * The state, in brackets, includes the String {@code "Count ="}
+     * followed by the current count.
+     *
+     * @return a string identifying this latch, as well as its state
+     */
+    public String toString() {
+        return super.toString() + "[Count = " + sync.getCount() + "]";
+    }
+}
diff --git a/java/util/concurrent/CountedCompleter.java b/java/util/concurrent/CountedCompleter.java
new file mode 100644
index 0000000..a29208e
--- /dev/null
+++ b/java/util/concurrent/CountedCompleter.java
@@ -0,0 +1,767 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link ForkJoinTask} with a completion action performed when
+ * triggered and there are no remaining pending actions.
+ * CountedCompleters are in general more robust in the
+ * presence of subtask stalls and blockage than are other forms of
+ * ForkJoinTasks, but are less intuitive to program.  Uses of
+ * CountedCompleter are similar to those of other completion based
+ * components (such as {@link java.nio.channels.CompletionHandler})
+ * except that multiple <em>pending</em> completions may be necessary
+ * to trigger the completion action {@link #onCompletion(CountedCompleter)},
+ * not just one.
+ * Unless initialized otherwise, the {@linkplain #getPendingCount pending
+ * count} starts at zero, but may be (atomically) changed using
+ * methods {@link #setPendingCount}, {@link #addToPendingCount}, and
+ * {@link #compareAndSetPendingCount}. Upon invocation of {@link
+ * #tryComplete}, if the pending action count is nonzero, it is
+ * decremented; otherwise, the completion action is performed, and if
+ * this completer itself has a completer, the process is continued
+ * with its completer.  As is the case with related synchronization
+ * components such as {@link java.util.concurrent.Phaser Phaser} and
+ * {@link java.util.concurrent.Semaphore Semaphore}, these methods
+ * affect only internal counts; they do not establish any further
+ * internal bookkeeping. In particular, the identities of pending
+ * tasks are not maintained. As illustrated below, you can create
+ * subclasses that do record some or all pending tasks or their
+ * results when needed.  As illustrated below, utility methods
+ * supporting customization of completion traversals are also
+ * provided. However, because CountedCompleters provide only basic
+ * synchronization mechanisms, it may be useful to create further
+ * abstract subclasses that maintain linkages, fields, and additional
+ * support methods appropriate for a set of related usages.
+ *
+ * <p>A concrete CountedCompleter class must define method {@link
+ * #compute}, that should in most cases (as illustrated below), invoke
+ * {@code tryComplete()} once before returning. The class may also
+ * optionally override method {@link #onCompletion(CountedCompleter)}
+ * to perform an action upon normal completion, and method
+ * {@link #onExceptionalCompletion(Throwable, CountedCompleter)} to
+ * perform an action upon any exception.
+ *
+ * <p>CountedCompleters most often do not bear results, in which case
+ * they are normally declared as {@code CountedCompleter<Void>}, and
+ * will always return {@code null} as a result value.  In other cases,
+ * you should override method {@link #getRawResult} to provide a
+ * result from {@code join(), invoke()}, and related methods.  In
+ * general, this method should return the value of a field (or a
+ * function of one or more fields) of the CountedCompleter object that
+ * holds the result upon completion. Method {@link #setRawResult} by
+ * default plays no role in CountedCompleters.  It is possible, but
+ * rarely applicable, to override this method to maintain other
+ * objects or fields holding result data.
+ *
+ * <p>A CountedCompleter that does not itself have a completer (i.e.,
+ * one for which {@link #getCompleter} returns {@code null}) can be
+ * used as a regular ForkJoinTask with this added functionality.
+ * However, any completer that in turn has another completer serves
+ * only as an internal helper for other computations, so its own task
+ * status (as reported in methods such as {@link ForkJoinTask#isDone})
+ * is arbitrary; this status changes only upon explicit invocations of
+ * {@link #complete}, {@link ForkJoinTask#cancel},
+ * {@link ForkJoinTask#completeExceptionally(Throwable)} or upon
+ * exceptional completion of method {@code compute}. Upon any
+ * exceptional completion, the exception may be relayed to a task's
+ * completer (and its completer, and so on), if one exists and it has
+ * not otherwise already completed. Similarly, cancelling an internal
+ * CountedCompleter has only a local effect on that completer, so is
+ * not often useful.
+ *
+ * <p><b>Sample Usages.</b>
+ *
+ * <p><b>Parallel recursive decomposition.</b> CountedCompleters may
+ * be arranged in trees similar to those often used with {@link
+ * RecursiveAction}s, although the constructions involved in setting
+ * them up typically vary. Here, the completer of each task is its
+ * parent in the computation tree. Even though they entail a bit more
+ * bookkeeping, CountedCompleters may be better choices when applying
+ * a possibly time-consuming operation (that cannot be further
+ * subdivided) to each element of an array or collection; especially
+ * when the operation takes a significantly different amount of time
+ * to complete for some elements than others, either because of
+ * intrinsic variation (for example I/O) or auxiliary effects such as
+ * garbage collection.  Because CountedCompleters provide their own
+ * continuations, other threads need not block waiting to perform
+ * them.
+ *
+ * <p>For example, here is an initial version of a class that uses
+ * divide-by-two recursive decomposition to divide work into single
+ * pieces (leaf tasks). Even when work is split into individual calls,
+ * tree-based techniques are usually preferable to directly forking
+ * leaf tasks, because they reduce inter-thread communication and
+ * improve load balancing. In the recursive case, the second of each
+ * pair of subtasks to finish triggers completion of its parent
+ * (because no result combination is performed, the default no-op
+ * implementation of method {@code onCompletion} is not overridden).
+ * A static utility method sets up the base task and invokes it
+ * (here, implicitly using the {@link ForkJoinPool#commonPool()}).
+ *
+ * <pre> {@code
+ * class MyOperation<E> { void apply(E e) { ... }  }
+ *
+ * class ForEach<E> extends CountedCompleter<Void> {
+ *
+ *   public static <E> void forEach(E[] array, MyOperation<E> op) {
+ *     new ForEach<E>(null, array, op, 0, array.length).invoke();
+ *   }
+ *
+ *   final E[] array; final MyOperation<E> op; final int lo, hi;
+ *   ForEach(CountedCompleter<?> p, E[] array, MyOperation<E> op, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.op = op; this.lo = lo; this.hi = hi;
+ *   }
+ *
+ *   public void compute() { // version 1
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       setPendingCount(2); // must set pending count before fork
+ *       new ForEach(this, array, op, mid, hi).fork(); // right child
+ *       new ForEach(this, array, op, lo, mid).fork(); // left child
+ *     }
+ *     else if (hi > lo)
+ *       op.apply(array[lo]);
+ *     tryComplete();
+ *   }
+ * }}</pre>
+ *
+ * This design can be improved by noticing that in the recursive case,
+ * the task has nothing to do after forking its right task, so can
+ * directly invoke its left task before returning. (This is an analog
+ * of tail recursion removal.)  Also, because the task returns upon
+ * executing its left task (rather than falling through to invoke
+ * {@code tryComplete}) the pending count is set to one:
+ *
+ * <pre> {@code
+ * class ForEach<E> ... {
+ *   ...
+ *   public void compute() { // version 2
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       setPendingCount(1); // only one pending
+ *       new ForEach(this, array, op, mid, hi).fork(); // right child
+ *       new ForEach(this, array, op, lo, mid).compute(); // direct invoke
+ *     }
+ *     else {
+ *       if (hi > lo)
+ *         op.apply(array[lo]);
+ *       tryComplete();
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * As a further optimization, notice that the left task need not even exist.
+ * Instead of creating a new one, we can iterate using the original task,
+ * and add a pending count for each fork.  Additionally, because no task
+ * in this tree implements an {@link #onCompletion(CountedCompleter)} method,
+ * {@code tryComplete()} can be replaced with {@link #propagateCompletion}.
+ *
+ * <pre> {@code
+ * class ForEach<E> ... {
+ *   ...
+ *   public void compute() { // version 3
+ *     int l = lo, h = hi;
+ *     while (h - l >= 2) {
+ *       int mid = (l + h) >>> 1;
+ *       addToPendingCount(1);
+ *       new ForEach(this, array, op, mid, h).fork(); // right child
+ *       h = mid;
+ *     }
+ *     if (h > l)
+ *       op.apply(array[l]);
+ *     propagateCompletion();
+ *   }
+ * }}</pre>
+ *
+ * Additional optimizations of such classes might entail precomputing
+ * pending counts so that they can be established in constructors,
+ * specializing classes for leaf steps, subdividing by say, four,
+ * instead of two per iteration, and using an adaptive threshold
+ * instead of always subdividing down to single elements.
+ *
+ * <p><b>Searching.</b> A tree of CountedCompleters can search for a
+ * value or property in different parts of a data structure, and
+ * report a result in an {@link
+ * java.util.concurrent.atomic.AtomicReference AtomicReference} as
+ * soon as one is found. The others can poll the result to avoid
+ * unnecessary work. (You could additionally {@linkplain #cancel
+ * cancel} other tasks, but it is usually simpler and more efficient
+ * to just let them notice that the result is set and if so skip
+ * further processing.)  Illustrating again with an array using full
+ * partitioning (again, in practice, leaf tasks will almost always
+ * process more than one element):
+ *
+ * <pre> {@code
+ * class Searcher<E> extends CountedCompleter<E> {
+ *   final E[] array; final AtomicReference<E> result; final int lo, hi;
+ *   Searcher(CountedCompleter<?> p, E[] array, AtomicReference<E> result, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.result = result; this.lo = lo; this.hi = hi;
+ *   }
+ *   public E getRawResult() { return result.get(); }
+ *   public void compute() { // similar to ForEach version 3
+ *     int l = lo, h = hi;
+ *     while (result.get() == null && h >= l) {
+ *       if (h - l >= 2) {
+ *         int mid = (l + h) >>> 1;
+ *         addToPendingCount(1);
+ *         new Searcher(this, array, result, mid, h).fork();
+ *         h = mid;
+ *       }
+ *       else {
+ *         E x = array[l];
+ *         if (matches(x) && result.compareAndSet(null, x))
+ *           quietlyCompleteRoot(); // root task is now joinable
+ *         break;
+ *       }
+ *     }
+ *     tryComplete(); // normally complete whether or not found
+ *   }
+ *   boolean matches(E e) { ... } // return true if found
+ *
+ *   public static <E> E search(E[] array) {
+ *       return new Searcher<E>(null, array, new AtomicReference<E>(), 0, array.length).invoke();
+ *   }
+ * }}</pre>
+ *
+ * In this example, as well as others in which tasks have no other
+ * effects except to {@code compareAndSet} a common result, the
+ * trailing unconditional invocation of {@code tryComplete} could be
+ * made conditional ({@code if (result.get() == null) tryComplete();})
+ * because no further bookkeeping is required to manage completions
+ * once the root task completes.
+ *
+ * <p><b>Recording subtasks.</b> CountedCompleter tasks that combine
+ * results of multiple subtasks usually need to access these results
+ * in method {@link #onCompletion(CountedCompleter)}. As illustrated in the following
+ * class (that performs a simplified form of map-reduce where mappings
+ * and reductions are all of type {@code E}), one way to do this in
+ * divide and conquer designs is to have each subtask record its
+ * sibling, so that it can be accessed in method {@code onCompletion}.
+ * This technique applies to reductions in which the order of
+ * combining left and right results does not matter; ordered
+ * reductions require explicit left/right designations.  Variants of
+ * other streamlinings seen in the above examples may also apply.
+ *
+ * <pre> {@code
+ * class MyMapper<E> { E apply(E v) {  ...  } }
+ * class MyReducer<E> { E apply(E x, E y) {  ...  } }
+ * class MapReducer<E> extends CountedCompleter<E> {
+ *   final E[] array; final MyMapper<E> mapper;
+ *   final MyReducer<E> reducer; final int lo, hi;
+ *   MapReducer<E> sibling;
+ *   E result;
+ *   MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
+ *              MyReducer<E> reducer, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.mapper = mapper;
+ *     this.reducer = reducer; this.lo = lo; this.hi = hi;
+ *   }
+ *   public void compute() {
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       MapReducer<E> left = new MapReducer(this, array, mapper, reducer, lo, mid);
+ *       MapReducer<E> right = new MapReducer(this, array, mapper, reducer, mid, hi);
+ *       left.sibling = right;
+ *       right.sibling = left;
+ *       setPendingCount(1); // only right is pending
+ *       right.fork();
+ *       left.compute();     // directly execute left
+ *     }
+ *     else {
+ *       if (hi > lo)
+ *           result = mapper.apply(array[lo]);
+ *       tryComplete();
+ *     }
+ *   }
+ *   public void onCompletion(CountedCompleter<?> caller) {
+ *     if (caller != this) {
+ *       MapReducer<E> child = (MapReducer<E>)caller;
+ *       MapReducer<E> sib = child.sibling;
+ *       if (sib == null || sib.result == null)
+ *         result = child.result;
+ *       else
+ *         result = reducer.apply(child.result, sib.result);
+ *     }
+ *   }
+ *   public E getRawResult() { return result; }
+ *
+ *   public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
+ *     return new MapReducer<E>(null, array, mapper, reducer,
+ *                              0, array.length).invoke();
+ *   }
+ * }}</pre>
+ *
+ * Here, method {@code onCompletion} takes a form common to many
+ * completion designs that combine results. This callback-style method
+ * is triggered once per task, in either of the two different contexts
+ * in which the pending count is, or becomes, zero: (1) by a task
+ * itself, if its pending count is zero upon invocation of {@code
+ * tryComplete}, or (2) by any of its subtasks when they complete and
+ * decrement the pending count to zero. The {@code caller} argument
+ * distinguishes cases.  Most often, when the caller is {@code this},
+ * no action is necessary. Otherwise the caller argument can be used
+ * (usually via a cast) to supply a value (and/or links to other
+ * values) to be combined.  Assuming proper use of pending counts, the
+ * actions inside {@code onCompletion} occur (once) upon completion of
+ * a task and its subtasks. No additional synchronization is required
+ * within this method to ensure thread safety of accesses to fields of
+ * this task or other completed tasks.
+ *
+ * <p><b>Completion Traversals</b>. If using {@code onCompletion} to
+ * process completions is inapplicable or inconvenient, you can use
+ * methods {@link #firstComplete} and {@link #nextComplete} to create
+ * custom traversals.  For example, to define a MapReducer that only
+ * splits out right-hand tasks in the form of the third ForEach
+ * example, the completions must cooperatively reduce along
+ * unexhausted subtask links, which can be done as follows:
+ *
+ * <pre> {@code
+ * class MapReducer<E> extends CountedCompleter<E> { // version 2
+ *   final E[] array; final MyMapper<E> mapper;
+ *   final MyReducer<E> reducer; final int lo, hi;
+ *   MapReducer<E> forks, next; // record subtask forks in list
+ *   E result;
+ *   MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
+ *              MyReducer<E> reducer, int lo, int hi, MapReducer<E> next) {
+ *     super(p);
+ *     this.array = array; this.mapper = mapper;
+ *     this.reducer = reducer; this.lo = lo; this.hi = hi;
+ *     this.next = next;
+ *   }
+ *   public void compute() {
+ *     int l = lo, h = hi;
+ *     while (h - l >= 2) {
+ *       int mid = (l + h) >>> 1;
+ *       addToPendingCount(1);
+ *       (forks = new MapReducer(this, array, mapper, reducer, mid, h, forks)).fork();
+ *       h = mid;
+ *     }
+ *     if (h > l)
+ *       result = mapper.apply(array[l]);
+ *     // process completions by reducing along and advancing subtask links
+ *     for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ *       for (MapReducer t = (MapReducer)c, s = t.forks; s != null; s = t.forks = s.next)
+ *         t.result = reducer.apply(t.result, s.result);
+ *     }
+ *   }
+ *   public E getRawResult() { return result; }
+ *
+ *   public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
+ *     return new MapReducer<E>(null, array, mapper, reducer,
+ *                              0, array.length, null).invoke();
+ *   }
+ * }}</pre>
+ *
+ * <p><b>Triggers.</b> Some CountedCompleters are themselves never
+ * forked, but instead serve as bits of plumbing in other designs;
+ * including those in which the completion of one or more async tasks
+ * triggers another async task. For example:
+ *
+ * <pre> {@code
+ * class HeaderBuilder extends CountedCompleter<...> { ... }
+ * class BodyBuilder extends CountedCompleter<...> { ... }
+ * class PacketSender extends CountedCompleter<...> {
+ *   PacketSender(...) { super(null, 1); ... } // trigger on second completion
+ *   public void compute() { } // never called
+ *   public void onCompletion(CountedCompleter<?> caller) { sendPacket(); }
+ * }
+ * // sample use:
+ * PacketSender p = new PacketSender();
+ * new HeaderBuilder(p, ...).fork();
+ * new BodyBuilder(p, ...).fork();}</pre>
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
+    private static final long serialVersionUID = 5232453752276485070L;
+
+    /** This task's completer, or null if none */
+    final CountedCompleter<?> completer;
+    /** The number of pending tasks until completion */
+    volatile int pending;
+
+    /**
+     * Creates a new CountedCompleter with the given completer
+     * and initial pending count.
+     *
+     * @param completer this task's completer, or {@code null} if none
+     * @param initialPendingCount the initial pending count
+     */
+    protected CountedCompleter(CountedCompleter<?> completer,
+                               int initialPendingCount) {
+        this.completer = completer;
+        this.pending = initialPendingCount;
+    }
+
+    /**
+     * Creates a new CountedCompleter with the given completer
+     * and an initial pending count of zero.
+     *
+     * @param completer this task's completer, or {@code null} if none
+     */
+    protected CountedCompleter(CountedCompleter<?> completer) {
+        this.completer = completer;
+    }
+
+    /**
+     * Creates a new CountedCompleter with no completer
+     * and an initial pending count of zero.
+     */
+    protected CountedCompleter() {
+        this.completer = null;
+    }
+
+    /**
+     * The main computation performed by this task.
+     */
+    public abstract void compute();
+
+    /**
+     * Performs an action when method {@link #tryComplete} is invoked
+     * and the pending count is zero, or when the unconditional
+     * method {@link #complete} is invoked.  By default, this method
+     * does nothing. You can distinguish cases by checking the
+     * identity of the given caller argument. If not equal to {@code
+     * this}, then it is typically a subtask that may contain results
+     * (and/or links to other results) to combine.
+     *
+     * @param caller the task invoking this method (which may
+     * be this task itself)
+     */
+    public void onCompletion(CountedCompleter<?> caller) {
+    }
+
+    /**
+     * Performs an action when method {@link
+     * #completeExceptionally(Throwable)} is invoked or method {@link
+     * #compute} throws an exception, and this task has not already
+     * otherwise completed normally. On entry to this method, this task
+     * {@link ForkJoinTask#isCompletedAbnormally}.  The return value
+     * of this method controls further propagation: If {@code true}
+     * and this task has a completer that has not completed, then that
+     * completer is also completed exceptionally, with the same
+     * exception as this completer.  The default implementation of
+     * this method does nothing except return {@code true}.
+     *
+     * @param ex the exception
+     * @param caller the task invoking this method (which may
+     * be this task itself)
+     * @return {@code true} if this exception should be propagated to this
+     * task's completer, if one exists
+     */
+    public boolean onExceptionalCompletion(Throwable ex, CountedCompleter<?> caller) {
+        return true;
+    }
+
+    /**
+     * Returns the completer established in this task's constructor,
+     * or {@code null} if none.
+     *
+     * @return the completer
+     */
+    public final CountedCompleter<?> getCompleter() {
+        return completer;
+    }
+
+    /**
+     * Returns the current pending count.
+     *
+     * @return the current pending count
+     */
+    public final int getPendingCount() {
+        return pending;
+    }
+
+    /**
+     * Sets the pending count to the given value.
+     *
+     * @param count the count
+     */
+    public final void setPendingCount(int count) {
+        pending = count;
+    }
+
+    /**
+     * Adds (atomically) the given value to the pending count.
+     *
+     * @param delta the value to add
+     */
+    public final void addToPendingCount(int delta) {
+        U.getAndAddInt(this, PENDING, delta);
+    }
+
+    /**
+     * Sets (atomically) the pending count to the given count only if
+     * it currently holds the given expected value.
+     *
+     * @param expected the expected value
+     * @param count the new value
+     * @return {@code true} if successful
+     */
+    public final boolean compareAndSetPendingCount(int expected, int count) {
+        return U.compareAndSwapInt(this, PENDING, expected, count);
+    }
+
+    /**
+     * If the pending count is nonzero, (atomically) decrements it.
+     *
+     * @return the initial (undecremented) pending count holding on entry
+     * to this method
+     */
+    public final int decrementPendingCountUnlessZero() {
+        int c;
+        do {} while ((c = pending) != 0 &&
+                     !U.compareAndSwapInt(this, PENDING, c, c - 1));
+        return c;
+    }
+
+    /**
+     * Returns the root of the current computation; i.e., this
+     * task if it has no completer, else its completer's root.
+     *
+     * @return the root of the current computation
+     */
+    public final CountedCompleter<?> getRoot() {
+        CountedCompleter<?> a = this, p;
+        while ((p = a.completer) != null)
+            a = p;
+        return a;
+    }
+
+    /**
+     * If the pending count is nonzero, decrements the count;
+     * otherwise invokes {@link #onCompletion(CountedCompleter)}
+     * and then similarly tries to complete this task's completer,
+     * if one exists, else marks this task as complete.
+     */
+    public final void tryComplete() {
+        CountedCompleter<?> a = this, s = a;
+        for (int c;;) {
+            if ((c = a.pending) == 0) {
+                a.onCompletion(s);
+                if ((a = (s = a).completer) == null) {
+                    s.quietlyComplete();
+                    return;
+                }
+            }
+            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+                return;
+        }
+    }
+
+    /**
+     * Equivalent to {@link #tryComplete} but does not invoke {@link
+     * #onCompletion(CountedCompleter)} along the completion path:
+     * If the pending count is nonzero, decrements the count;
+     * otherwise, similarly tries to complete this task's completer, if
+     * one exists, else marks this task as complete. This method may be
+     * useful in cases where {@code onCompletion} should not, or need
+     * not, be invoked for each completer in a computation.
+     */
+    public final void propagateCompletion() {
+        CountedCompleter<?> a = this, s = a;
+        for (int c;;) {
+            if ((c = a.pending) == 0) {
+                if ((a = (s = a).completer) == null) {
+                    s.quietlyComplete();
+                    return;
+                }
+            }
+            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+                return;
+        }
+    }
+
+    /**
+     * Regardless of pending count, invokes
+     * {@link #onCompletion(CountedCompleter)}, marks this task as
+     * complete and further triggers {@link #tryComplete} on this
+     * task's completer, if one exists.  The given rawResult is
+     * used as an argument to {@link #setRawResult} before invoking
+     * {@link #onCompletion(CountedCompleter)} or marking this task
+     * as complete; its value is meaningful only for classes
+     * overriding {@code setRawResult}.  This method does not modify
+     * the pending count.
+     *
+     * <p>This method may be useful when forcing completion as soon as
+     * any one (versus all) of several subtask results are obtained.
+     * However, in the common (and recommended) case in which {@code
+     * setRawResult} is not overridden, this effect can be obtained
+     * more simply using {@link #quietlyCompleteRoot()}.
+     *
+     * @param rawResult the raw result
+     */
+    public void complete(T rawResult) {
+        CountedCompleter<?> p;
+        setRawResult(rawResult);
+        onCompletion(this);
+        quietlyComplete();
+        if ((p = completer) != null)
+            p.tryComplete();
+    }
+
+    /**
+     * If this task's pending count is zero, returns this task;
+     * otherwise decrements its pending count and returns {@code null}.
+     * This method is designed to be used with {@link #nextComplete} in
+     * completion traversal loops.
+     *
+     * @return this task, if pending count was zero, else {@code null}
+     */
+    public final CountedCompleter<?> firstComplete() {
+        for (int c;;) {
+            if ((c = pending) == 0)
+                return this;
+            else if (U.compareAndSwapInt(this, PENDING, c, c - 1))
+                return null;
+        }
+    }
+
+    /**
+     * If this task does not have a completer, invokes {@link
+     * ForkJoinTask#quietlyComplete} and returns {@code null}.  Or, if
+     * the completer's pending count is non-zero, decrements that
+     * pending count and returns {@code null}.  Otherwise, returns the
+     * completer.  This method can be used as part of a completion
+     * traversal loop for homogeneous task hierarchies:
+     *
+     * <pre> {@code
+     * for (CountedCompleter<?> c = firstComplete();
+     *      c != null;
+     *      c = c.nextComplete()) {
+     *   // ... process c ...
+     * }}</pre>
+     *
+     * @return the completer, or {@code null} if none
+     */
+    public final CountedCompleter<?> nextComplete() {
+        CountedCompleter<?> p;
+        if ((p = completer) != null)
+            return p.firstComplete();
+        else {
+            quietlyComplete();
+            return null;
+        }
+    }
+
+    /**
+     * Equivalent to {@code getRoot().quietlyComplete()}.
+     */
+    public final void quietlyCompleteRoot() {
+        for (CountedCompleter<?> a = this, p;;) {
+            if ((p = a.completer) == null) {
+                a.quietlyComplete();
+                return;
+            }
+            a = p;
+        }
+    }
+
+    /**
+     * If this task has not completed, attempts to process at most the
+     * given number of other unprocessed tasks for which this task is
+     * on the completion path, if any are known to exist.
+     *
+     * @param maxTasks the maximum number of tasks to process.  If
+     *                 less than or equal to zero, then no tasks are
+     *                 processed.
+     */
+    public final void helpComplete(int maxTasks) {
+        Thread t; ForkJoinWorkerThread wt;
+        if (maxTasks > 0 && status >= 0) {
+            if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+                (wt = (ForkJoinWorkerThread)t).pool.
+                    helpComplete(wt.workQueue, this, maxTasks);
+            else
+                ForkJoinPool.common.externalHelpComplete(this, maxTasks);
+        }
+    }
+
+    /**
+     * Supports ForkJoinTask exception propagation.
+     */
+    void internalPropagateException(Throwable ex) {
+        CountedCompleter<?> a = this, s = a;
+        while (a.onExceptionalCompletion(ex, s) &&
+               (a = (s = a).completer) != null && a.status >= 0 &&
+               a.recordExceptionalCompletion(ex) == EXCEPTIONAL)
+            ;
+    }
+
+    /**
+     * Implements execution conventions for CountedCompleters.
+     */
+    protected final boolean exec() {
+        compute();
+        return false;
+    }
+
+    /**
+     * Returns the result of the computation.  By default,
+     * returns {@code null}, which is appropriate for {@code Void}
+     * actions, but in other cases should be overridden, almost
+     * always to return a field or function of a field that
+     * holds the result upon completion.
+     *
+     * @return the result of the computation
+     */
+    public T getRawResult() { return null; }
+
+    /**
+     * A method that result-bearing CountedCompleters may optionally
+     * use to help maintain result data.  By default, does nothing.
+     * Overrides are not recommended. However, if this method is
+     * overridden to update existing objects or fields, then it must
+     * in general be defined to be thread-safe.
+     */
+    protected void setRawResult(T t) { }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long PENDING;
+    static {
+        try {
+            PENDING = U.objectFieldOffset
+                (CountedCompleter.class.getDeclaredField("pending"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/CyclicBarrier.java b/java/util/concurrent/CyclicBarrier.java
new file mode 100644
index 0000000..5e018f1
--- /dev/null
+++ b/java/util/concurrent/CyclicBarrier.java
@@ -0,0 +1,492 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * A synchronization aid that allows a set of threads to all wait for
+ * each other to reach a common barrier point.  CyclicBarriers are
+ * useful in programs involving a fixed sized party of threads that
+ * must occasionally wait for each other. The barrier is called
+ * <em>cyclic</em> because it can be re-used after the waiting threads
+ * are released.
+ *
+ * <p>A {@code CyclicBarrier} supports an optional {@link Runnable} command
+ * that is run once per barrier point, after the last thread in the party
+ * arrives, but before any threads are released.
+ * This <em>barrier action</em> is useful
+ * for updating shared-state before any of the parties continue.
+ *
+ * <p><b>Sample usage:</b> Here is an example of using a barrier in a
+ * parallel decomposition design:
+ *
+ * <pre> {@code
+ * class Solver {
+ *   final int N;
+ *   final float[][] data;
+ *   final CyclicBarrier barrier;
+ *
+ *   class Worker implements Runnable {
+ *     int myRow;
+ *     Worker(int row) { myRow = row; }
+ *     public void run() {
+ *       while (!done()) {
+ *         processRow(myRow);
+ *
+ *         try {
+ *           barrier.await();
+ *         } catch (InterruptedException ex) {
+ *           return;
+ *         } catch (BrokenBarrierException ex) {
+ *           return;
+ *         }
+ *       }
+ *     }
+ *   }
+ *
+ *   public Solver(float[][] matrix) {
+ *     data = matrix;
+ *     N = matrix.length;
+ *     Runnable barrierAction =
+ *       new Runnable() { public void run() { mergeRows(...); }};
+ *     barrier = new CyclicBarrier(N, barrierAction);
+ *
+ *     List<Thread> threads = new ArrayList<>(N);
+ *     for (int i = 0; i < N; i++) {
+ *       Thread thread = new Thread(new Worker(i));
+ *       threads.add(thread);
+ *       thread.start();
+ *     }
+ *
+ *     // wait until done
+ *     for (Thread thread : threads)
+ *       thread.join();
+ *   }
+ * }}</pre>
+ *
+ * Here, each worker thread processes a row of the matrix then waits at the
+ * barrier until all rows have been processed. When all rows are processed
+ * the supplied {@link Runnable} barrier action is executed and merges the
+ * rows. If the merger
+ * determines that a solution has been found then {@code done()} will return
+ * {@code true} and each worker will terminate.
+ *
+ * <p>If the barrier action does not rely on the parties being suspended when
+ * it is executed, then any of the threads in the party could execute that
+ * action when it is released. To facilitate this, each invocation of
+ * {@link #await} returns the arrival index of that thread at the barrier.
+ * You can then choose which thread should execute the barrier action, for
+ * example:
+ * <pre> {@code
+ * if (barrier.await() == 0) {
+ *   // log the completion of this iteration
+ * }}</pre>
+ *
+ * <p>The {@code CyclicBarrier} uses an all-or-none breakage model
+ * for failed synchronization attempts: If a thread leaves a barrier
+ * point prematurely because of interruption, failure, or timeout, all
+ * other threads waiting at that barrier point will also leave
+ * abnormally via {@link BrokenBarrierException} (or
+ * {@link InterruptedException} if they too were interrupted at about
+ * the same time).
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to calling
+ * {@code await()}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions that are part of the barrier action, which in turn
+ * <i>happen-before</i> actions following a successful return from the
+ * corresponding {@code await()} in other threads.
+ *
+ * @since 1.5
+ * @see CountDownLatch
+ *
+ * @author Doug Lea
+ */
+public class CyclicBarrier {
+    /**
+     * Each use of the barrier is represented as a generation instance.
+     * The generation changes whenever the barrier is tripped, or
+     * is reset. There can be many generations associated with threads
+     * using the barrier - due to the non-deterministic way the lock
+     * may be allocated to waiting threads - but only one of these
+     * can be active at a time (the one to which {@code count} applies)
+     * and all the rest are either broken or tripped.
+     * There need not be an active generation if there has been a break
+     * but no subsequent reset.
+     */
+    private static class Generation {
+        boolean broken;         // initially false
+    }
+
+    /** The lock for guarding barrier entry */
+    private final ReentrantLock lock = new ReentrantLock();
+    /** Condition to wait on until tripped */
+    private final Condition trip = lock.newCondition();
+    /** The number of parties */
+    private final int parties;
+    /** The command to run when tripped */
+    private final Runnable barrierCommand;
+    /** The current generation */
+    private Generation generation = new Generation();
+
+    /**
+     * Number of parties still waiting. Counts down from parties to 0
+     * on each generation.  It is reset to parties on each new
+     * generation or when broken.
+     */
+    private int count;
+
+    /**
+     * Updates state on barrier trip and wakes up everyone.
+     * Called only while holding lock.
+     */
+    private void nextGeneration() {
+        // signal completion of last generation
+        trip.signalAll();
+        // set up next generation
+        count = parties;
+        generation = new Generation();
+    }
+
+    /**
+     * Sets current barrier generation as broken and wakes up everyone.
+     * Called only while holding lock.
+     */
+    private void breakBarrier() {
+        generation.broken = true;
+        count = parties;
+        trip.signalAll();
+    }
+
+    /**
+     * Main barrier code, covering the various policies.
+     */
+    private int dowait(boolean timed, long nanos)
+        throws InterruptedException, BrokenBarrierException,
+               TimeoutException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Generation g = generation;
+
+            if (g.broken)
+                throw new BrokenBarrierException();
+
+            if (Thread.interrupted()) {
+                breakBarrier();
+                throw new InterruptedException();
+            }
+
+            int index = --count;
+            if (index == 0) {  // tripped
+                boolean ranAction = false;
+                try {
+                    final Runnable command = barrierCommand;
+                    if (command != null)
+                        command.run();
+                    ranAction = true;
+                    nextGeneration();
+                    return 0;
+                } finally {
+                    if (!ranAction)
+                        breakBarrier();
+                }
+            }
+
+            // loop until tripped, broken, interrupted, or timed out
+            for (;;) {
+                try {
+                    if (!timed)
+                        trip.await();
+                    else if (nanos > 0L)
+                        nanos = trip.awaitNanos(nanos);
+                } catch (InterruptedException ie) {
+                    if (g == generation && ! g.broken) {
+                        breakBarrier();
+                        throw ie;
+                    } else {
+                        // We're about to finish waiting even if we had not
+                        // been interrupted, so this interrupt is deemed to
+                        // "belong" to subsequent execution.
+                        Thread.currentThread().interrupt();
+                    }
+                }
+
+                if (g.broken)
+                    throw new BrokenBarrierException();
+
+                if (g != generation)
+                    return index;
+
+                if (timed && nanos <= 0L) {
+                    breakBarrier();
+                    throw new TimeoutException();
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Creates a new {@code CyclicBarrier} that will trip when the
+     * given number of parties (threads) are waiting upon it, and which
+     * will execute the given barrier action when the barrier is tripped,
+     * performed by the last thread entering the barrier.
+     *
+     * @param parties the number of threads that must invoke {@link #await}
+     *        before the barrier is tripped
+     * @param barrierAction the command to execute when the barrier is
+     *        tripped, or {@code null} if there is no action
+     * @throws IllegalArgumentException if {@code parties} is less than 1
+     */
+    public CyclicBarrier(int parties, Runnable barrierAction) {
+        if (parties <= 0) throw new IllegalArgumentException();
+        this.parties = parties;
+        this.count = parties;
+        this.barrierCommand = barrierAction;
+    }
+
+    /**
+     * Creates a new {@code CyclicBarrier} that will trip when the
+     * given number of parties (threads) are waiting upon it, and
+     * does not perform a predefined action when the barrier is tripped.
+     *
+     * @param parties the number of threads that must invoke {@link #await}
+     *        before the barrier is tripped
+     * @throws IllegalArgumentException if {@code parties} is less than 1
+     */
+    public CyclicBarrier(int parties) {
+        this(parties, null);
+    }
+
+    /**
+     * Returns the number of parties required to trip this barrier.
+     *
+     * @return the number of parties required to trip this barrier
+     */
+    public int getParties() {
+        return parties;
+    }
+
+    /**
+     * Waits until all {@linkplain #getParties parties} have invoked
+     * {@code await} on this barrier.
+     *
+     * <p>If the current thread is not the last to arrive then it is
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of the following things happens:
+     * <ul>
+     * <li>The last thread arrives; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * one of the other waiting threads; or
+     * <li>Some other thread times out while waiting for barrier; or
+     * <li>Some other thread invokes {@link #reset} on this barrier.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the barrier is {@link #reset} while any thread is waiting,
+     * or if the barrier {@linkplain #isBroken is broken} when
+     * {@code await} is invoked, or while any thread is waiting, then
+     * {@link BrokenBarrierException} is thrown.
+     *
+     * <p>If any thread is {@linkplain Thread#interrupt interrupted} while waiting,
+     * then all other waiting threads will throw
+     * {@link BrokenBarrierException} and the barrier is placed in the broken
+     * state.
+     *
+     * <p>If the current thread is the last thread to arrive, and a
+     * non-null barrier action was supplied in the constructor, then the
+     * current thread runs the action before allowing the other threads to
+     * continue.
+     * If an exception occurs during the barrier action then that exception
+     * will be propagated in the current thread and the barrier is placed in
+     * the broken state.
+     *
+     * @return the arrival index of the current thread, where index
+     *         {@code getParties() - 1} indicates the first
+     *         to arrive and zero indicates the last to arrive
+     * @throws InterruptedException if the current thread was interrupted
+     *         while waiting
+     * @throws BrokenBarrierException if <em>another</em> thread was
+     *         interrupted or timed out while the current thread was
+     *         waiting, or the barrier was reset, or the barrier was
+     *         broken when {@code await} was called, or the barrier
+     *         action (if present) failed due to an exception
+     */
+    public int await() throws InterruptedException, BrokenBarrierException {
+        try {
+            return dowait(false, 0L);
+        } catch (TimeoutException toe) {
+            throw new Error(toe); // cannot happen
+        }
+    }
+
+    /**
+     * Waits until all {@linkplain #getParties parties} have invoked
+     * {@code await} on this barrier, or the specified waiting time elapses.
+     *
+     * <p>If the current thread is not the last to arrive then it is
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of the following things happens:
+     * <ul>
+     * <li>The last thread arrives; or
+     * <li>The specified timeout elapses; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * one of the other waiting threads; or
+     * <li>Some other thread times out while waiting for barrier; or
+     * <li>Some other thread invokes {@link #reset} on this barrier.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then {@link TimeoutException}
+     * is thrown. If the time is less than or equal to zero, the
+     * method will not wait at all.
+     *
+     * <p>If the barrier is {@link #reset} while any thread is waiting,
+     * or if the barrier {@linkplain #isBroken is broken} when
+     * {@code await} is invoked, or while any thread is waiting, then
+     * {@link BrokenBarrierException} is thrown.
+     *
+     * <p>If any thread is {@linkplain Thread#interrupt interrupted} while
+     * waiting, then all other waiting threads will throw {@link
+     * BrokenBarrierException} and the barrier is placed in the broken
+     * state.
+     *
+     * <p>If the current thread is the last thread to arrive, and a
+     * non-null barrier action was supplied in the constructor, then the
+     * current thread runs the action before allowing the other threads to
+     * continue.
+     * If an exception occurs during the barrier action then that exception
+     * will be propagated in the current thread and the barrier is placed in
+     * the broken state.
+     *
+     * @param timeout the time to wait for the barrier
+     * @param unit the time unit of the timeout parameter
+     * @return the arrival index of the current thread, where index
+     *         {@code getParties() - 1} indicates the first
+     *         to arrive and zero indicates the last to arrive
+     * @throws InterruptedException if the current thread was interrupted
+     *         while waiting
+     * @throws TimeoutException if the specified timeout elapses.
+     *         In this case the barrier will be broken.
+     * @throws BrokenBarrierException if <em>another</em> thread was
+     *         interrupted or timed out while the current thread was
+     *         waiting, or the barrier was reset, or the barrier was broken
+     *         when {@code await} was called, or the barrier action (if
+     *         present) failed due to an exception
+     */
+    public int await(long timeout, TimeUnit unit)
+        throws InterruptedException,
+               BrokenBarrierException,
+               TimeoutException {
+        return dowait(true, unit.toNanos(timeout));
+    }
+
+    /**
+     * Queries if this barrier is in a broken state.
+     *
+     * @return {@code true} if one or more parties broke out of this
+     *         barrier due to interruption or timeout since
+     *         construction or the last reset, or a barrier action
+     *         failed due to an exception; {@code false} otherwise.
+     */
+    public boolean isBroken() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return generation.broken;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Resets the barrier to its initial state.  If any parties are
+     * currently waiting at the barrier, they will return with a
+     * {@link BrokenBarrierException}. Note that resets <em>after</em>
+     * a breakage has occurred for other reasons can be complicated to
+     * carry out; threads need to re-synchronize in some other way,
+     * and choose one to perform the reset.  It may be preferable to
+     * instead create a new barrier for subsequent use.
+     */
+    public void reset() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            breakBarrier();   // break the current generation
+            nextGeneration(); // start a new generation
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns the number of parties currently waiting at the barrier.
+     * This method is primarily useful for debugging and assertions.
+     *
+     * @return the number of parties currently blocked in {@link #await}
+     */
+    public int getNumberWaiting() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return parties - count;
+        } finally {
+            lock.unlock();
+        }
+    }
+}
diff --git a/java/util/concurrent/DelayQueue.java b/java/util/concurrent/DelayQueue.java
new file mode 100644
index 0000000..04a83d9
--- /dev/null
+++ b/java/util/concurrent/DelayQueue.java
@@ -0,0 +1,562 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.PriorityQueue;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An unbounded {@linkplain BlockingQueue blocking queue} of
+ * {@code Delayed} elements, in which an element can only be taken
+ * when its delay has expired.  The <em>head</em> of the queue is that
+ * {@code Delayed} element whose delay expired furthest in the
+ * past.  If no delay has expired there is no head and {@code poll}
+ * will return {@code null}. Expiration occurs when an element's
+ * {@code getDelay(TimeUnit.NANOSECONDS)} method returns a value less
+ * than or equal to zero.  Even though unexpired elements cannot be
+ * removed using {@code take} or {@code poll}, they are otherwise
+ * treated as normal elements. For example, the {@code size} method
+ * returns the count of both expired and unexpired elements.
+ * This queue does not permit null elements.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.  The Iterator provided in method {@link
+ * #iterator()} is <em>not</em> guaranteed to traverse the elements of
+ * the DelayQueue in any particular order.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
+    implements BlockingQueue<E> {
+
+    private final transient ReentrantLock lock = new ReentrantLock();
+    private final PriorityQueue<E> q = new PriorityQueue<E>();
+
+    /**
+     * Thread designated to wait for the element at the head of
+     * the queue.  This variant of the Leader-Follower pattern
+     * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to
+     * minimize unnecessary timed waiting.  When a thread becomes
+     * the leader, it waits only for the next delay to elapse, but
+     * other threads await indefinitely.  The leader thread must
+     * signal some other thread before returning from take() or
+     * poll(...), unless some other thread becomes leader in the
+     * interim.  Whenever the head of the queue is replaced with
+     * an element with an earlier expiration time, the leader
+     * field is invalidated by being reset to null, and some
+     * waiting thread, but not necessarily the current leader, is
+     * signalled.  So waiting threads must be prepared to acquire
+     * and lose leadership while waiting.
+     */
+    private Thread leader;
+
+    /**
+     * Condition signalled when a newer element becomes available
+     * at the head of the queue or a new thread may need to
+     * become leader.
+     */
+    private final Condition available = lock.newCondition();
+
+    /**
+     * Creates a new {@code DelayQueue} that is initially empty.
+     */
+    public DelayQueue() {}
+
+    /**
+     * Creates a {@code DelayQueue} initially containing the elements of the
+     * given collection of {@link Delayed} instances.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public DelayQueue(Collection<? extends E> c) {
+        this.addAll(c);
+    }
+
+    /**
+     * Inserts the specified element into this delay queue.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this delay queue.
+     *
+     * @param e the element to add
+     * @return {@code true}
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            q.offer(e);
+            if (q.peek() == e) {
+                leader = null;
+                available.signal();
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element into this delay queue. As the queue is
+     * unbounded this method will never block.
+     *
+     * @param e the element to add
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) {
+        offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this delay queue. As the queue is
+     * unbounded this method will never block.
+     *
+     * @param e the element to add
+     * @param timeout This parameter is ignored as the method never blocks
+     * @param unit This parameter is ignored as the method never blocks
+     * @return {@code true}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit) {
+        return offer(e);
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, or returns {@code null}
+     * if this queue has no elements with an expired delay.
+     *
+     * @return the head of this queue, or {@code null} if this
+     *         queue has no elements with an expired delay
+     */
+    public E poll() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            E first = q.peek();
+            return (first == null || first.getDelay(NANOSECONDS) > 0)
+                ? null
+                : q.poll();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * until an element with an expired delay is available on this queue.
+     *
+     * @return the head of this queue
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E take() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            for (;;) {
+                E first = q.peek();
+                if (first == null)
+                    available.await();
+                else {
+                    long delay = first.getDelay(NANOSECONDS);
+                    if (delay <= 0L)
+                        return q.poll();
+                    first = null; // don't retain ref while waiting
+                    if (leader != null)
+                        available.await();
+                    else {
+                        Thread thisThread = Thread.currentThread();
+                        leader = thisThread;
+                        try {
+                            available.awaitNanos(delay);
+                        } finally {
+                            if (leader == thisThread)
+                                leader = null;
+                        }
+                    }
+                }
+            }
+        } finally {
+            if (leader == null && q.peek() != null)
+                available.signal();
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * until an element with an expired delay is available on this queue,
+     * or the specified wait time expires.
+     *
+     * @return the head of this queue, or {@code null} if the
+     *         specified waiting time elapses before an element with
+     *         an expired delay becomes available
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            for (;;) {
+                E first = q.peek();
+                if (first == null) {
+                    if (nanos <= 0L)
+                        return null;
+                    else
+                        nanos = available.awaitNanos(nanos);
+                } else {
+                    long delay = first.getDelay(NANOSECONDS);
+                    if (delay <= 0L)
+                        return q.poll();
+                    if (nanos <= 0L)
+                        return null;
+                    first = null; // don't retain ref while waiting
+                    if (nanos < delay || leader != null)
+                        nanos = available.awaitNanos(nanos);
+                    else {
+                        Thread thisThread = Thread.currentThread();
+                        leader = thisThread;
+                        try {
+                            long timeLeft = available.awaitNanos(delay);
+                            nanos -= delay - timeLeft;
+                        } finally {
+                            if (leader == thisThread)
+                                leader = null;
+                        }
+                    }
+                }
+            }
+        } finally {
+            if (leader == null && q.peek() != null)
+                available.signal();
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of this queue, or
+     * returns {@code null} if this queue is empty.  Unlike
+     * {@code poll}, if no expired elements are available in the queue,
+     * this method returns the element that will expire next,
+     * if one exists.
+     *
+     * @return the head of this queue, or {@code null} if this
+     *         queue is empty
+     */
+    public E peek() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.peek();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.size();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns first element only if it is expired.
+     * Used only by drainTo.  Call only when holding lock.
+     */
+    private E peekExpired() {
+        // assert lock.isHeldByCurrentThread();
+        E first = q.peek();
+        return (first == null || first.getDelay(NANOSECONDS) > 0) ?
+            null : first;
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = 0;
+            for (E e; (e = peekExpired()) != null;) {
+                c.add(e);       // In this order, in case add() throws.
+                q.poll();
+                ++n;
+            }
+            return n;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = 0;
+            for (E e; n < maxElements && (e = peekExpired()) != null;) {
+                c.add(e);       // In this order, in case add() throws.
+                q.poll();
+                ++n;
+            }
+            return n;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Atomically removes all of the elements from this delay queue.
+     * The queue will be empty after this call returns.
+     * Elements with an unexpired delay are not waited for; they are
+     * simply discarded from the queue.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            q.clear();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Always returns {@code Integer.MAX_VALUE} because
+     * a {@code DelayQueue} is not capacity constrained.
+     *
+     * @return {@code Integer.MAX_VALUE}
+     */
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue.
+     * The returned array elements are in no particular order.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.toArray();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue; the
+     * runtime type of the returned array is that of the specified array.
+     * The returned array elements are in no particular order.
+     * If the queue fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>The following code can be used to dump a delay queue into a newly
+     * allocated array of {@code Delayed}:
+     *
+     * <pre> {@code Delayed[] a = q.toArray(new Delayed[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.toArray(a);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Removes a single instance of the specified element from this
+     * queue, if it is present, whether or not it has expired.
+     */
+    public boolean remove(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.remove(o);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Identity-based version for use in Itr.remove.
+     */
+    void removeEQ(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Iterator<E> it = q.iterator(); it.hasNext(); ) {
+                if (o == it.next()) {
+                    it.remove();
+                    break;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an iterator over all the elements (both expired and
+     * unexpired) in this queue. The iterator does not return the
+     * elements in any particular order.
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue
+     */
+    public Iterator<E> iterator() {
+        return new Itr(toArray());
+    }
+
+    /**
+     * Snapshot iterator that works off copy of underlying q array.
+     */
+    private class Itr implements Iterator<E> {
+        final Object[] array; // Array of all elements
+        int cursor;           // index of next element to return
+        int lastRet;          // index of last element, or -1 if no such
+
+        Itr(Object[] array) {
+            lastRet = -1;
+            this.array = array;
+        }
+
+        public boolean hasNext() {
+            return cursor < array.length;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (cursor >= array.length)
+                throw new NoSuchElementException();
+            lastRet = cursor;
+            return (E)array[cursor++];
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            removeEQ(array[lastRet]);
+            lastRet = -1;
+        }
+    }
+
+}
diff --git a/java/util/concurrent/Delayed.java b/java/util/concurrent/Delayed.java
new file mode 100644
index 0000000..5da1ec8
--- /dev/null
+++ b/java/util/concurrent/Delayed.java
@@ -0,0 +1,60 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A mix-in style interface for marking objects that should be
+ * acted upon after a given delay.
+ *
+ * <p>An implementation of this interface must define a
+ * {@code compareTo} method that provides an ordering consistent with
+ * its {@code getDelay} method.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Delayed extends Comparable<Delayed> {
+
+    /**
+     * Returns the remaining delay associated with this object, in the
+     * given time unit.
+     *
+     * @param unit the time unit
+     * @return the remaining delay; zero or negative values indicate
+     * that the delay has already elapsed
+     */
+    long getDelay(TimeUnit unit);
+}
diff --git a/java/util/concurrent/Exchanger.java b/java/util/concurrent/Exchanger.java
new file mode 100644
index 0000000..f01a705
--- /dev/null
+++ b/java/util/concurrent/Exchanger.java
@@ -0,0 +1,658 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea, Bill Scherer, and Michael Scott with
+ * assistance from members of JCP JSR-166 Expert Group and released to
+ * the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A synchronization point at which threads can pair and swap elements
+ * within pairs.  Each thread presents some object on entry to the
+ * {@link #exchange exchange} method, matches with a partner thread,
+ * and receives its partner's object on return.  An Exchanger may be
+ * viewed as a bidirectional form of a {@link SynchronousQueue}.
+ * Exchangers may be useful in applications such as genetic algorithms
+ * and pipeline designs.
+ *
+ * <p><b>Sample Usage:</b>
+ * Here are the highlights of a class that uses an {@code Exchanger}
+ * to swap buffers between threads so that the thread filling the
+ * buffer gets a freshly emptied one when it needs it, handing off the
+ * filled one to the thread emptying the buffer.
+ * <pre> {@code
+ * class FillAndEmpty {
+ *   Exchanger<DataBuffer> exchanger = new Exchanger<>();
+ *   DataBuffer initialEmptyBuffer = ... a made-up type
+ *   DataBuffer initialFullBuffer = ...
+ *
+ *   class FillingLoop implements Runnable {
+ *     public void run() {
+ *       DataBuffer currentBuffer = initialEmptyBuffer;
+ *       try {
+ *         while (currentBuffer != null) {
+ *           addToBuffer(currentBuffer);
+ *           if (currentBuffer.isFull())
+ *             currentBuffer = exchanger.exchange(currentBuffer);
+ *         }
+ *       } catch (InterruptedException ex) { ... handle ... }
+ *     }
+ *   }
+ *
+ *   class EmptyingLoop implements Runnable {
+ *     public void run() {
+ *       DataBuffer currentBuffer = initialFullBuffer;
+ *       try {
+ *         while (currentBuffer != null) {
+ *           takeFromBuffer(currentBuffer);
+ *           if (currentBuffer.isEmpty())
+ *             currentBuffer = exchanger.exchange(currentBuffer);
+ *         }
+ *       } catch (InterruptedException ex) { ... handle ...}
+ *     }
+ *   }
+ *
+ *   void start() {
+ *     new Thread(new FillingLoop()).start();
+ *     new Thread(new EmptyingLoop()).start();
+ *   }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: For each pair of threads that
+ * successfully exchange objects via an {@code Exchanger}, actions
+ * prior to the {@code exchange()} in each thread
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * those subsequent to a return from the corresponding {@code exchange()}
+ * in the other thread.
+ *
+ * @since 1.5
+ * @author Doug Lea and Bill Scherer and Michael Scott
+ * @param <V> The type of objects that may be exchanged
+ */
+public class Exchanger<V> {
+
+    /*
+     * Overview: The core algorithm is, for an exchange "slot",
+     * and a participant (caller) with an item:
+     *
+     * for (;;) {
+     *   if (slot is empty) {                       // offer
+     *     place item in a Node;
+     *     if (can CAS slot from empty to node) {
+     *       wait for release;
+     *       return matching item in node;
+     *     }
+     *   }
+     *   else if (can CAS slot from node to empty) { // release
+     *     get the item in node;
+     *     set matching item in node;
+     *     release waiting thread;
+     *   }
+     *   // else retry on CAS failure
+     * }
+     *
+     * This is among the simplest forms of a "dual data structure" --
+     * see Scott and Scherer's DISC 04 paper and
+     * http://www.cs.rochester.edu/research/synchronization/pseudocode/duals.html
+     *
+     * This works great in principle. But in practice, like many
+     * algorithms centered on atomic updates to a single location, it
+     * scales horribly when there are more than a few participants
+     * using the same Exchanger. So the implementation instead uses a
+     * form of elimination arena, that spreads out this contention by
+     * arranging that some threads typically use different slots,
+     * while still ensuring that eventually, any two parties will be
+     * able to exchange items. That is, we cannot completely partition
+     * across threads, but instead give threads arena indices that
+     * will on average grow under contention and shrink under lack of
+     * contention. We approach this by defining the Nodes that we need
+     * anyway as ThreadLocals, and include in them per-thread index
+     * and related bookkeeping state. (We can safely reuse per-thread
+     * nodes rather than creating them fresh each time because slots
+     * alternate between pointing to a node vs null, so cannot
+     * encounter ABA problems. However, we do need some care in
+     * resetting them between uses.)
+     *
+     * Implementing an effective arena requires allocating a bunch of
+     * space, so we only do so upon detecting contention (except on
+     * uniprocessors, where they wouldn't help, so aren't used).
+     * Otherwise, exchanges use the single-slot slotExchange method.
+     * On contention, not only must the slots be in different
+     * locations, but the locations must not encounter memory
+     * contention due to being on the same cache line (or more
+     * generally, the same coherence unit).  Because, as of this
+     * writing, there is no way to determine cacheline size, we define
+     * a value that is enough for common platforms.  Additionally,
+     * extra care elsewhere is taken to avoid other false/unintended
+     * sharing and to enhance locality, including adding padding (via
+     * @Contended) to Nodes, embedding "bound" as an Exchanger field,
+     * and reworking some park/unpark mechanics compared to
+     * LockSupport versions.
+     *
+     * The arena starts out with only one used slot. We expand the
+     * effective arena size by tracking collisions; i.e., failed CASes
+     * while trying to exchange. By nature of the above algorithm, the
+     * only kinds of collision that reliably indicate contention are
+     * when two attempted releases collide -- one of two attempted
+     * offers can legitimately fail to CAS without indicating
+     * contention by more than one other thread. (Note: it is possible
+     * but not worthwhile to more precisely detect contention by
+     * reading slot values after CAS failures.)  When a thread has
+     * collided at each slot within the current arena bound, it tries
+     * to expand the arena size by one. We track collisions within
+     * bounds by using a version (sequence) number on the "bound"
+     * field, and conservatively reset collision counts when a
+     * participant notices that bound has been updated (in either
+     * direction).
+     *
+     * The effective arena size is reduced (when there is more than
+     * one slot) by giving up on waiting after a while and trying to
+     * decrement the arena size on expiration. The value of "a while"
+     * is an empirical matter.  We implement by piggybacking on the
+     * use of spin->yield->block that is essential for reasonable
+     * waiting performance anyway -- in a busy exchanger, offers are
+     * usually almost immediately released, in which case context
+     * switching on multiprocessors is extremely slow/wasteful.  Arena
+     * waits just omit the blocking part, and instead cancel. The spin
+     * count is empirically chosen to be a value that avoids blocking
+     * 99% of the time under maximum sustained exchange rates on a
+     * range of test machines. Spins and yields entail some limited
+     * randomness (using a cheap xorshift) to avoid regular patterns
+     * that can induce unproductive grow/shrink cycles. (Using a
+     * pseudorandom also helps regularize spin cycle duration by
+     * making branches unpredictable.)  Also, during an offer, a
+     * waiter can "know" that it will be released when its slot has
+     * changed, but cannot yet proceed until match is set.  In the
+     * mean time it cannot cancel the offer, so instead spins/yields.
+     * Note: It is possible to avoid this secondary check by changing
+     * the linearization point to be a CAS of the match field (as done
+     * in one case in the Scott & Scherer DISC paper), which also
+     * increases asynchrony a bit, at the expense of poorer collision
+     * detection and inability to always reuse per-thread nodes. So
+     * the current scheme is typically a better tradeoff.
+     *
+     * On collisions, indices traverse the arena cyclically in reverse
+     * order, restarting at the maximum index (which will tend to be
+     * sparsest) when bounds change. (On expirations, indices instead
+     * are halved until reaching 0.) It is possible (and has been
+     * tried) to use randomized, prime-value-stepped, or double-hash
+     * style traversal instead of simple cyclic traversal to reduce
+     * bunching.  But empirically, whatever benefits these may have
+     * don't overcome their added overhead: We are managing operations
+     * that occur very quickly unless there is sustained contention,
+     * so simpler/faster control policies work better than more
+     * accurate but slower ones.
+     *
+     * Because we use expiration for arena size control, we cannot
+     * throw TimeoutExceptions in the timed version of the public
+     * exchange method until the arena size has shrunken to zero (or
+     * the arena isn't enabled). This may delay response to timeout
+     * but is still within spec.
+     *
+     * Essentially all of the implementation is in methods
+     * slotExchange and arenaExchange. These have similar overall
+     * structure, but differ in too many details to combine. The
+     * slotExchange method uses the single Exchanger field "slot"
+     * rather than arena array elements. However, it still needs
+     * minimal collision detection to trigger arena construction.
+     * (The messiest part is making sure interrupt status and
+     * InterruptedExceptions come out right during transitions when
+     * both methods may be called. This is done by using null return
+     * as a sentinel to recheck interrupt status.)
+     *
+     * As is too common in this sort of code, methods are monolithic
+     * because most of the logic relies on reads of fields that are
+     * maintained as local variables so can't be nicely factored --
+     * mainly, here, bulky spin->yield->block/cancel code), and
+     * heavily dependent on intrinsics (Unsafe) to use inlined
+     * embedded CAS and related memory access operations (that tend
+     * not to be as readily inlined by dynamic compilers when they are
+     * hidden behind other methods that would more nicely name and
+     * encapsulate the intended effects). This includes the use of
+     * putOrderedX to clear fields of the per-thread Nodes between
+     * uses. Note that field Node.item is not declared as volatile
+     * even though it is read by releasing threads, because they only
+     * do so after CAS operations that must precede access, and all
+     * uses by the owning thread are otherwise acceptably ordered by
+     * other operations. (Because the actual points of atomicity are
+     * slot CASes, it would also be legal for the write to Node.match
+     * in a release to be weaker than a full volatile write. However,
+     * this is not done because it could allow further postponement of
+     * the write, delaying progress.)
+     */
+
+    /**
+     * The byte distance (as a shift value) between any two used slots
+     * in the arena.  1 << ASHIFT should be at least cacheline size.
+     */
+    private static final int ASHIFT = 7;
+
+    /**
+     * The maximum supported arena index. The maximum allocatable
+     * arena size is MMASK + 1. Must be a power of two minus one, less
+     * than (1<<(31-ASHIFT)). The cap of 255 (0xff) more than suffices
+     * for the expected scaling limits of the main algorithms.
+     */
+    private static final int MMASK = 0xff;
+
+    /**
+     * Unit for sequence/version bits of bound field. Each successful
+     * change to the bound also adds SEQ.
+     */
+    private static final int SEQ = MMASK + 1;
+
+    /** The number of CPUs, for sizing and spin control */
+    private static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * The maximum slot index of the arena: The number of slots that
+     * can in principle hold all threads without contention, or at
+     * most the maximum indexable value.
+     */
+    static final int FULL = (NCPU >= (MMASK << 1)) ? MMASK : NCPU >>> 1;
+
+    /**
+     * The bound for spins while waiting for a match. The actual
+     * number of iterations will on average be about twice this value
+     * due to randomization. Note: Spinning is disabled when NCPU==1.
+     */
+    private static final int SPINS = 1 << 10;
+
+    /**
+     * Value representing null arguments/returns from public
+     * methods. Needed because the API originally didn't disallow null
+     * arguments, which it should have.
+     */
+    private static final Object NULL_ITEM = new Object();
+
+    /**
+     * Sentinel value returned by internal exchange methods upon
+     * timeout, to avoid need for separate timed versions of these
+     * methods.
+     */
+    private static final Object TIMED_OUT = new Object();
+
+    /**
+     * Nodes hold partially exchanged data, plus other per-thread
+     * bookkeeping. Padded via @Contended to reduce memory contention.
+     */
+    // Android-removed: @Contended, this hint is not used by the Android runtime.
+    //@jdk.internal.vm.annotation.Contended
+    static final class Node {
+        int index;              // Arena index
+        int bound;              // Last recorded value of Exchanger.bound
+        int collides;           // Number of CAS failures at current bound
+        int hash;               // Pseudo-random for spins
+        Object item;            // This thread's current item
+        volatile Object match;  // Item provided by releasing thread
+        volatile Thread parked; // Set to this thread when parked, else null
+    }
+
+    /** The corresponding thread local class */
+    static final class Participant extends ThreadLocal<Node> {
+        public Node initialValue() { return new Node(); }
+    }
+
+    /**
+     * Per-thread state.
+     */
+    private final Participant participant;
+
+    /**
+     * Elimination array; null until enabled (within slotExchange).
+     * Element accesses use emulation of volatile gets and CAS.
+     */
+    private volatile Node[] arena;
+
+    /**
+     * Slot used until contention detected.
+     */
+    private volatile Node slot;
+
+    /**
+     * The index of the largest valid arena position, OR'ed with SEQ
+     * number in high bits, incremented on each update.  The initial
+     * update from 0 to SEQ is used to ensure that the arena array is
+     * constructed only once.
+     */
+    private volatile int bound;
+
+    /**
+     * Exchange function when arenas enabled. See above for explanation.
+     *
+     * @param item the (non-null) item to exchange
+     * @param timed true if the wait is timed
+     * @param ns if timed, the maximum wait time, else 0L
+     * @return the other thread's item; or null if interrupted; or
+     * TIMED_OUT if timed and timed out
+     */
+    private final Object arenaExchange(Object item, boolean timed, long ns) {
+        Node[] a = arena;
+        Node p = participant.get();
+        for (int i = p.index;;) {                      // access slot at i
+            int b, m, c; long j;                       // j is raw array offset
+            Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE);
+            if (q != null && U.compareAndSwapObject(a, j, q, null)) {
+                Object v = q.item;                     // release
+                q.match = item;
+                Thread w = q.parked;
+                if (w != null)
+                    U.unpark(w);
+                return v;
+            }
+            else if (i <= (m = (b = bound) & MMASK) && q == null) {
+                p.item = item;                         // offer
+                if (U.compareAndSwapObject(a, j, null, p)) {
+                    long end = (timed && m == 0) ? System.nanoTime() + ns : 0L;
+                    Thread t = Thread.currentThread(); // wait
+                    for (int h = p.hash, spins = SPINS;;) {
+                        Object v = p.match;
+                        if (v != null) {
+                            U.putOrderedObject(p, MATCH, null);
+                            p.item = null;             // clear for next use
+                            p.hash = h;
+                            return v;
+                        }
+                        else if (spins > 0) {
+                            h ^= h << 1; h ^= h >>> 3; h ^= h << 10; // xorshift
+                            if (h == 0)                // initialize hash
+                                h = SPINS | (int)t.getId();
+                            else if (h < 0 &&          // approx 50% true
+                                     (--spins & ((SPINS >>> 1) - 1)) == 0)
+                                Thread.yield();        // two yields per wait
+                        }
+                        else if (U.getObjectVolatile(a, j) != p)
+                            spins = SPINS;       // releaser hasn't set match yet
+                        else if (!t.isInterrupted() && m == 0 &&
+                                 (!timed ||
+                                  (ns = end - System.nanoTime()) > 0L)) {
+                            U.putObject(t, BLOCKER, this); // emulate LockSupport
+                            p.parked = t;              // minimize window
+                            if (U.getObjectVolatile(a, j) == p)
+                                U.park(false, ns);
+                            p.parked = null;
+                            U.putObject(t, BLOCKER, null);
+                        }
+                        else if (U.getObjectVolatile(a, j) == p &&
+                                 U.compareAndSwapObject(a, j, p, null)) {
+                            if (m != 0)                // try to shrink
+                                U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1);
+                            p.item = null;
+                            p.hash = h;
+                            i = p.index >>>= 1;        // descend
+                            if (Thread.interrupted())
+                                return null;
+                            if (timed && m == 0 && ns <= 0L)
+                                return TIMED_OUT;
+                            break;                     // expired; restart
+                        }
+                    }
+                }
+                else
+                    p.item = null;                     // clear offer
+            }
+            else {
+                if (p.bound != b) {                    // stale; reset
+                    p.bound = b;
+                    p.collides = 0;
+                    i = (i != m || m == 0) ? m : m - 1;
+                }
+                else if ((c = p.collides) < m || m == FULL ||
+                         !U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) {
+                    p.collides = c + 1;
+                    i = (i == 0) ? m : i - 1;          // cyclically traverse
+                }
+                else
+                    i = m + 1;                         // grow
+                p.index = i;
+            }
+        }
+    }
+
+    /**
+     * Exchange function used until arenas enabled. See above for explanation.
+     *
+     * @param item the item to exchange
+     * @param timed true if the wait is timed
+     * @param ns if timed, the maximum wait time, else 0L
+     * @return the other thread's item; or null if either the arena
+     * was enabled or the thread was interrupted before completion; or
+     * TIMED_OUT if timed and timed out
+     */
+    private final Object slotExchange(Object item, boolean timed, long ns) {
+        Node p = participant.get();
+        Thread t = Thread.currentThread();
+        if (t.isInterrupted()) // preserve interrupt status so caller can recheck
+            return null;
+
+        for (Node q;;) {
+            if ((q = slot) != null) {
+                if (U.compareAndSwapObject(this, SLOT, q, null)) {
+                    Object v = q.item;
+                    q.match = item;
+                    Thread w = q.parked;
+                    if (w != null)
+                        U.unpark(w);
+                    return v;
+                }
+                // create arena on contention, but continue until slot null
+                if (NCPU > 1 && bound == 0 &&
+                    U.compareAndSwapInt(this, BOUND, 0, SEQ))
+                    arena = new Node[(FULL + 2) << ASHIFT];
+            }
+            else if (arena != null)
+                return null; // caller must reroute to arenaExchange
+            else {
+                p.item = item;
+                if (U.compareAndSwapObject(this, SLOT, null, p))
+                    break;
+                p.item = null;
+            }
+        }
+
+        // await release
+        int h = p.hash;
+        long end = timed ? System.nanoTime() + ns : 0L;
+        int spins = (NCPU > 1) ? SPINS : 1;
+        Object v;
+        while ((v = p.match) == null) {
+            if (spins > 0) {
+                h ^= h << 1; h ^= h >>> 3; h ^= h << 10;
+                if (h == 0)
+                    h = SPINS | (int)t.getId();
+                else if (h < 0 && (--spins & ((SPINS >>> 1) - 1)) == 0)
+                    Thread.yield();
+            }
+            else if (slot != p)
+                spins = SPINS;
+            else if (!t.isInterrupted() && arena == null &&
+                     (!timed || (ns = end - System.nanoTime()) > 0L)) {
+                U.putObject(t, BLOCKER, this);
+                p.parked = t;
+                if (slot == p)
+                    U.park(false, ns);
+                p.parked = null;
+                U.putObject(t, BLOCKER, null);
+            }
+            else if (U.compareAndSwapObject(this, SLOT, p, null)) {
+                v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
+                break;
+            }
+        }
+        U.putOrderedObject(p, MATCH, null);
+        p.item = null;
+        p.hash = h;
+        return v;
+    }
+
+    /**
+     * Creates a new Exchanger.
+     */
+    public Exchanger() {
+        participant = new Participant();
+    }
+
+    /**
+     * Waits for another thread to arrive at this exchange point (unless
+     * the current thread is {@linkplain Thread#interrupt interrupted}),
+     * and then transfers the given object to it, receiving its object
+     * in return.
+     *
+     * <p>If another thread is already waiting at the exchange point then
+     * it is resumed for thread scheduling purposes and receives the object
+     * passed in by the current thread.  The current thread returns immediately,
+     * receiving the object passed to the exchange by that other thread.
+     *
+     * <p>If no other thread is already waiting at the exchange then the
+     * current thread is disabled for thread scheduling purposes and lies
+     * dormant until one of two things happens:
+     * <ul>
+     * <li>Some other thread enters the exchange; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for the exchange,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * @param x the object to exchange
+     * @return the object provided by the other thread
+     * @throws InterruptedException if the current thread was
+     *         interrupted while waiting
+     */
+    @SuppressWarnings("unchecked")
+    public V exchange(V x) throws InterruptedException {
+        Object v;
+        Object item = (x == null) ? NULL_ITEM : x; // translate null args
+        if ((arena != null ||
+             (v = slotExchange(item, false, 0L)) == null) &&
+            ((Thread.interrupted() || // disambiguates null return
+              (v = arenaExchange(item, false, 0L)) == null)))
+            throw new InterruptedException();
+        return (v == NULL_ITEM) ? null : (V)v;
+    }
+
+    /**
+     * Waits for another thread to arrive at this exchange point (unless
+     * the current thread is {@linkplain Thread#interrupt interrupted} or
+     * the specified waiting time elapses), and then transfers the given
+     * object to it, receiving its object in return.
+     *
+     * <p>If another thread is already waiting at the exchange point then
+     * it is resumed for thread scheduling purposes and receives the object
+     * passed in by the current thread.  The current thread returns immediately,
+     * receiving the object passed to the exchange by that other thread.
+     *
+     * <p>If no other thread is already waiting at the exchange then the
+     * current thread is disabled for thread scheduling purposes and lies
+     * dormant until one of three things happens:
+     * <ul>
+     * <li>Some other thread enters the exchange; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for the exchange,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then {@link
+     * TimeoutException} is thrown.  If the time is less than or equal
+     * to zero, the method will not wait at all.
+     *
+     * @param x the object to exchange
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the {@code timeout} argument
+     * @return the object provided by the other thread
+     * @throws InterruptedException if the current thread was
+     *         interrupted while waiting
+     * @throws TimeoutException if the specified waiting time elapses
+     *         before another thread enters the exchange
+     */
+    @SuppressWarnings("unchecked")
+    public V exchange(V x, long timeout, TimeUnit unit)
+        throws InterruptedException, TimeoutException {
+        Object v;
+        Object item = (x == null) ? NULL_ITEM : x;
+        long ns = unit.toNanos(timeout);
+        if ((arena != null ||
+             (v = slotExchange(item, true, ns)) == null) &&
+            ((Thread.interrupted() ||
+              (v = arenaExchange(item, true, ns)) == null)))
+            throw new InterruptedException();
+        if (v == TIMED_OUT)
+            throw new TimeoutException();
+        return (v == NULL_ITEM) ? null : (V)v;
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long BOUND;
+    private static final long SLOT;
+    private static final long MATCH;
+    private static final long BLOCKER;
+    private static final int ABASE;
+    static {
+        try {
+            BOUND = U.objectFieldOffset
+                (Exchanger.class.getDeclaredField("bound"));
+            SLOT = U.objectFieldOffset
+                (Exchanger.class.getDeclaredField("slot"));
+
+            MATCH = U.objectFieldOffset
+                (Node.class.getDeclaredField("match"));
+
+            BLOCKER = U.objectFieldOffset
+                (Thread.class.getDeclaredField("parkBlocker"));
+
+            int scale = U.arrayIndexScale(Node[].class);
+            if ((scale & (scale - 1)) != 0 || scale > (1 << ASHIFT))
+                throw new Error("Unsupported array scale");
+            // ABASE absorbs padding in front of element 0
+            ABASE = U.arrayBaseOffset(Node[].class) + (1 << ASHIFT);
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/ExecutionException.java b/java/util/concurrent/ExecutionException.java
new file mode 100644
index 0000000..71e7a71
--- /dev/null
+++ b/java/util/concurrent/ExecutionException.java
@@ -0,0 +1,92 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when attempting to retrieve the result of a task
+ * that aborted by throwing an exception. This exception can be
+ * inspected using the {@link #getCause()} method.
+ *
+ * @see Future
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ExecutionException extends Exception {
+    private static final long serialVersionUID = 7830266012832686185L;
+
+    /**
+     * Constructs an {@code ExecutionException} with no detail message.
+     * The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     */
+    protected ExecutionException() { }
+
+    /**
+     * Constructs an {@code ExecutionException} with the specified detail
+     * message. The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     *
+     * @param message the detail message
+     */
+    protected ExecutionException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an {@code ExecutionException} with the specified detail
+     * message and cause.
+     *
+     * @param  message the detail message
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public ExecutionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs an {@code ExecutionException} with the specified cause.
+     * The detail message is set to {@code (cause == null ? null :
+     * cause.toString())} (which typically contains the class and
+     * detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public ExecutionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/util/concurrent/Executor.java b/java/util/concurrent/Executor.java
new file mode 100644
index 0000000..a615705
--- /dev/null
+++ b/java/util/concurrent/Executor.java
@@ -0,0 +1,139 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * An object that executes submitted {@link Runnable} tasks. This
+ * interface provides a way of decoupling task submission from the
+ * mechanics of how each task will be run, including details of thread
+ * use, scheduling, etc.  An {@code Executor} is normally used
+ * instead of explicitly creating threads. For example, rather than
+ * invoking {@code new Thread(new RunnableTask()).start()} for each
+ * of a set of tasks, you might use:
+ *
+ * <pre> {@code
+ * Executor executor = anExecutor();
+ * executor.execute(new RunnableTask1());
+ * executor.execute(new RunnableTask2());
+ * ...}</pre>
+ *
+ * However, the {@code Executor} interface does not strictly require
+ * that execution be asynchronous. In the simplest case, an executor
+ * can run the submitted task immediately in the caller's thread:
+ *
+ * <pre> {@code
+ * class DirectExecutor implements Executor {
+ *   public void execute(Runnable r) {
+ *     r.run();
+ *   }
+ * }}</pre>
+ *
+ * More typically, tasks are executed in some thread other than the
+ * caller's thread.  The executor below spawns a new thread for each
+ * task.
+ *
+ * <pre> {@code
+ * class ThreadPerTaskExecutor implements Executor {
+ *   public void execute(Runnable r) {
+ *     new Thread(r).start();
+ *   }
+ * }}</pre>
+ *
+ * Many {@code Executor} implementations impose some sort of
+ * limitation on how and when tasks are scheduled.  The executor below
+ * serializes the submission of tasks to a second executor,
+ * illustrating a composite executor.
+ *
+ * <pre> {@code
+ * class SerialExecutor implements Executor {
+ *   final Queue<Runnable> tasks = new ArrayDeque<>();
+ *   final Executor executor;
+ *   Runnable active;
+ *
+ *   SerialExecutor(Executor executor) {
+ *     this.executor = executor;
+ *   }
+ *
+ *   public synchronized void execute(final Runnable r) {
+ *     tasks.add(new Runnable() {
+ *       public void run() {
+ *         try {
+ *           r.run();
+ *         } finally {
+ *           scheduleNext();
+ *         }
+ *       }
+ *     });
+ *     if (active == null) {
+ *       scheduleNext();
+ *     }
+ *   }
+ *
+ *   protected synchronized void scheduleNext() {
+ *     if ((active = tasks.poll()) != null) {
+ *       executor.execute(active);
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * The {@code Executor} implementations provided in this package
+ * implement {@link ExecutorService}, which is a more extensive
+ * interface.  The {@link ThreadPoolExecutor} class provides an
+ * extensible thread pool implementation. The {@link Executors} class
+ * provides convenient factory methods for these Executors.
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to
+ * submitting a {@code Runnable} object to an {@code Executor}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * its execution begins, perhaps in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Executor {
+
+    /**
+     * Executes the given command at some time in the future.  The command
+     * may execute in a new thread, in a pooled thread, or in the calling
+     * thread, at the discretion of the {@code Executor} implementation.
+     *
+     * @param command the runnable task
+     * @throws RejectedExecutionException if this task cannot be
+     * accepted for execution
+     * @throws NullPointerException if command is null
+     */
+    void execute(Runnable command);
+}
diff --git a/java/util/concurrent/ExecutorCompletionService.java b/java/util/concurrent/ExecutorCompletionService.java
new file mode 100644
index 0000000..a093844
--- /dev/null
+++ b/java/util/concurrent/ExecutorCompletionService.java
@@ -0,0 +1,207 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link CompletionService} that uses a supplied {@link Executor}
+ * to execute tasks.  This class arranges that submitted tasks are,
+ * upon completion, placed on a queue accessible using {@code take}.
+ * The class is lightweight enough to be suitable for transient use
+ * when processing groups of tasks.
+ *
+ * <p>
+ *
+ * <b>Usage Examples.</b>
+ *
+ * Suppose you have a set of solvers for a certain problem, each
+ * returning a value of some type {@code Result}, and would like to
+ * run them concurrently, processing the results of each of them that
+ * return a non-null value, in some method {@code use(Result r)}. You
+ * could write this as:
+ *
+ * <pre> {@code
+ * void solve(Executor e,
+ *            Collection<Callable<Result>> solvers)
+ *     throws InterruptedException, ExecutionException {
+ *   CompletionService<Result> ecs
+ *       = new ExecutorCompletionService<Result>(e);
+ *   for (Callable<Result> s : solvers)
+ *     ecs.submit(s);
+ *   int n = solvers.size();
+ *   for (int i = 0; i < n; ++i) {
+ *     Result r = ecs.take().get();
+ *     if (r != null)
+ *       use(r);
+ *   }
+ * }}</pre>
+ *
+ * Suppose instead that you would like to use the first non-null result
+ * of the set of tasks, ignoring any that encounter exceptions,
+ * and cancelling all other tasks when the first one is ready:
+ *
+ * <pre> {@code
+ * void solve(Executor e,
+ *            Collection<Callable<Result>> solvers)
+ *     throws InterruptedException {
+ *   CompletionService<Result> ecs
+ *       = new ExecutorCompletionService<Result>(e);
+ *   int n = solvers.size();
+ *   List<Future<Result>> futures = new ArrayList<>(n);
+ *   Result result = null;
+ *   try {
+ *     for (Callable<Result> s : solvers)
+ *       futures.add(ecs.submit(s));
+ *     for (int i = 0; i < n; ++i) {
+ *       try {
+ *         Result r = ecs.take().get();
+ *         if (r != null) {
+ *           result = r;
+ *           break;
+ *         }
+ *       } catch (ExecutionException ignore) {}
+ *     }
+ *   }
+ *   finally {
+ *     for (Future<Result> f : futures)
+ *       f.cancel(true);
+ *   }
+ *
+ *   if (result != null)
+ *     use(result);
+ * }}</pre>
+ */
+public class ExecutorCompletionService<V> implements CompletionService<V> {
+    private final Executor executor;
+    private final AbstractExecutorService aes;
+    private final BlockingQueue<Future<V>> completionQueue;
+
+    /**
+     * FutureTask extension to enqueue upon completion.
+     */
+    private static class QueueingFuture<V> extends FutureTask<Void> {
+        QueueingFuture(RunnableFuture<V> task,
+                       BlockingQueue<Future<V>> completionQueue) {
+            super(task, null);
+            this.task = task;
+            this.completionQueue = completionQueue;
+        }
+        private final Future<V> task;
+        private final BlockingQueue<Future<V>> completionQueue;
+        protected void done() { completionQueue.add(task); }
+    }
+
+    private RunnableFuture<V> newTaskFor(Callable<V> task) {
+        if (aes == null)
+            return new FutureTask<V>(task);
+        else
+            return aes.newTaskFor(task);
+    }
+
+    private RunnableFuture<V> newTaskFor(Runnable task, V result) {
+        if (aes == null)
+            return new FutureTask<V>(task, result);
+        else
+            return aes.newTaskFor(task, result);
+    }
+
+    /**
+     * Creates an ExecutorCompletionService using the supplied
+     * executor for base task execution and a
+     * {@link LinkedBlockingQueue} as a completion queue.
+     *
+     * @param executor the executor to use
+     * @throws NullPointerException if executor is {@code null}
+     */
+    public ExecutorCompletionService(Executor executor) {
+        if (executor == null)
+            throw new NullPointerException();
+        this.executor = executor;
+        this.aes = (executor instanceof AbstractExecutorService) ?
+            (AbstractExecutorService) executor : null;
+        this.completionQueue = new LinkedBlockingQueue<Future<V>>();
+    }
+
+    /**
+     * Creates an ExecutorCompletionService using the supplied
+     * executor for base task execution and the supplied queue as its
+     * completion queue.
+     *
+     * @param executor the executor to use
+     * @param completionQueue the queue to use as the completion queue
+     *        normally one dedicated for use by this service. This
+     *        queue is treated as unbounded -- failed attempted
+     *        {@code Queue.add} operations for completed tasks cause
+     *        them not to be retrievable.
+     * @throws NullPointerException if executor or completionQueue are {@code null}
+     */
+    public ExecutorCompletionService(Executor executor,
+                                     BlockingQueue<Future<V>> completionQueue) {
+        if (executor == null || completionQueue == null)
+            throw new NullPointerException();
+        this.executor = executor;
+        this.aes = (executor instanceof AbstractExecutorService) ?
+            (AbstractExecutorService) executor : null;
+        this.completionQueue = completionQueue;
+    }
+
+    public Future<V> submit(Callable<V> task) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<V> f = newTaskFor(task);
+        executor.execute(new QueueingFuture<V>(f, completionQueue));
+        return f;
+    }
+
+    public Future<V> submit(Runnable task, V result) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<V> f = newTaskFor(task, result);
+        executor.execute(new QueueingFuture<V>(f, completionQueue));
+        return f;
+    }
+
+    public Future<V> take() throws InterruptedException {
+        return completionQueue.take();
+    }
+
+    public Future<V> poll() {
+        return completionQueue.poll();
+    }
+
+    public Future<V> poll(long timeout, TimeUnit unit)
+            throws InterruptedException {
+        return completionQueue.poll(timeout, unit);
+    }
+
+}
diff --git a/java/util/concurrent/ExecutorService.java b/java/util/concurrent/ExecutorService.java
new file mode 100644
index 0000000..83be00b
--- /dev/null
+++ b/java/util/concurrent/ExecutorService.java
@@ -0,0 +1,360 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+import java.util.List;
+
+// BEGIN android-note
+// removed security manager docs
+// END android-note
+
+/**
+ * An {@link Executor} that provides methods to manage termination and
+ * methods that can produce a {@link Future} for tracking progress of
+ * one or more asynchronous tasks.
+ *
+ * <p>An {@code ExecutorService} can be shut down, which will cause
+ * it to reject new tasks.  Two different methods are provided for
+ * shutting down an {@code ExecutorService}. The {@link #shutdown}
+ * method will allow previously submitted tasks to execute before
+ * terminating, while the {@link #shutdownNow} method prevents waiting
+ * tasks from starting and attempts to stop currently executing tasks.
+ * Upon termination, an executor has no tasks actively executing, no
+ * tasks awaiting execution, and no new tasks can be submitted.  An
+ * unused {@code ExecutorService} should be shut down to allow
+ * reclamation of its resources.
+ *
+ * <p>Method {@code submit} extends base method {@link
+ * Executor#execute(Runnable)} by creating and returning a {@link Future}
+ * that can be used to cancel execution and/or wait for completion.
+ * Methods {@code invokeAny} and {@code invokeAll} perform the most
+ * commonly useful forms of bulk execution, executing a collection of
+ * tasks and then waiting for at least one, or all, to
+ * complete. (Class {@link ExecutorCompletionService} can be used to
+ * write customized variants of these methods.)
+ *
+ * <p>The {@link Executors} class provides factory methods for the
+ * executor services provided in this package.
+ *
+ * <h3>Usage Examples</h3>
+ *
+ * Here is a sketch of a network service in which threads in a thread
+ * pool service incoming requests. It uses the preconfigured {@link
+ * Executors#newFixedThreadPool} factory method:
+ *
+ * <pre> {@code
+ * class NetworkService implements Runnable {
+ *   private final ServerSocket serverSocket;
+ *   private final ExecutorService pool;
+ *
+ *   public NetworkService(int port, int poolSize)
+ *       throws IOException {
+ *     serverSocket = new ServerSocket(port);
+ *     pool = Executors.newFixedThreadPool(poolSize);
+ *   }
+ *
+ *   public void run() { // run the service
+ *     try {
+ *       for (;;) {
+ *         pool.execute(new Handler(serverSocket.accept()));
+ *       }
+ *     } catch (IOException ex) {
+ *       pool.shutdown();
+ *     }
+ *   }
+ * }
+ *
+ * class Handler implements Runnable {
+ *   private final Socket socket;
+ *   Handler(Socket socket) { this.socket = socket; }
+ *   public void run() {
+ *     // read and service request on socket
+ *   }
+ * }}</pre>
+ *
+ * The following method shuts down an {@code ExecutorService} in two phases,
+ * first by calling {@code shutdown} to reject incoming tasks, and then
+ * calling {@code shutdownNow}, if necessary, to cancel any lingering tasks:
+ *
+ * <pre> {@code
+ * void shutdownAndAwaitTermination(ExecutorService pool) {
+ *   pool.shutdown(); // Disable new tasks from being submitted
+ *   try {
+ *     // Wait a while for existing tasks to terminate
+ *     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
+ *       pool.shutdownNow(); // Cancel currently executing tasks
+ *       // Wait a while for tasks to respond to being cancelled
+ *       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
+ *           System.err.println("Pool did not terminate");
+ *     }
+ *   } catch (InterruptedException ie) {
+ *     // (Re-)Cancel if current thread also interrupted
+ *     pool.shutdownNow();
+ *     // Preserve interrupt status
+ *     Thread.currentThread().interrupt();
+ *   }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to the
+ * submission of a {@code Runnable} or {@code Callable} task to an
+ * {@code ExecutorService}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * any actions taken by that task, which in turn <i>happen-before</i> the
+ * result is retrieved via {@code Future.get()}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ExecutorService extends Executor {
+
+    /**
+     * Initiates an orderly shutdown in which previously submitted
+     * tasks are executed, but no new tasks will be accepted.
+     * Invocation has no additional effect if already shut down.
+     *
+     * <p>This method does not wait for previously submitted tasks to
+     * complete execution.  Use {@link #awaitTermination awaitTermination}
+     * to do that.
+     */
+    void shutdown();
+
+    /**
+     * Attempts to stop all actively executing tasks, halts the
+     * processing of waiting tasks, and returns a list of the tasks
+     * that were awaiting execution.
+     *
+     * <p>This method does not wait for actively executing tasks to
+     * terminate.  Use {@link #awaitTermination awaitTermination} to
+     * do that.
+     *
+     * <p>There are no guarantees beyond best-effort attempts to stop
+     * processing actively executing tasks.  For example, typical
+     * implementations will cancel via {@link Thread#interrupt}, so any
+     * task that fails to respond to interrupts may never terminate.
+     *
+     * @return list of tasks that never commenced execution
+     */
+    List<Runnable> shutdownNow();
+
+    /**
+     * Returns {@code true} if this executor has been shut down.
+     *
+     * @return {@code true} if this executor has been shut down
+     */
+    boolean isShutdown();
+
+    /**
+     * Returns {@code true} if all tasks have completed following shut down.
+     * Note that {@code isTerminated} is never {@code true} unless
+     * either {@code shutdown} or {@code shutdownNow} was called first.
+     *
+     * @return {@code true} if all tasks have completed following shut down
+     */
+    boolean isTerminated();
+
+    /**
+     * Blocks until all tasks have completed execution after a shutdown
+     * request, or the timeout occurs, or the current thread is
+     * interrupted, whichever happens first.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return {@code true} if this executor terminated and
+     *         {@code false} if the timeout elapsed before termination
+     * @throws InterruptedException if interrupted while waiting
+     */
+    boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Submits a value-returning task for execution and returns a
+     * Future representing the pending results of the task. The
+     * Future's {@code get} method will return the task's result upon
+     * successful completion.
+     *
+     * <p>
+     * If you would like to immediately block waiting
+     * for a task, you can use constructions of the form
+     * {@code result = exec.submit(aCallable).get();}
+     *
+     * <p>Note: The {@link Executors} class includes a set of methods
+     * that can convert some other common closure-like objects,
+     * for example, {@link java.security.PrivilegedAction} to
+     * {@link Callable} form so they can be submitted.
+     *
+     * @param task the task to submit
+     * @param <T> the type of the task's result
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    <T> Future<T> submit(Callable<T> task);
+
+    /**
+     * Submits a Runnable task for execution and returns a Future
+     * representing that task. The Future's {@code get} method will
+     * return the given result upon successful completion.
+     *
+     * @param task the task to submit
+     * @param result the result to return
+     * @param <T> the type of the result
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    <T> Future<T> submit(Runnable task, T result);
+
+    /**
+     * Submits a Runnable task for execution and returns a Future
+     * representing that task. The Future's {@code get} method will
+     * return {@code null} upon <em>successful</em> completion.
+     *
+     * @param task the task to submit
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    Future<?> submit(Runnable task);
+
+    /**
+     * Executes the given tasks, returning a list of Futures holding
+     * their status and results when all complete.
+     * {@link Future#isDone} is {@code true} for each
+     * element of the returned list.
+     * Note that a <em>completed</em> task could have
+     * terminated either normally or by throwing an exception.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param <T> the type of the values returned from the tasks
+     * @return a list of Futures representing the tasks, in the same
+     *         sequential order as produced by the iterator for the
+     *         given task list, each of which has completed
+     * @throws InterruptedException if interrupted while waiting, in
+     *         which case unfinished tasks are cancelled
+     * @throws NullPointerException if tasks or any of its elements are {@code null}
+     * @throws RejectedExecutionException if any task cannot be
+     *         scheduled for execution
+     */
+    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException;
+
+    /**
+     * Executes the given tasks, returning a list of Futures holding
+     * their status and results
+     * when all complete or the timeout expires, whichever happens first.
+     * {@link Future#isDone} is {@code true} for each
+     * element of the returned list.
+     * Upon return, tasks that have not completed are cancelled.
+     * Note that a <em>completed</em> task could have
+     * terminated either normally or by throwing an exception.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @param <T> the type of the values returned from the tasks
+     * @return a list of Futures representing the tasks, in the same
+     *         sequential order as produced by the iterator for the
+     *         given task list. If the operation did not time out,
+     *         each task will have completed. If it did time out, some
+     *         of these tasks will not have completed.
+     * @throws InterruptedException if interrupted while waiting, in
+     *         which case unfinished tasks are cancelled
+     * @throws NullPointerException if tasks, any of its elements, or
+     *         unit are {@code null}
+     * @throws RejectedExecutionException if any task cannot be scheduled
+     *         for execution
+     */
+    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
+                                  long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Executes the given tasks, returning the result
+     * of one that has completed successfully (i.e., without throwing
+     * an exception), if any do. Upon normal or exceptional return,
+     * tasks that have not completed are cancelled.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param <T> the type of the values returned from the tasks
+     * @return the result returned by one of the tasks
+     * @throws InterruptedException if interrupted while waiting
+     * @throws NullPointerException if tasks or any element task
+     *         subject to execution is {@code null}
+     * @throws IllegalArgumentException if tasks is empty
+     * @throws ExecutionException if no task successfully completes
+     * @throws RejectedExecutionException if tasks cannot be scheduled
+     *         for execution
+     */
+    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException, ExecutionException;
+
+    /**
+     * Executes the given tasks, returning the result
+     * of one that has completed successfully (i.e., without throwing
+     * an exception), if any do before the given timeout elapses.
+     * Upon normal or exceptional return, tasks that have not
+     * completed are cancelled.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @param <T> the type of the values returned from the tasks
+     * @return the result returned by one of the tasks
+     * @throws InterruptedException if interrupted while waiting
+     * @throws NullPointerException if tasks, or unit, or any element
+     *         task subject to execution is {@code null}
+     * @throws TimeoutException if the given timeout elapses before
+     *         any task successfully completes
+     * @throws ExecutionException if no task successfully completes
+     * @throws RejectedExecutionException if tasks cannot be scheduled
+     *         for execution
+     */
+    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+                    long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException;
+}
diff --git a/java/util/concurrent/Executors.java b/java/util/concurrent/Executors.java
new file mode 100644
index 0000000..565fdeb
--- /dev/null
+++ b/java/util/concurrent/Executors.java
@@ -0,0 +1,706 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import sun.security.util.SecurityConstants;
+
+// BEGIN android-note
+// removed security manager docs
+// END android-note
+
+/**
+ * Factory and utility methods for {@link Executor}, {@link
+ * ExecutorService}, {@link ScheduledExecutorService}, {@link
+ * ThreadFactory}, and {@link Callable} classes defined in this
+ * package. This class supports the following kinds of methods:
+ *
+ * <ul>
+ *   <li>Methods that create and return an {@link ExecutorService}
+ *       set up with commonly useful configuration settings.
+ *   <li>Methods that create and return a {@link ScheduledExecutorService}
+ *       set up with commonly useful configuration settings.
+ *   <li>Methods that create and return a "wrapped" ExecutorService, that
+ *       disables reconfiguration by making implementation-specific methods
+ *       inaccessible.
+ *   <li>Methods that create and return a {@link ThreadFactory}
+ *       that sets newly created threads to a known state.
+ *   <li>Methods that create and return a {@link Callable}
+ *       out of other closure-like forms, so they can be used
+ *       in execution methods requiring {@code Callable}.
+ * </ul>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class Executors {
+
+    /**
+     * Creates a thread pool that reuses a fixed number of threads
+     * operating off a shared unbounded queue.  At any point, at most
+     * {@code nThreads} threads will be active processing tasks.
+     * If additional tasks are submitted when all threads are active,
+     * they will wait in the queue until a thread is available.
+     * If any thread terminates due to a failure during execution
+     * prior to shutdown, a new one will take its place if needed to
+     * execute subsequent tasks.  The threads in the pool will exist
+     * until it is explicitly {@link ExecutorService#shutdown shutdown}.
+     *
+     * @param nThreads the number of threads in the pool
+     * @return the newly created thread pool
+     * @throws IllegalArgumentException if {@code nThreads <= 0}
+     */
+    public static ExecutorService newFixedThreadPool(int nThreads) {
+        return new ThreadPoolExecutor(nThreads, nThreads,
+                                      0L, TimeUnit.MILLISECONDS,
+                                      new LinkedBlockingQueue<Runnable>());
+    }
+
+    /**
+     * Creates a thread pool that maintains enough threads to support
+     * the given parallelism level, and may use multiple queues to
+     * reduce contention. The parallelism level corresponds to the
+     * maximum number of threads actively engaged in, or available to
+     * engage in, task processing. The actual number of threads may
+     * grow and shrink dynamically. A work-stealing pool makes no
+     * guarantees about the order in which submitted tasks are
+     * executed.
+     *
+     * @param parallelism the targeted parallelism level
+     * @return the newly created thread pool
+     * @throws IllegalArgumentException if {@code parallelism <= 0}
+     * @since 1.8
+     */
+    public static ExecutorService newWorkStealingPool(int parallelism) {
+        return new ForkJoinPool
+            (parallelism,
+             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+             null, true);
+    }
+
+    /**
+     * Creates a work-stealing thread pool using the number of
+     * {@linkplain Runtime#availableProcessors available processors}
+     * as its target parallelism level.
+     *
+     * @return the newly created thread pool
+     * @see #newWorkStealingPool(int)
+     * @since 1.8
+     */
+    public static ExecutorService newWorkStealingPool() {
+        return new ForkJoinPool
+            (Runtime.getRuntime().availableProcessors(),
+             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+             null, true);
+    }
+
+    /**
+     * Creates a thread pool that reuses a fixed number of threads
+     * operating off a shared unbounded queue, using the provided
+     * ThreadFactory to create new threads when needed.  At any point,
+     * at most {@code nThreads} threads will be active processing
+     * tasks.  If additional tasks are submitted when all threads are
+     * active, they will wait in the queue until a thread is
+     * available.  If any thread terminates due to a failure during
+     * execution prior to shutdown, a new one will take its place if
+     * needed to execute subsequent tasks.  The threads in the pool will
+     * exist until it is explicitly {@link ExecutorService#shutdown
+     * shutdown}.
+     *
+     * @param nThreads the number of threads in the pool
+     * @param threadFactory the factory to use when creating new threads
+     * @return the newly created thread pool
+     * @throws NullPointerException if threadFactory is null
+     * @throws IllegalArgumentException if {@code nThreads <= 0}
+     */
+    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
+        return new ThreadPoolExecutor(nThreads, nThreads,
+                                      0L, TimeUnit.MILLISECONDS,
+                                      new LinkedBlockingQueue<Runnable>(),
+                                      threadFactory);
+    }
+
+    /**
+     * Creates an Executor that uses a single worker thread operating
+     * off an unbounded queue. (Note however that if this single
+     * thread terminates due to a failure during execution prior to
+     * shutdown, a new one will take its place if needed to execute
+     * subsequent tasks.)  Tasks are guaranteed to execute
+     * sequentially, and no more than one task will be active at any
+     * given time. Unlike the otherwise equivalent
+     * {@code newFixedThreadPool(1)} the returned executor is
+     * guaranteed not to be reconfigurable to use additional threads.
+     *
+     * @return the newly created single-threaded Executor
+     */
+    public static ExecutorService newSingleThreadExecutor() {
+        return new FinalizableDelegatedExecutorService
+            (new ThreadPoolExecutor(1, 1,
+                                    0L, TimeUnit.MILLISECONDS,
+                                    new LinkedBlockingQueue<Runnable>()));
+    }
+
+    /**
+     * Creates an Executor that uses a single worker thread operating
+     * off an unbounded queue, and uses the provided ThreadFactory to
+     * create a new thread when needed. Unlike the otherwise
+     * equivalent {@code newFixedThreadPool(1, threadFactory)} the
+     * returned executor is guaranteed not to be reconfigurable to use
+     * additional threads.
+     *
+     * @param threadFactory the factory to use when creating new
+     * threads
+     *
+     * @return the newly created single-threaded Executor
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
+        return new FinalizableDelegatedExecutorService
+            (new ThreadPoolExecutor(1, 1,
+                                    0L, TimeUnit.MILLISECONDS,
+                                    new LinkedBlockingQueue<Runnable>(),
+                                    threadFactory));
+    }
+
+    /**
+     * Creates a thread pool that creates new threads as needed, but
+     * will reuse previously constructed threads when they are
+     * available.  These pools will typically improve the performance
+     * of programs that execute many short-lived asynchronous tasks.
+     * Calls to {@code execute} will reuse previously constructed
+     * threads if available. If no existing thread is available, a new
+     * thread will be created and added to the pool. Threads that have
+     * not been used for sixty seconds are terminated and removed from
+     * the cache. Thus, a pool that remains idle for long enough will
+     * not consume any resources. Note that pools with similar
+     * properties but different details (for example, timeout parameters)
+     * may be created using {@link ThreadPoolExecutor} constructors.
+     *
+     * @return the newly created thread pool
+     */
+    public static ExecutorService newCachedThreadPool() {
+        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
+                                      60L, TimeUnit.SECONDS,
+                                      new SynchronousQueue<Runnable>());
+    }
+
+    /**
+     * Creates a thread pool that creates new threads as needed, but
+     * will reuse previously constructed threads when they are
+     * available, and uses the provided
+     * ThreadFactory to create new threads when needed.
+     * @param threadFactory the factory to use when creating new threads
+     * @return the newly created thread pool
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
+        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
+                                      60L, TimeUnit.SECONDS,
+                                      new SynchronousQueue<Runnable>(),
+                                      threadFactory);
+    }
+
+    /**
+     * Creates a single-threaded executor that can schedule commands
+     * to run after a given delay, or to execute periodically.
+     * (Note however that if this single
+     * thread terminates due to a failure during execution prior to
+     * shutdown, a new one will take its place if needed to execute
+     * subsequent tasks.)  Tasks are guaranteed to execute
+     * sequentially, and no more than one task will be active at any
+     * given time. Unlike the otherwise equivalent
+     * {@code newScheduledThreadPool(1)} the returned executor is
+     * guaranteed not to be reconfigurable to use additional threads.
+     * @return the newly created scheduled executor
+     */
+    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
+        return new DelegatedScheduledExecutorService
+            (new ScheduledThreadPoolExecutor(1));
+    }
+
+    /**
+     * Creates a single-threaded executor that can schedule commands
+     * to run after a given delay, or to execute periodically.  (Note
+     * however that if this single thread terminates due to a failure
+     * during execution prior to shutdown, a new one will take its
+     * place if needed to execute subsequent tasks.)  Tasks are
+     * guaranteed to execute sequentially, and no more than one task
+     * will be active at any given time. Unlike the otherwise
+     * equivalent {@code newScheduledThreadPool(1, threadFactory)}
+     * the returned executor is guaranteed not to be reconfigurable to
+     * use additional threads.
+     * @param threadFactory the factory to use when creating new
+     * threads
+     * @return a newly created scheduled executor
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
+        return new DelegatedScheduledExecutorService
+            (new ScheduledThreadPoolExecutor(1, threadFactory));
+    }
+
+    /**
+     * Creates a thread pool that can schedule commands to run after a
+     * given delay, or to execute periodically.
+     * @param corePoolSize the number of threads to keep in the pool,
+     * even if they are idle
+     * @return a newly created scheduled thread pool
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     */
+    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
+        return new ScheduledThreadPoolExecutor(corePoolSize);
+    }
+
+    /**
+     * Creates a thread pool that can schedule commands to run after a
+     * given delay, or to execute periodically.
+     * @param corePoolSize the number of threads to keep in the pool,
+     * even if they are idle
+     * @param threadFactory the factory to use when the executor
+     * creates a new thread
+     * @return a newly created scheduled thread pool
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ScheduledExecutorService newScheduledThreadPool(
+            int corePoolSize, ThreadFactory threadFactory) {
+        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
+    }
+
+    /**
+     * Returns an object that delegates all defined {@link
+     * ExecutorService} methods to the given executor, but not any
+     * other methods that might otherwise be accessible using
+     * casts. This provides a way to safely "freeze" configuration and
+     * disallow tuning of a given concrete implementation.
+     * @param executor the underlying implementation
+     * @return an {@code ExecutorService} instance
+     * @throws NullPointerException if executor null
+     */
+    public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
+        if (executor == null)
+            throw new NullPointerException();
+        return new DelegatedExecutorService(executor);
+    }
+
+    /**
+     * Returns an object that delegates all defined {@link
+     * ScheduledExecutorService} methods to the given executor, but
+     * not any other methods that might otherwise be accessible using
+     * casts. This provides a way to safely "freeze" configuration and
+     * disallow tuning of a given concrete implementation.
+     * @param executor the underlying implementation
+     * @return a {@code ScheduledExecutorService} instance
+     * @throws NullPointerException if executor null
+     */
+    public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
+        if (executor == null)
+            throw new NullPointerException();
+        return new DelegatedScheduledExecutorService(executor);
+    }
+
+    // Android-changed: Removed references to SecurityManager from javadoc.
+    /**
+     * Returns a default thread factory used to create new threads.
+     * This factory creates all new threads used by an Executor in the
+     * same {@link ThreadGroup}. Each new
+     * thread is created as a non-daemon thread with priority set to
+     * the smaller of {@code Thread.NORM_PRIORITY} and the maximum
+     * priority permitted in the thread group.  New threads have names
+     * accessible via {@link Thread#getName} of
+     * <em>pool-N-thread-M</em>, where <em>N</em> is the sequence
+     * number of this factory, and <em>M</em> is the sequence number
+     * of the thread created by this factory.
+     * @return a thread factory
+     */
+    public static ThreadFactory defaultThreadFactory() {
+        return new DefaultThreadFactory();
+    }
+
+    // Android-changed: Dropped documentation for legacy security code.
+    /**
+     * Legacy security code; do not use.
+     */
+    public static ThreadFactory privilegedThreadFactory() {
+        return new PrivilegedThreadFactory();
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given task and returns the given result.  This
+     * can be useful when applying methods requiring a
+     * {@code Callable} to an otherwise resultless action.
+     * @param task the task to run
+     * @param result the result to return
+     * @param <T> the type of the result
+     * @return a callable object
+     * @throws NullPointerException if task null
+     */
+    public static <T> Callable<T> callable(Runnable task, T result) {
+        if (task == null)
+            throw new NullPointerException();
+        return new RunnableAdapter<T>(task, result);
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given task and returns {@code null}.
+     * @param task the task to run
+     * @return a callable object
+     * @throws NullPointerException if task null
+     */
+    public static Callable<Object> callable(Runnable task) {
+        if (task == null)
+            throw new NullPointerException();
+        return new RunnableAdapter<Object>(task, null);
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given privileged action and returns its result.
+     * @param action the privileged action to run
+     * @return a callable object
+     * @throws NullPointerException if action null
+     */
+    public static Callable<Object> callable(final PrivilegedAction<?> action) {
+        if (action == null)
+            throw new NullPointerException();
+        return new Callable<Object>() {
+            public Object call() { return action.run(); }};
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given privileged exception action and returns
+     * its result.
+     * @param action the privileged exception action to run
+     * @return a callable object
+     * @throws NullPointerException if action null
+     */
+    public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) {
+        if (action == null)
+            throw new NullPointerException();
+        return new Callable<Object>() {
+            public Object call() throws Exception { return action.run(); }};
+    }
+
+    // Android-changed: Dropped documentation for legacy security code.
+    /**
+     * Legacy security code; do not use.
+     */
+    public static <T> Callable<T> privilegedCallable(Callable<T> callable) {
+        if (callable == null)
+            throw new NullPointerException();
+        return new PrivilegedCallable<T>(callable);
+    }
+
+    // Android-changed: Dropped documentation for legacy security code.
+    /**
+     * Legacy security code; do not use.
+     */
+    public static <T> Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> callable) {
+        if (callable == null)
+            throw new NullPointerException();
+        return new PrivilegedCallableUsingCurrentClassLoader<T>(callable);
+    }
+
+    // Non-public classes supporting the public methods
+
+    /**
+     * A callable that runs given task and returns given result.
+     */
+    private static final class RunnableAdapter<T> implements Callable<T> {
+        private final Runnable task;
+        private final T result;
+        RunnableAdapter(Runnable task, T result) {
+            this.task = task;
+            this.result = result;
+        }
+        public T call() {
+            task.run();
+            return result;
+        }
+    }
+
+    /**
+     * A callable that runs under established access control settings.
+     */
+    private static final class PrivilegedCallable<T> implements Callable<T> {
+        final Callable<T> task;
+        final AccessControlContext acc;
+
+        PrivilegedCallable(Callable<T> task) {
+            this.task = task;
+            this.acc = AccessController.getContext();
+        }
+
+        public T call() throws Exception {
+            try {
+                return AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<T>() {
+                        public T run() throws Exception {
+                            return task.call();
+                        }
+                    }, acc);
+            } catch (PrivilegedActionException e) {
+                throw e.getException();
+            }
+        }
+    }
+
+    /**
+     * A callable that runs under established access control settings and
+     * current ClassLoader.
+     */
+    private static final class PrivilegedCallableUsingCurrentClassLoader<T>
+            implements Callable<T> {
+        final Callable<T> task;
+        final AccessControlContext acc;
+        final ClassLoader ccl;
+
+        PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) {
+            // Android-removed: System.getSecurityManager always returns null.
+            /*
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                // Calls to getContextClassLoader from this class
+                // never trigger a security check, but we check
+                // whether our callers have this permission anyways.
+                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+
+                // Whether setContextClassLoader turns out to be necessary
+                // or not, we fail fast if permission is not available.
+                sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+            }
+            */
+            this.task = task;
+            this.acc = AccessController.getContext();
+            this.ccl = Thread.currentThread().getContextClassLoader();
+        }
+
+        public T call() throws Exception {
+            try {
+                return AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<T>() {
+                        public T run() throws Exception {
+                            Thread t = Thread.currentThread();
+                            ClassLoader cl = t.getContextClassLoader();
+                            if (ccl == cl) {
+                                return task.call();
+                            } else {
+                                t.setContextClassLoader(ccl);
+                                try {
+                                    return task.call();
+                                } finally {
+                                    t.setContextClassLoader(cl);
+                                }
+                            }
+                        }
+                    }, acc);
+            } catch (PrivilegedActionException e) {
+                throw e.getException();
+            }
+        }
+    }
+
+    /**
+     * The default thread factory.
+     */
+    private static class DefaultThreadFactory implements ThreadFactory {
+        private static final AtomicInteger poolNumber = new AtomicInteger(1);
+        private final ThreadGroup group;
+        private final AtomicInteger threadNumber = new AtomicInteger(1);
+        private final String namePrefix;
+
+        DefaultThreadFactory() {
+            SecurityManager s = System.getSecurityManager();
+            group = (s != null) ? s.getThreadGroup() :
+                                  Thread.currentThread().getThreadGroup();
+            namePrefix = "pool-" +
+                          poolNumber.getAndIncrement() +
+                         "-thread-";
+        }
+
+        public Thread newThread(Runnable r) {
+            Thread t = new Thread(group, r,
+                                  namePrefix + threadNumber.getAndIncrement(),
+                                  0);
+            if (t.isDaemon())
+                t.setDaemon(false);
+            if (t.getPriority() != Thread.NORM_PRIORITY)
+                t.setPriority(Thread.NORM_PRIORITY);
+            return t;
+        }
+    }
+
+    /**
+     * Thread factory capturing access control context and class loader.
+     */
+    private static class PrivilegedThreadFactory extends DefaultThreadFactory {
+        final AccessControlContext acc;
+        final ClassLoader ccl;
+
+        PrivilegedThreadFactory() {
+            super();
+            // Android-removed: System.getSecurityManager always returns null.
+            /*
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                // Calls to getContextClassLoader from this class
+                // never trigger a security check, but we check
+                // whether our callers have this permission anyways.
+                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+
+                // Fail fast
+                sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+            }
+            */
+            this.acc = AccessController.getContext();
+            this.ccl = Thread.currentThread().getContextClassLoader();
+        }
+
+        public Thread newThread(final Runnable r) {
+            return super.newThread(new Runnable() {
+                public void run() {
+                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                        public Void run() {
+                            Thread.currentThread().setContextClassLoader(ccl);
+                            r.run();
+                            return null;
+                        }
+                    }, acc);
+                }
+            });
+        }
+    }
+
+    /**
+     * A wrapper class that exposes only the ExecutorService methods
+     * of an ExecutorService implementation.
+     */
+    private static class DelegatedExecutorService
+            extends AbstractExecutorService {
+        // Android-added: @ReachabilitySensitive
+        // Needed for FinalizableDelegatedExecutorService below.
+        @ReachabilitySensitive
+        private final ExecutorService e;
+        DelegatedExecutorService(ExecutorService executor) { e = executor; }
+        public void execute(Runnable command) { e.execute(command); }
+        public void shutdown() { e.shutdown(); }
+        public List<Runnable> shutdownNow() { return e.shutdownNow(); }
+        public boolean isShutdown() { return e.isShutdown(); }
+        public boolean isTerminated() { return e.isTerminated(); }
+        public boolean awaitTermination(long timeout, TimeUnit unit)
+            throws InterruptedException {
+            return e.awaitTermination(timeout, unit);
+        }
+        public Future<?> submit(Runnable task) {
+            return e.submit(task);
+        }
+        public <T> Future<T> submit(Callable<T> task) {
+            return e.submit(task);
+        }
+        public <T> Future<T> submit(Runnable task, T result) {
+            return e.submit(task, result);
+        }
+        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+            throws InterruptedException {
+            return e.invokeAll(tasks);
+        }
+        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
+                                             long timeout, TimeUnit unit)
+            throws InterruptedException {
+            return e.invokeAll(tasks, timeout, unit);
+        }
+        public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+            throws InterruptedException, ExecutionException {
+            return e.invokeAny(tasks);
+        }
+        public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+                               long timeout, TimeUnit unit)
+            throws InterruptedException, ExecutionException, TimeoutException {
+            return e.invokeAny(tasks, timeout, unit);
+        }
+    }
+
+    private static class FinalizableDelegatedExecutorService
+            extends DelegatedExecutorService {
+        FinalizableDelegatedExecutorService(ExecutorService executor) {
+            super(executor);
+        }
+        protected void finalize() {
+            super.shutdown();
+        }
+    }
+
+    /**
+     * A wrapper class that exposes only the ScheduledExecutorService
+     * methods of a ScheduledExecutorService implementation.
+     */
+    private static class DelegatedScheduledExecutorService
+            extends DelegatedExecutorService
+            implements ScheduledExecutorService {
+        private final ScheduledExecutorService e;
+        DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
+            super(executor);
+            e = executor;
+        }
+        public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+            return e.schedule(command, delay, unit);
+        }
+        public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+            return e.schedule(callable, delay, unit);
+        }
+        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
+            return e.scheduleAtFixedRate(command, initialDelay, period, unit);
+        }
+        public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
+            return e.scheduleWithFixedDelay(command, initialDelay, delay, unit);
+        }
+    }
+
+    /** Cannot instantiate. */
+    private Executors() {}
+}
diff --git a/java/util/concurrent/Flow.java b/java/util/concurrent/Flow.java
new file mode 100644
index 0000000..0231790
--- /dev/null
+++ b/java/util/concurrent/Flow.java
@@ -0,0 +1,319 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+// Android-changed: Remove reference to SubmissionPublisher class (not present on Android).
+/**
+ * Interrelated interfaces and static methods for establishing
+ * flow-controlled components in which {@link Publisher Publishers}
+ * produce items consumed by one or more {@link Subscriber
+ * Subscribers}, each managed by a {@link Subscription
+ * Subscription}.
+ *
+ * <p>These interfaces correspond to the <a
+ * href="http://www.reactive-streams.org/"> reactive-streams</a>
+ * specification.  They apply in both concurrent and distributed
+ * asynchronous settings: All (seven) methods are defined in {@code
+ * void} "one-way" message style. Communication relies on a simple form
+ * of flow control (method {@link Subscription#request}) that can be
+ * used to avoid resource management problems that may otherwise occur
+ * in "push" based systems.
+ *
+ * <p><b>Examples.</b> A {@link Publisher} usually defines its own
+ * {@link Subscription} implementation; constructing one in method
+ * {@code subscribe} and issuing it to the calling {@link
+ * Subscriber}. It publishes items to the subscriber asynchronously,
+ * normally using an {@link Executor}.  For example, here is a very
+ * simple publisher that only issues (when requested) a single {@code
+ * TRUE} item to a single subscriber.  Because the subscriber receives
+ * only a single item, this class does not use buffering and ordering
+ * control required in most implementations.
+ *
+ * <pre> {@code
+ * class OneShotPublisher implements Publisher<Boolean> {
+ *   private final ExecutorService executor = ForkJoinPool.commonPool(); // daemon-based
+ *   private boolean subscribed; // true after first subscribe
+ *   public synchronized void subscribe(Subscriber<? super Boolean> subscriber) {
+ *     if (subscribed)
+ *       subscriber.onError(new IllegalStateException()); // only one allowed
+ *     else {
+ *       subscribed = true;
+ *       subscriber.onSubscribe(new OneShotSubscription(subscriber, executor));
+ *     }
+ *   }
+ *   static class OneShotSubscription implements Subscription {
+ *     private final Subscriber<? super Boolean> subscriber;
+ *     private final ExecutorService executor;
+ *     private Future<?> future; // to allow cancellation
+ *     private boolean completed;
+ *     OneShotSubscription(Subscriber<? super Boolean> subscriber,
+ *                         ExecutorService executor) {
+ *       this.subscriber = subscriber;
+ *       this.executor = executor;
+ *     }
+ *     public synchronized void request(long n) {
+ *       if (n != 0 && !completed) {
+ *         completed = true;
+ *         if (n < 0) {
+ *           IllegalArgumentException ex = new IllegalArgumentException();
+ *           executor.execute(() -> subscriber.onError(ex));
+ *         } else {
+ *           future = executor.submit(() -> {
+ *             subscriber.onNext(Boolean.TRUE);
+ *             subscriber.onComplete();
+ *           });
+ *         }
+ *       }
+ *     }
+ *     public synchronized void cancel() {
+ *       completed = true;
+ *       if (future != null) future.cancel(false);
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>A {@link Subscriber} arranges that items be requested and
+ * processed.  Items (invocations of {@link Subscriber#onNext}) are
+ * not issued unless requested, but multiple items may be requested.
+ * Many Subscriber implementations can arrange this in the style of
+ * the following example, where a buffer size of 1 single-steps, and
+ * larger sizes usually allow for more efficient overlapped processing
+ * with less communication; for example with a value of 64, this keeps
+ * total outstanding requests between 32 and 64.
+ * Because Subscriber method invocations for a given {@link
+ * Subscription} are strictly ordered, there is no need for these
+ * methods to use locks or volatiles unless a Subscriber maintains
+ * multiple Subscriptions (in which case it is better to instead
+ * define multiple Subscribers, each with its own Subscription).
+ *
+ * <pre> {@code
+ * class SampleSubscriber<T> implements Subscriber<T> {
+ *   final Consumer<? super T> consumer;
+ *   Subscription subscription;
+ *   final long bufferSize;
+ *   long count;
+ *   SampleSubscriber(long bufferSize, Consumer<? super T> consumer) {
+ *     this.bufferSize = bufferSize;
+ *     this.consumer = consumer;
+ *   }
+ *   public void onSubscribe(Subscription subscription) {
+ *     long initialRequestSize = bufferSize;
+ *     count = bufferSize - bufferSize / 2; // re-request when half consumed
+ *     (this.subscription = subscription).request(initialRequestSize);
+ *   }
+ *   public void onNext(T item) {
+ *     if (--count <= 0)
+ *       subscription.request(count = bufferSize - bufferSize / 2);
+ *     consumer.accept(item);
+ *   }
+ *   public void onError(Throwable ex) { ex.printStackTrace(); }
+ *   public void onComplete() {}
+ * }}</pre>
+ *
+ * <p>The default value of {@link #defaultBufferSize} may provide a
+ * useful starting point for choosing request sizes and capacities in
+ * Flow components based on expected rates, resources, and usages.
+ * Or, when flow control is never needed, a subscriber may initially
+ * request an effectively unbounded number of items, as in:
+ *
+ * <pre> {@code
+ * class UnboundedSubscriber<T> implements Subscriber<T> {
+ *   public void onSubscribe(Subscription subscription) {
+ *     subscription.request(Long.MAX_VALUE); // effectively unbounded
+ *   }
+ *   public void onNext(T item) { use(item); }
+ *   public void onError(Throwable ex) { ex.printStackTrace(); }
+ *   public void onComplete() {}
+ *   void use(T item) { ... }
+ * }}</pre>
+ *
+ * @author Doug Lea
+ * @since 9
+ */
+public final class Flow {
+
+    private Flow() {} // uninstantiable
+
+    /**
+     * A producer of items (and related control messages) received by
+     * Subscribers.  Each current {@link Subscriber} receives the same
+     * items (via method {@code onNext}) in the same order, unless
+     * drops or errors are encountered. If a Publisher encounters an
+     * error that does not allow items to be issued to a Subscriber,
+     * that Subscriber receives {@code onError}, and then receives no
+     * further messages.  Otherwise, when it is known that no further
+     * messages will be issued to it, a subscriber receives {@code
+     * onComplete}.  Publishers ensure that Subscriber method
+     * invocations for each subscription are strictly ordered in <a
+     * href="package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * order.
+     *
+     * <p>Publishers may vary in policy about whether drops (failures
+     * to issue an item because of resource limitations) are treated
+     * as unrecoverable errors.  Publishers may also vary about
+     * whether Subscribers receive items that were produced or
+     * available before they subscribed.
+     *
+     * @param <T> the published item type
+     */
+    @FunctionalInterface
+    public static interface Publisher<T> {
+        /**
+         * Adds the given Subscriber if possible.  If already
+         * subscribed, or the attempt to subscribe fails due to policy
+         * violations or errors, the Subscriber's {@code onError}
+         * method is invoked with an {@link IllegalStateException}.
+         * Otherwise, the Subscriber's {@code onSubscribe} method is
+         * invoked with a new {@link Subscription}.  Subscribers may
+         * enable receiving items by invoking the {@code request}
+         * method of this Subscription, and may unsubscribe by
+         * invoking its {@code cancel} method.
+         *
+         * @param subscriber the subscriber
+         * @throws NullPointerException if subscriber is null
+         */
+        public void subscribe(Subscriber<? super T> subscriber);
+    }
+
+    /**
+     * A receiver of messages.  The methods in this interface are
+     * invoked in strict sequential order for each {@link
+     * Subscription}.
+     *
+     * @param <T> the subscribed item type
+     */
+    public static interface Subscriber<T> {
+        /**
+         * Method invoked prior to invoking any other Subscriber
+         * methods for the given Subscription. If this method throws
+         * an exception, resulting behavior is not guaranteed, but may
+         * cause the Subscription not to be established or to be cancelled.
+         *
+         * <p>Typically, implementations of this method invoke {@code
+         * subscription.request} to enable receiving items.
+         *
+         * @param subscription a new subscription
+         */
+        public void onSubscribe(Subscription subscription);
+
+        /**
+         * Method invoked with a Subscription's next item.  If this
+         * method throws an exception, resulting behavior is not
+         * guaranteed, but may cause the Subscription to be cancelled.
+         *
+         * @param item the item
+         */
+        public void onNext(T item);
+
+        /**
+         * Method invoked upon an unrecoverable error encountered by a
+         * Publisher or Subscription, after which no other Subscriber
+         * methods are invoked by the Subscription.  If this method
+         * itself throws an exception, resulting behavior is
+         * undefined.
+         *
+         * @param throwable the exception
+         */
+        public void onError(Throwable throwable);
+
+        /**
+         * Method invoked when it is known that no additional
+         * Subscriber method invocations will occur for a Subscription
+         * that is not already terminated by error, after which no
+         * other Subscriber methods are invoked by the Subscription.
+         * If this method throws an exception, resulting behavior is
+         * undefined.
+         */
+        public void onComplete();
+    }
+
+    /**
+     * Message control linking a {@link Publisher} and {@link
+     * Subscriber}.  Subscribers receive items only when requested,
+     * and may cancel at any time. The methods in this interface are
+     * intended to be invoked only by their Subscribers; usages in
+     * other contexts have undefined effects.
+     */
+    public static interface Subscription {
+        /**
+         * Adds the given number {@code n} of items to the current
+         * unfulfilled demand for this subscription.  If {@code n} is
+         * less than or equal to zero, the Subscriber will receive an
+         * {@code onError} signal with an {@link
+         * IllegalArgumentException} argument.  Otherwise, the
+         * Subscriber will receive up to {@code n} additional {@code
+         * onNext} invocations (or fewer if terminated).
+         *
+         * @param n the increment of demand; a value of {@code
+         * Long.MAX_VALUE} may be considered as effectively unbounded
+         */
+        public void request(long n);
+
+        /**
+         * Causes the Subscriber to (eventually) stop receiving
+         * messages.  Implementation is best-effort -- additional
+         * messages may be received after invoking this method.
+         * A cancelled subscription need not ever receive an
+         * {@code onComplete} or {@code onError} signal.
+         */
+        public void cancel();
+    }
+
+    /**
+     * A component that acts as both a Subscriber and Publisher.
+     *
+     * @param <T> the subscribed item type
+     * @param <R> the published item type
+     */
+    public static interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
+    }
+
+    static final int DEFAULT_BUFFER_SIZE = 256;
+
+    /**
+     * Returns a default value for Publisher or Subscriber buffering,
+     * that may be used in the absence of other constraints.
+     *
+     * @implNote
+     * The current value returned is 256.
+     *
+     * @return the buffer size value
+     */
+    public static int defaultBufferSize() {
+        return DEFAULT_BUFFER_SIZE;
+    }
+
+}
diff --git a/java/util/concurrent/ForkJoinPool.java b/java/util/concurrent/ForkJoinPool.java
new file mode 100644
index 0000000..04ad7d7
--- /dev/null
+++ b/java/util/concurrent/ForkJoinPool.java
@@ -0,0 +1,3582 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.security.AccessControlContext;
+import java.security.Permissions;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.LockSupport;
+
+/**
+ * An {@link ExecutorService} for running {@link ForkJoinTask}s.
+ * A {@code ForkJoinPool} provides the entry point for submissions
+ * from non-{@code ForkJoinTask} clients, as well as management and
+ * monitoring operations.
+ *
+ * <p>A {@code ForkJoinPool} differs from other kinds of {@link
+ * ExecutorService} mainly by virtue of employing
+ * <em>work-stealing</em>: all threads in the pool attempt to find and
+ * execute tasks submitted to the pool and/or created by other active
+ * tasks (eventually blocking waiting for work if none exist). This
+ * enables efficient processing when most tasks spawn other subtasks
+ * (as do most {@code ForkJoinTask}s), as well as when many small
+ * tasks are submitted to the pool from external clients.  Especially
+ * when setting <em>asyncMode</em> to true in constructors, {@code
+ * ForkJoinPool}s may also be appropriate for use with event-style
+ * tasks that are never joined.
+ *
+ * <p>A static {@link #commonPool()} is available and appropriate for
+ * most applications. The common pool is used by any ForkJoinTask that
+ * is not explicitly submitted to a specified pool. Using the common
+ * pool normally reduces resource usage (its threads are slowly
+ * reclaimed during periods of non-use, and reinstated upon subsequent
+ * use).
+ *
+ * <p>For applications that require separate or custom pools, a {@code
+ * ForkJoinPool} may be constructed with a given target parallelism
+ * level; by default, equal to the number of available processors.
+ * The pool attempts to maintain enough active (or available) threads
+ * by dynamically adding, suspending, or resuming internal worker
+ * threads, even if some tasks are stalled waiting to join others.
+ * However, no such adjustments are guaranteed in the face of blocked
+ * I/O or other unmanaged synchronization. The nested {@link
+ * ManagedBlocker} interface enables extension of the kinds of
+ * synchronization accommodated.
+ *
+ * <p>In addition to execution and lifecycle control methods, this
+ * class provides status check methods (for example
+ * {@link #getStealCount}) that are intended to aid in developing,
+ * tuning, and monitoring fork/join applications. Also, method
+ * {@link #toString} returns indications of pool state in a
+ * convenient form for informal monitoring.
+ *
+ * <p>As is the case with other ExecutorServices, there are three
+ * main task execution methods summarized in the following table.
+ * These are designed to be used primarily by clients not already
+ * engaged in fork/join computations in the current pool.  The main
+ * forms of these methods accept instances of {@code ForkJoinTask},
+ * but overloaded forms also allow mixed execution of plain {@code
+ * Runnable}- or {@code Callable}- based activities as well.  However,
+ * tasks that are already executing in a pool should normally instead
+ * use the within-computation forms listed in the table unless using
+ * async event-style tasks that are not usually joined, in which case
+ * there is little difference among choice of methods.
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of task execution methods</caption>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER> <b>Call from non-fork/join clients</b></td>
+ *    <td ALIGN=CENTER> <b>Call from within fork/join computations</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td> <b>Arrange async execution</b></td>
+ *    <td> {@link #execute(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#fork}</td>
+ *  </tr>
+ *  <tr>
+ *    <td> <b>Await and obtain result</b></td>
+ *    <td> {@link #invoke(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#invoke}</td>
+ *  </tr>
+ *  <tr>
+ *    <td> <b>Arrange exec and obtain Future</b></td>
+ *    <td> {@link #submit(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#fork} (ForkJoinTasks <em>are</em> Futures)</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>The common pool is by default constructed with default
+ * parameters, but these may be controlled by setting three
+ * {@linkplain System#getProperty system properties}:
+ * <ul>
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.parallelism}
+ * - the parallelism level, a non-negative integer
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.threadFactory}
+ * - the class name of a {@link ForkJoinWorkerThreadFactory}
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.exceptionHandler}
+ * - the class name of a {@link UncaughtExceptionHandler}
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.maximumSpares}
+ * - the maximum number of allowed extra threads to maintain target
+ * parallelism (default 256).
+ * </ul>
+ * If a {@link SecurityManager} is present and no factory is
+ * specified, then the default pool uses a factory supplying
+ * threads that have no {@link Permissions} enabled.
+ * The system class loader is used to load these classes.
+ * Upon any error in establishing these settings, default parameters
+ * are used. It is possible to disable or limit the use of threads in
+ * the common pool by setting the parallelism property to zero, and/or
+ * using a factory that may return {@code null}. However doing so may
+ * cause unjoined tasks to never be executed.
+ *
+ * <p><b>Implementation notes</b>: This implementation restricts the
+ * maximum number of running threads to 32767. Attempts to create
+ * pools with greater than the maximum number result in
+ * {@code IllegalArgumentException}.
+ *
+ * <p>This implementation rejects submitted tasks (that is, by throwing
+ * {@link RejectedExecutionException}) only when the pool is shut down
+ * or internal resources have been exhausted.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+// Android-removed: @Contended, this hint is not used by the Android runtime.
+//@jdk.internal.vm.annotation.Contended
+public class ForkJoinPool extends AbstractExecutorService {
+
+    /*
+     * Implementation Overview
+     *
+     * This class and its nested classes provide the main
+     * functionality and control for a set of worker threads:
+     * Submissions from non-FJ threads enter into submission queues.
+     * Workers take these tasks and typically split them into subtasks
+     * that may be stolen by other workers.  Preference rules give
+     * first priority to processing tasks from their own queues (LIFO
+     * or FIFO, depending on mode), then to randomized FIFO steals of
+     * tasks in other queues.  This framework began as vehicle for
+     * supporting tree-structured parallelism using work-stealing.
+     * Over time, its scalability advantages led to extensions and
+     * changes to better support more diverse usage contexts.  Because
+     * most internal methods and nested classes are interrelated,
+     * their main rationale and descriptions are presented here;
+     * individual methods and nested classes contain only brief
+     * comments about details.
+     *
+     * WorkQueues
+     * ==========
+     *
+     * Most operations occur within work-stealing queues (in nested
+     * class WorkQueue).  These are special forms of Deques that
+     * support only three of the four possible end-operations -- push,
+     * pop, and poll (aka steal), under the further constraints that
+     * push and pop are called only from the owning thread (or, as
+     * extended here, under a lock), while poll may be called from
+     * other threads.  (If you are unfamiliar with them, you probably
+     * want to read Herlihy and Shavit's book "The Art of
+     * Multiprocessor programming", chapter 16 describing these in
+     * more detail before proceeding.)  The main work-stealing queue
+     * design is roughly similar to those in the papers "Dynamic
+     * Circular Work-Stealing Deque" by Chase and Lev, SPAA 2005
+     * (http://research.sun.com/scalable/pubs/index.html) and
+     * "Idempotent work stealing" by Michael, Saraswat, and Vechev,
+     * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186).
+     * The main differences ultimately stem from GC requirements that
+     * we null out taken slots as soon as we can, to maintain as small
+     * a footprint as possible even in programs generating huge
+     * numbers of tasks. To accomplish this, we shift the CAS
+     * arbitrating pop vs poll (steal) from being on the indices
+     * ("base" and "top") to the slots themselves.
+     *
+     * Adding tasks then takes the form of a classic array push(task)
+     * in a circular buffer:
+     *    q.array[q.top++ % length] = task;
+     *
+     * (The actual code needs to null-check and size-check the array,
+     * uses masking, not mod, for indexing a power-of-two-sized array,
+     * properly fences accesses, and possibly signals waiting workers
+     * to start scanning -- see below.)  Both a successful pop and
+     * poll mainly entail a CAS of a slot from non-null to null.
+     *
+     * The pop operation (always performed by owner) is:
+     *   if ((the task at top slot is not null) and
+     *        (CAS slot to null))
+     *           decrement top and return task;
+     *
+     * And the poll operation (usually by a stealer) is
+     *    if ((the task at base slot is not null) and
+     *        (CAS slot to null))
+     *           increment base and return task;
+     *
+     * There are several variants of each of these; for example most
+     * versions of poll pre-screen the CAS by rechecking that the base
+     * has not changed since reading the slot, and most methods only
+     * attempt the CAS if base appears not to be equal to top.
+     *
+     * Memory ordering.  See "Correct and Efficient Work-Stealing for
+     * Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
+     * (http://www.di.ens.fr/~zappa/readings/ppopp13.pdf) for an
+     * analysis of memory ordering requirements in work-stealing
+     * algorithms similar to (but different than) the one used here.
+     * Extracting tasks in array slots via (fully fenced) CAS provides
+     * primary synchronization. The base and top indices imprecisely
+     * guide where to extract from. We do not always require strict
+     * orderings of array and index updates, so sometimes let them be
+     * subject to compiler and processor reorderings. However, the
+     * volatile "base" index also serves as a basis for memory
+     * ordering: Slot accesses are preceded by a read of base,
+     * ensuring happens-before ordering with respect to stealers (so
+     * the slots themselves can be read via plain array reads.)  The
+     * only other memory orderings relied on are maintained in the
+     * course of signalling and activation (see below).  A check that
+     * base == top indicates (momentary) emptiness, but otherwise may
+     * err on the side of possibly making the queue appear nonempty
+     * when a push, pop, or poll have not fully committed, or making
+     * it appear empty when an update of top has not yet been visibly
+     * written.  (Method isEmpty() checks the case of a partially
+     * completed removal of the last element.)  Because of this, the
+     * poll operation, considered individually, is not wait-free. One
+     * thief cannot successfully continue until another in-progress
+     * one (or, if previously empty, a push) visibly completes.
+     * However, in the aggregate, we ensure at least probabilistic
+     * non-blockingness.  If an attempted steal fails, a scanning
+     * thief chooses a different random victim target to try next. So,
+     * in order for one thief to progress, it suffices for any
+     * in-progress poll or new push on any empty queue to
+     * complete. (This is why we normally use method pollAt and its
+     * variants that try once at the apparent base index, else
+     * consider alternative actions, rather than method poll, which
+     * retries.)
+     *
+     * This approach also enables support of a user mode in which
+     * local task processing is in FIFO, not LIFO order, simply by
+     * using poll rather than pop.  This can be useful in
+     * message-passing frameworks in which tasks are never joined.
+     *
+     * WorkQueues are also used in a similar way for tasks submitted
+     * to the pool. We cannot mix these tasks in the same queues used
+     * by workers. Instead, we randomly associate submission queues
+     * with submitting threads, using a form of hashing.  The
+     * ThreadLocalRandom probe value serves as a hash code for
+     * choosing existing queues, and may be randomly repositioned upon
+     * contention with other submitters.  In essence, submitters act
+     * like workers except that they are restricted to executing local
+     * tasks that they submitted (or in the case of CountedCompleters,
+     * others with the same root task).  Insertion of tasks in shared
+     * mode requires a lock but we use only a simple spinlock (using
+     * field qlock), because submitters encountering a busy queue move
+     * on to try or create other queues -- they block only when
+     * creating and registering new queues. Because it is used only as
+     * a spinlock, unlocking requires only a "releasing" store (using
+     * putOrderedInt).  The qlock is also used during termination
+     * detection, in which case it is forced to a negative
+     * non-lockable value.
+     *
+     * Management
+     * ==========
+     *
+     * The main throughput advantages of work-stealing stem from
+     * decentralized control -- workers mostly take tasks from
+     * themselves or each other, at rates that can exceed a billion
+     * per second.  The pool itself creates, activates (enables
+     * scanning for and running tasks), deactivates, blocks, and
+     * terminates threads, all with minimal central information.
+     * There are only a few properties that we can globally track or
+     * maintain, so we pack them into a small number of variables,
+     * often maintaining atomicity without blocking or locking.
+     * Nearly all essentially atomic control state is held in two
+     * volatile variables that are by far most often read (not
+     * written) as status and consistency checks. (Also, field
+     * "config" holds unchanging configuration state.)
+     *
+     * Field "ctl" contains 64 bits holding information needed to
+     * atomically decide to add, inactivate, enqueue (on an event
+     * queue), dequeue, and/or re-activate workers.  To enable this
+     * packing, we restrict maximum parallelism to (1<<15)-1 (which is
+     * far in excess of normal operating range) to allow ids, counts,
+     * and their negations (used for thresholding) to fit into 16bit
+     * subfields.
+     *
+     * Field "runState" holds lifetime status, atomically and
+     * monotonically setting STARTED, SHUTDOWN, STOP, and finally
+     * TERMINATED bits.
+     *
+     * Field "auxState" is a ReentrantLock subclass that also
+     * opportunistically holds some other bookkeeping fields accessed
+     * only when locked.  It is mainly used to lock (infrequent)
+     * updates to workQueues.  The auxState instance is itself lazily
+     * constructed (see tryInitialize), requiring a double-check-style
+     * bootstrapping use of field runState, and locking a private
+     * static.
+     *
+     * Field "workQueues" holds references to WorkQueues.  It is
+     * updated (only during worker creation and termination) under the
+     * lock, but is otherwise concurrently readable, and accessed
+     * directly. We also ensure that reads of the array reference
+     * itself never become too stale (for example, re-reading before
+     * each scan). To simplify index-based operations, the array size
+     * is always a power of two, and all readers must tolerate null
+     * slots. Worker queues are at odd indices. Shared (submission)
+     * queues are at even indices, up to a maximum of 64 slots, to
+     * limit growth even if array needs to expand to add more
+     * workers. Grouping them together in this way simplifies and
+     * speeds up task scanning.
+     *
+     * All worker thread creation is on-demand, triggered by task
+     * submissions, replacement of terminated workers, and/or
+     * compensation for blocked workers. However, all other support
+     * code is set up to work with other policies.  To ensure that we
+     * do not hold on to worker references that would prevent GC, all
+     * accesses to workQueues are via indices into the workQueues
+     * array (which is one source of some of the messy code
+     * constructions here). In essence, the workQueues array serves as
+     * a weak reference mechanism. Thus for example the stack top
+     * subfield of ctl stores indices, not references.
+     *
+     * Queuing Idle Workers. Unlike HPC work-stealing frameworks, we
+     * cannot let workers spin indefinitely scanning for tasks when
+     * none can be found immediately, and we cannot start/resume
+     * workers unless there appear to be tasks available.  On the
+     * other hand, we must quickly prod them into action when new
+     * tasks are submitted or generated. In many usages, ramp-up time
+     * to activate workers is the main limiting factor in overall
+     * performance, which is compounded at program start-up by JIT
+     * compilation and allocation. So we streamline this as much as
+     * possible.
+     *
+     * The "ctl" field atomically maintains active and total worker
+     * counts as well as a queue to place waiting threads so they can
+     * be located for signalling. Active counts also play the role of
+     * quiescence indicators, so are decremented when workers believe
+     * that there are no more tasks to execute. The "queue" is
+     * actually a form of Treiber stack.  A stack is ideal for
+     * activating threads in most-recently used order. This improves
+     * performance and locality, outweighing the disadvantages of
+     * being prone to contention and inability to release a worker
+     * unless it is topmost on stack.  We block/unblock workers after
+     * pushing on the idle worker stack (represented by the lower
+     * 32bit subfield of ctl) when they cannot find work.  The top
+     * stack state holds the value of the "scanState" field of the
+     * worker: its index and status, plus a version counter that, in
+     * addition to the count subfields (also serving as version
+     * stamps) provide protection against Treiber stack ABA effects.
+     *
+     * Creating workers. To create a worker, we pre-increment total
+     * count (serving as a reservation), and attempt to construct a
+     * ForkJoinWorkerThread via its factory. Upon construction, the
+     * new thread invokes registerWorker, where it constructs a
+     * WorkQueue and is assigned an index in the workQueues array
+     * (expanding the array if necessary). The thread is then started.
+     * Upon any exception across these steps, or null return from
+     * factory, deregisterWorker adjusts counts and records
+     * accordingly.  If a null return, the pool continues running with
+     * fewer than the target number workers. If exceptional, the
+     * exception is propagated, generally to some external caller.
+     * Worker index assignment avoids the bias in scanning that would
+     * occur if entries were sequentially packed starting at the front
+     * of the workQueues array. We treat the array as a simple
+     * power-of-two hash table, expanding as needed. The seedIndex
+     * increment ensures no collisions until a resize is needed or a
+     * worker is deregistered and replaced, and thereafter keeps
+     * probability of collision low. We cannot use
+     * ThreadLocalRandom.getProbe() for similar purposes here because
+     * the thread has not started yet, but do so for creating
+     * submission queues for existing external threads (see
+     * externalPush).
+     *
+     * WorkQueue field scanState is used by both workers and the pool
+     * to manage and track whether a worker is UNSIGNALLED (possibly
+     * blocked waiting for a signal).  When a worker is inactivated,
+     * its scanState field is set, and is prevented from executing
+     * tasks, even though it must scan once for them to avoid queuing
+     * races. Note that scanState updates lag queue CAS releases so
+     * usage requires care. When queued, the lower 16 bits of
+     * scanState must hold its pool index. So we place the index there
+     * upon initialization (see registerWorker) and otherwise keep it
+     * there or restore it when necessary.
+     *
+     * The ctl field also serves as the basis for memory
+     * synchronization surrounding activation. This uses a more
+     * efficient version of a Dekker-like rule that task producers and
+     * consumers sync with each other by both writing/CASing ctl (even
+     * if to its current value).  This would be extremely costly. So
+     * we relax it in several ways: (1) Producers only signal when
+     * their queue is empty. Other workers propagate this signal (in
+     * method scan) when they find tasks. (2) Workers only enqueue
+     * after scanning (see below) and not finding any tasks.  (3)
+     * Rather than CASing ctl to its current value in the common case
+     * where no action is required, we reduce write contention by
+     * equivalently prefacing signalWork when called by an external
+     * task producer using a memory access with full-volatile
+     * semantics or a "fullFence". (4) For internal task producers we
+     * rely on the fact that even if no other workers awaken, the
+     * producer itself will eventually see the task and execute it.
+     *
+     * Almost always, too many signals are issued. A task producer
+     * cannot in general tell if some existing worker is in the midst
+     * of finishing one task (or already scanning) and ready to take
+     * another without being signalled. So the producer might instead
+     * activate a different worker that does not find any work, and
+     * then inactivates. This scarcely matters in steady-state
+     * computations involving all workers, but can create contention
+     * and bookkeeping bottlenecks during ramp-up, ramp-down, and small
+     * computations involving only a few workers.
+     *
+     * Scanning. Method scan() performs top-level scanning for tasks.
+     * Each scan traverses (and tries to poll from) each queue in
+     * pseudorandom permutation order by randomly selecting an origin
+     * index and a step value.  (The pseudorandom generator need not
+     * have high-quality statistical properties in the long term, but
+     * just within computations; We use 64bit and 32bit Marsaglia
+     * XorShifts, which are cheap and suffice here.)  Scanning also
+     * employs contention reduction: When scanning workers fail a CAS
+     * polling for work, they soon restart with a different
+     * pseudorandom scan order (thus likely retrying at different
+     * intervals). This improves throughput when many threads are
+     * trying to take tasks from few queues.  Scans do not otherwise
+     * explicitly take into account core affinities, loads, cache
+     * localities, etc, However, they do exploit temporal locality
+     * (which usually approximates these) by preferring to re-poll (up
+     * to POLL_LIMIT times) from the same queue after a successful
+     * poll before trying others.  Restricted forms of scanning occur
+     * in methods helpComplete and findNonEmptyStealQueue, and take
+     * similar but simpler forms.
+     *
+     * Deactivation and waiting. Queuing encounters several intrinsic
+     * races; most notably that an inactivating scanning worker can
+     * miss seeing a task produced during a scan.  So when a worker
+     * cannot find a task to steal, it inactivates and enqueues, and
+     * then rescans to ensure that it didn't miss one, reactivating
+     * upon seeing one with probability approximately proportional to
+     * probability of a miss.  (In most cases, the worker will be
+     * signalled before self-signalling, avoiding cascades of multiple
+     * signals for the same task).
+     *
+     * Workers block (in method awaitWork) using park/unpark;
+     * advertising the need for signallers to unpark by setting their
+     * "parker" fields.
+     *
+     * Trimming workers. To release resources after periods of lack of
+     * use, a worker starting to wait when the pool is quiescent will
+     * time out and terminate (see awaitWork) if the pool has remained
+     * quiescent for period given by IDLE_TIMEOUT_MS, increasing the
+     * period as the number of threads decreases, eventually removing
+     * all workers.
+     *
+     * Shutdown and Termination. A call to shutdownNow invokes
+     * tryTerminate to atomically set a runState bit. The calling
+     * thread, as well as every other worker thereafter terminating,
+     * helps terminate others by setting their (qlock) status,
+     * cancelling their unprocessed tasks, and waking them up, doing
+     * so repeatedly until stable. Calls to non-abrupt shutdown()
+     * preface this by checking whether termination should commence.
+     * This relies primarily on the active count bits of "ctl"
+     * maintaining consensus -- tryTerminate is called from awaitWork
+     * whenever quiescent. However, external submitters do not take
+     * part in this consensus.  So, tryTerminate sweeps through queues
+     * (until stable) to ensure lack of in-flight submissions and
+     * workers about to process them before triggering the "STOP"
+     * phase of termination. (Note: there is an intrinsic conflict if
+     * helpQuiescePool is called when shutdown is enabled. Both wait
+     * for quiescence, but tryTerminate is biased to not trigger until
+     * helpQuiescePool completes.)
+     *
+     * Joining Tasks
+     * =============
+     *
+     * Any of several actions may be taken when one worker is waiting
+     * to join a task stolen (or always held) by another.  Because we
+     * are multiplexing many tasks on to a pool of workers, we can't
+     * just let them block (as in Thread.join).  We also cannot just
+     * reassign the joiner's run-time stack with another and replace
+     * it later, which would be a form of "continuation", that even if
+     * possible is not necessarily a good idea since we may need both
+     * an unblocked task and its continuation to progress.  Instead we
+     * combine two tactics:
+     *
+     *   Helping: Arranging for the joiner to execute some task that it
+     *      would be running if the steal had not occurred.
+     *
+     *   Compensating: Unless there are already enough live threads,
+     *      method tryCompensate() may create or re-activate a spare
+     *      thread to compensate for blocked joiners until they unblock.
+     *
+     * A third form (implemented in tryRemoveAndExec) amounts to
+     * helping a hypothetical compensator: If we can readily tell that
+     * a possible action of a compensator is to steal and execute the
+     * task being joined, the joining thread can do so directly,
+     * without the need for a compensation thread (although at the
+     * expense of larger run-time stacks, but the tradeoff is
+     * typically worthwhile).
+     *
+     * The ManagedBlocker extension API can't use helping so relies
+     * only on compensation in method awaitBlocker.
+     *
+     * The algorithm in helpStealer entails a form of "linear
+     * helping".  Each worker records (in field currentSteal) the most
+     * recent task it stole from some other worker (or a submission).
+     * It also records (in field currentJoin) the task it is currently
+     * actively joining. Method helpStealer uses these markers to try
+     * to find a worker to help (i.e., steal back a task from and
+     * execute it) that could hasten completion of the actively joined
+     * task.  Thus, the joiner executes a task that would be on its
+     * own local deque had the to-be-joined task not been stolen. This
+     * is a conservative variant of the approach described in Wagner &
+     * Calder "Leapfrogging: a portable technique for implementing
+     * efficient futures" SIGPLAN Notices, 1993
+     * (http://portal.acm.org/citation.cfm?id=155354). It differs in
+     * that: (1) We only maintain dependency links across workers upon
+     * steals, rather than use per-task bookkeeping.  This sometimes
+     * requires a linear scan of workQueues array to locate stealers,
+     * but often doesn't because stealers leave hints (that may become
+     * stale/wrong) of where to locate them.  It is only a hint
+     * because a worker might have had multiple steals and the hint
+     * records only one of them (usually the most current).  Hinting
+     * isolates cost to when it is needed, rather than adding to
+     * per-task overhead.  (2) It is "shallow", ignoring nesting and
+     * potentially cyclic mutual steals.  (3) It is intentionally
+     * racy: field currentJoin is updated only while actively joining,
+     * which means that we miss links in the chain during long-lived
+     * tasks, GC stalls etc (which is OK since blocking in such cases
+     * is usually a good idea).  (4) We bound the number of attempts
+     * to find work using checksums and fall back to suspending the
+     * worker and if necessary replacing it with another.
+     *
+     * Helping actions for CountedCompleters do not require tracking
+     * currentJoins: Method helpComplete takes and executes any task
+     * with the same root as the task being waited on (preferring
+     * local pops to non-local polls). However, this still entails
+     * some traversal of completer chains, so is less efficient than
+     * using CountedCompleters without explicit joins.
+     *
+     * Compensation does not aim to keep exactly the target
+     * parallelism number of unblocked threads running at any given
+     * time. Some previous versions of this class employed immediate
+     * compensations for any blocked join. However, in practice, the
+     * vast majority of blockages are transient byproducts of GC and
+     * other JVM or OS activities that are made worse by replacement.
+     * Currently, compensation is attempted only after validating that
+     * all purportedly active threads are processing tasks by checking
+     * field WorkQueue.scanState, which eliminates most false
+     * positives.  Also, compensation is bypassed (tolerating fewer
+     * threads) in the most common case in which it is rarely
+     * beneficial: when a worker with an empty queue (thus no
+     * continuation tasks) blocks on a join and there still remain
+     * enough threads to ensure liveness.
+     *
+     * Spare threads are removed as soon as they notice that the
+     * target parallelism level has been exceeded, in method
+     * tryDropSpare. (Method scan arranges returns for rechecks upon
+     * each probe via the "bound" parameter.)
+     *
+     * The compensation mechanism may be bounded.  Bounds for the
+     * commonPool (see COMMON_MAX_SPARES) better enable JVMs to cope
+     * with programming errors and abuse before running out of
+     * resources to do so. In other cases, users may supply factories
+     * that limit thread construction. The effects of bounding in this
+     * pool (like all others) is imprecise.  Total worker counts are
+     * decremented when threads deregister, not when they exit and
+     * resources are reclaimed by the JVM and OS. So the number of
+     * simultaneously live threads may transiently exceed bounds.
+     *
+     * Common Pool
+     * ===========
+     *
+     * The static common pool always exists after static
+     * initialization.  Since it (or any other created pool) need
+     * never be used, we minimize initial construction overhead and
+     * footprint to the setup of about a dozen fields, with no nested
+     * allocation. Most bootstrapping occurs within method
+     * externalSubmit during the first submission to the pool.
+     *
+     * When external threads submit to the common pool, they can
+     * perform subtask processing (see externalHelpComplete and
+     * related methods) upon joins.  This caller-helps policy makes it
+     * sensible to set common pool parallelism level to one (or more)
+     * less than the total number of available cores, or even zero for
+     * pure caller-runs.  We do not need to record whether external
+     * submissions are to the common pool -- if not, external help
+     * methods return quickly. These submitters would otherwise be
+     * blocked waiting for completion, so the extra effort (with
+     * liberally sprinkled task status checks) in inapplicable cases
+     * amounts to an odd form of limited spin-wait before blocking in
+     * ForkJoinTask.join.
+     *
+     * As a more appropriate default in managed environments, unless
+     * overridden by system properties, we use workers of subclass
+     * InnocuousForkJoinWorkerThread when there is a SecurityManager
+     * present. These workers have no permissions set, do not belong
+     * to any user-defined ThreadGroup, and erase all ThreadLocals
+     * after executing any top-level task (see WorkQueue.runTask).
+     * The associated mechanics (mainly in ForkJoinWorkerThread) may
+     * be JVM-dependent and must access particular Thread class fields
+     * to achieve this effect.
+     *
+     * Style notes
+     * ===========
+     *
+     * Memory ordering relies mainly on Unsafe intrinsics that carry
+     * the further responsibility of explicitly performing null- and
+     * bounds- checks otherwise carried out implicitly by JVMs.  This
+     * can be awkward and ugly, but also reflects the need to control
+     * outcomes across the unusual cases that arise in very racy code
+     * with very few invariants. So these explicit checks would exist
+     * in some form anyway.  All fields are read into locals before
+     * use, and null-checked if they are references.  This is usually
+     * done in a "C"-like style of listing declarations at the heads
+     * of methods or blocks, and using inline assignments on first
+     * encounter.  Array bounds-checks are usually performed by
+     * masking with array.length-1, which relies on the invariant that
+     * these arrays are created with positive lengths, which is itself
+     * paranoically checked. Nearly all explicit checks lead to
+     * bypass/return, not exception throws, because they may
+     * legitimately arise due to cancellation/revocation during
+     * shutdown.
+     *
+     * There is a lot of representation-level coupling among classes
+     * ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask.  The
+     * fields of WorkQueue maintain data structures managed by
+     * ForkJoinPool, so are directly accessed.  There is little point
+     * trying to reduce this, since any associated future changes in
+     * representations will need to be accompanied by algorithmic
+     * changes anyway. Several methods intrinsically sprawl because
+     * they must accumulate sets of consistent reads of fields held in
+     * local variables.  There are also other coding oddities
+     * (including several unnecessary-looking hoisted null checks)
+     * that help some methods perform reasonably even when interpreted
+     * (not compiled).
+     *
+     * The order of declarations in this file is (with a few exceptions):
+     * (1) Static utility functions
+     * (2) Nested (static) classes
+     * (3) Static fields
+     * (4) Fields, along with constants used when unpacking some of them
+     * (5) Internal control methods
+     * (6) Callbacks and other support for ForkJoinTask methods
+     * (7) Exported methods
+     * (8) Static block initializing statics in minimally dependent order
+     */
+
+    // Static utilities
+
+    /**
+     * If there is a security manager, makes sure caller has
+     * permission to modify threads.
+     */
+    private static void checkPermission() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(modifyThreadPermission);
+    }
+
+    // Nested classes
+
+    /**
+     * Factory for creating new {@link ForkJoinWorkerThread}s.
+     * A {@code ForkJoinWorkerThreadFactory} must be defined and used
+     * for {@code ForkJoinWorkerThread} subclasses that extend base
+     * functionality or initialize threads with different contexts.
+     */
+    public static interface ForkJoinWorkerThreadFactory {
+        /**
+         * Returns a new worker thread operating in the given pool.
+         *
+         * @param pool the pool this thread works in
+         * @return the new worker thread, or {@code null} if the request
+         *         to create a thread is rejected
+         * @throws NullPointerException if the pool is null
+         */
+        public ForkJoinWorkerThread newThread(ForkJoinPool pool);
+    }
+
+    /**
+     * Default ForkJoinWorkerThreadFactory implementation; creates a
+     * new ForkJoinWorkerThread.
+     */
+    private static final class DefaultForkJoinWorkerThreadFactory
+        implements ForkJoinWorkerThreadFactory {
+        public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
+            return new ForkJoinWorkerThread(pool);
+        }
+    }
+
+    /**
+     * Class for artificial tasks that are used to replace the target
+     * of local joins if they are removed from an interior queue slot
+     * in WorkQueue.tryRemoveAndExec. We don't need the proxy to
+     * actually do anything beyond having a unique identity.
+     */
+    private static final class EmptyTask extends ForkJoinTask<Void> {
+        private static final long serialVersionUID = -7721805057305804111L;
+        EmptyTask() { status = ForkJoinTask.NORMAL; } // force done
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void x) {}
+        public final boolean exec() { return true; }
+    }
+
+    /**
+     * Additional fields and lock created upon initialization.
+     */
+    private static final class AuxState extends ReentrantLock {
+        private static final long serialVersionUID = -6001602636862214147L;
+        volatile long stealCount;     // cumulative steal count
+        long indexSeed;               // index bits for registerWorker
+        AuxState() {}
+    }
+
+    // Constants shared across ForkJoinPool and WorkQueue
+
+    // Bounds
+    static final int SMASK        = 0xffff;        // short bits == max index
+    static final int MAX_CAP      = 0x7fff;        // max #workers - 1
+    static final int EVENMASK     = 0xfffe;        // even short bits
+    static final int SQMASK       = 0x007e;        // max 64 (even) slots
+
+    // Masks and units for WorkQueue.scanState and ctl sp subfield
+    static final int UNSIGNALLED  = 1 << 31;       // must be negative
+    static final int SS_SEQ       = 1 << 16;       // version count
+
+    // Mode bits for ForkJoinPool.config and WorkQueue.config
+    static final int MODE_MASK    = 0xffff << 16;  // top half of int
+    static final int SPARE_WORKER = 1 << 17;       // set if tc > 0 on creation
+    static final int UNREGISTERED = 1 << 18;       // to skip some of deregister
+    static final int FIFO_QUEUE   = 1 << 31;       // must be negative
+    static final int LIFO_QUEUE   = 0;             // for clarity
+    static final int IS_OWNED     = 1;             // low bit 0 if shared
+
+    /**
+     * The maximum number of task executions from the same queue
+     * before checking other queues, bounding unfairness and impact of
+     * infinite user task recursion.  Must be a power of two minus 1.
+     */
+    static final int POLL_LIMIT = (1 << 10) - 1;
+
+    /**
+     * Queues supporting work-stealing as well as external task
+     * submission. See above for descriptions and algorithms.
+     * Performance on most platforms is very sensitive to placement of
+     * instances of both WorkQueues and their arrays -- we absolutely
+     * do not want multiple WorkQueue instances or multiple queue
+     * arrays sharing cache lines. The @Contended annotation alerts
+     * JVMs to try to keep instances apart.
+     */
+    // Android-removed: @Contended, this hint is not used by the Android runtime.
+    //@jdk.internal.vm.annotation.Contended
+    static final class WorkQueue {
+
+        /**
+         * Capacity of work-stealing queue array upon initialization.
+         * Must be a power of two; at least 4, but should be larger to
+         * reduce or eliminate cacheline sharing among queues.
+         * Currently, it is much larger, as a partial workaround for
+         * the fact that JVMs often place arrays in locations that
+         * share GC bookkeeping (especially cardmarks) such that
+         * per-write accesses encounter serious memory contention.
+         */
+        static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
+
+        /**
+         * Maximum size for queue arrays. Must be a power of two less
+         * than or equal to 1 << (31 - width of array entry) to ensure
+         * lack of wraparound of index calculations, but defined to a
+         * value a bit less than this to help users trap runaway
+         * programs before saturating systems.
+         */
+        static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
+
+        // Instance fields
+
+        volatile int scanState;    // versioned, negative if inactive
+        int stackPred;             // pool stack (ctl) predecessor
+        int nsteals;               // number of steals
+        int hint;                  // randomization and stealer index hint
+        int config;                // pool index and mode
+        volatile int qlock;        // 1: locked, < 0: terminate; else 0
+        volatile int base;         // index of next slot for poll
+        int top;                   // index of next slot for push
+        ForkJoinTask<?>[] array;   // the elements (initially unallocated)
+        final ForkJoinPool pool;   // the containing pool (may be null)
+        final ForkJoinWorkerThread owner; // owning thread or null if shared
+        volatile Thread parker;    // == owner during call to park; else null
+        volatile ForkJoinTask<?> currentJoin; // task being joined in awaitJoin
+
+      // Android-removed: @Contended, this hint is not used by the Android runtime.
+      // @jdk.internal.vm.annotation.Contended("group2") // segregate
+        volatile ForkJoinTask<?> currentSteal; // nonnull when running some task
+
+        WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner) {
+            this.pool = pool;
+            this.owner = owner;
+            // Place indices in the center of array (that is not yet allocated)
+            base = top = INITIAL_QUEUE_CAPACITY >>> 1;
+        }
+
+        /**
+         * Returns an exportable index (used by ForkJoinWorkerThread).
+         */
+        final int getPoolIndex() {
+            return (config & 0xffff) >>> 1; // ignore odd/even tag bit
+        }
+
+        /**
+         * Returns the approximate number of tasks in the queue.
+         */
+        final int queueSize() {
+            int n = base - top;       // read base first
+            return (n >= 0) ? 0 : -n; // ignore transient negative
+        }
+
+        /**
+         * Provides a more accurate estimate of whether this queue has
+         * any tasks than does queueSize, by checking whether a
+         * near-empty queue has at least one unclaimed task.
+         */
+        final boolean isEmpty() {
+            ForkJoinTask<?>[] a; int n, al, s;
+            return ((n = base - (s = top)) >= 0 || // possibly one task
+                    (n == -1 && ((a = array) == null ||
+                                 (al = a.length) == 0 ||
+                                 a[(al - 1) & (s - 1)] == null)));
+        }
+
+        /**
+         * Pushes a task. Call only by owner in unshared queues.
+         *
+         * @param task the task. Caller must ensure non-null.
+         * @throws RejectedExecutionException if array cannot be resized
+         */
+        final void push(ForkJoinTask<?> task) {
+            U.storeFence();              // ensure safe publication
+            int s = top, al, d; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (al = a.length) > 0) {
+                a[(al - 1) & s] = task;  // relaxed writes OK
+                top = s + 1;
+                ForkJoinPool p = pool;
+                if ((d = base - s) == 0 && p != null) {
+                    U.fullFence();
+                    p.signalWork();
+                }
+                else if (al + d == 1)
+                    growArray();
+            }
+        }
+
+        /**
+         * Initializes or doubles the capacity of array. Call either
+         * by owner or with lock held -- it is OK for base, but not
+         * top, to move while resizings are in progress.
+         */
+        final ForkJoinTask<?>[] growArray() {
+            ForkJoinTask<?>[] oldA = array;
+            int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY;
+            if (size < INITIAL_QUEUE_CAPACITY || size > MAXIMUM_QUEUE_CAPACITY)
+                throw new RejectedExecutionException("Queue capacity exceeded");
+            int oldMask, t, b;
+            ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size];
+            if (oldA != null && (oldMask = oldA.length - 1) > 0 &&
+                (t = top) - (b = base) > 0) {
+                int mask = size - 1;
+                do { // emulate poll from old array, push to new array
+                    int index = b & oldMask;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> x = (ForkJoinTask<?>)
+                        U.getObjectVolatile(oldA, offset);
+                    if (x != null &&
+                        U.compareAndSwapObject(oldA, offset, x, null))
+                        a[b & mask] = x;
+                } while (++b != t);
+                U.storeFence();
+            }
+            return a;
+        }
+
+        /**
+         * Takes next task, if one exists, in LIFO order.  Call only
+         * by owner in unshared queues.
+         */
+        final ForkJoinTask<?> pop() {
+            int b = base, s = top, al, i; ForkJoinTask<?>[] a;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & --s;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> t = (ForkJoinTask<?>)
+                    U.getObject(a, offset);
+                if (t != null &&
+                    U.compareAndSwapObject(a, offset, t, null)) {
+                    top = s;
+                    return t;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Takes a task in FIFO order if b is base of queue and a task
+         * can be claimed without contention. Specialized versions
+         * appear in ForkJoinPool methods scan and helpStealer.
+         */
+        final ForkJoinTask<?> pollAt(int b) {
+            ForkJoinTask<?>[] a; int al;
+            if ((a = array) != null && (al = a.length) > 0) {
+                int index = (al - 1) & b;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> t = (ForkJoinTask<?>)
+                    U.getObjectVolatile(a, offset);
+                if (t != null && b++ == base &&
+                    U.compareAndSwapObject(a, offset, t, null)) {
+                    base = b;
+                    return t;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Takes next task, if one exists, in FIFO order.
+         */
+        final ForkJoinTask<?> poll() {
+            for (;;) {
+                int b = base, s = top, d, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && (d = b - s) < 0 &&
+                    (al = a.length) > 0) {
+                    int index = (al - 1) & b;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getObjectVolatile(a, offset);
+                    if (b++ == base) {
+                        if (t != null) {
+                            if (U.compareAndSwapObject(a, offset, t, null)) {
+                                base = b;
+                                return t;
+                            }
+                        }
+                        else if (d == -1)
+                            break; // now empty
+                    }
+                }
+                else
+                    break;
+            }
+            return null;
+        }
+
+        /**
+         * Takes next task, if one exists, in order specified by mode.
+         */
+        final ForkJoinTask<?> nextLocalTask() {
+            return (config < 0) ? poll() : pop();
+        }
+
+        /**
+         * Returns next task, if one exists, in order specified by mode.
+         */
+        final ForkJoinTask<?> peek() {
+            int al; ForkJoinTask<?>[] a;
+            return ((a = array) != null && (al = a.length) > 0) ?
+                a[(al - 1) & (config < 0 ? base : top - 1)] : null;
+        }
+
+        /**
+         * Pops the given task only if it is at the current top.
+         */
+        final boolean tryUnpush(ForkJoinTask<?> task) {
+            int b = base, s = top, al; ForkJoinTask<?>[] a;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & --s;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                if (U.compareAndSwapObject(a, offset, task, null)) {
+                    top = s;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Shared version of push. Fails if already locked.
+         *
+         * @return status: > 0 locked, 0 possibly was empty, < 0 was nonempty
+         */
+        final int sharedPush(ForkJoinTask<?> task) {
+            int stat;
+            if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+                int b = base, s = top, al, d; ForkJoinTask<?>[] a;
+                if ((a = array) != null && (al = a.length) > 0 &&
+                    al - 1 + (d = b - s) > 0) {
+                    a[(al - 1) & s] = task;
+                    top = s + 1;                 // relaxed writes OK here
+                    qlock = 0;
+                    stat = (d < 0 && b == base) ? d : 0;
+                }
+                else {
+                    growAndSharedPush(task);
+                    stat = 0;
+                }
+            }
+            else
+                stat = 1;
+            return stat;
+        }
+
+        /**
+         * Helper for sharedPush; called only when locked and resize
+         * needed.
+         */
+        private void growAndSharedPush(ForkJoinTask<?> task) {
+            try {
+                growArray();
+                int s = top, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && (al = a.length) > 0) {
+                    a[(al - 1) & s] = task;
+                    top = s + 1;
+                }
+            } finally {
+                qlock = 0;
+            }
+        }
+
+        /**
+         * Shared version of tryUnpush.
+         */
+        final boolean trySharedUnpush(ForkJoinTask<?> task) {
+            boolean popped = false;
+            int s = top - 1, al; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (al = a.length) > 0) {
+                int index = (al - 1) & s;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> t = (ForkJoinTask<?>) U.getObject(a, offset);
+                if (t == task &&
+                    U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+                    if (top == s + 1 && array == a &&
+                        U.compareAndSwapObject(a, offset, task, null)) {
+                        popped = true;
+                        top = s;
+                    }
+                    U.putOrderedInt(this, QLOCK, 0);
+                }
+            }
+            return popped;
+        }
+
+        /**
+         * Removes and cancels all known tasks, ignoring any exceptions.
+         */
+        final void cancelAll() {
+            ForkJoinTask<?> t;
+            if ((t = currentJoin) != null) {
+                currentJoin = null;
+                ForkJoinTask.cancelIgnoringExceptions(t);
+            }
+            if ((t = currentSteal) != null) {
+                currentSteal = null;
+                ForkJoinTask.cancelIgnoringExceptions(t);
+            }
+            while ((t = poll()) != null)
+                ForkJoinTask.cancelIgnoringExceptions(t);
+        }
+
+        // Specialized execution methods
+
+        /**
+         * Pops and executes up to POLL_LIMIT tasks or until empty.
+         */
+        final void localPopAndExec() {
+            for (int nexec = 0;;) {
+                int b = base, s = top, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && b != s && (al = a.length) > 0) {
+                    int index = (al - 1) & --s;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getAndSetObject(a, offset, null);
+                    if (t != null) {
+                        top = s;
+                        (currentSteal = t).doExec();
+                        if (++nexec > POLL_LIMIT)
+                            break;
+                    }
+                    else
+                        break;
+                }
+                else
+                    break;
+            }
+        }
+
+        /**
+         * Polls and executes up to POLL_LIMIT tasks or until empty.
+         */
+        final void localPollAndExec() {
+            for (int nexec = 0;;) {
+                int b = base, s = top, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && b != s && (al = a.length) > 0) {
+                    int index = (al - 1) & b++;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getAndSetObject(a, offset, null);
+                    if (t != null) {
+                        base = b;
+                        t.doExec();
+                        if (++nexec > POLL_LIMIT)
+                            break;
+                    }
+                }
+                else
+                    break;
+            }
+        }
+
+        /**
+         * Executes the given task and (some) remaining local tasks.
+         */
+        final void runTask(ForkJoinTask<?> task) {
+            if (task != null) {
+                task.doExec();
+                if (config < 0)
+                    localPollAndExec();
+                else
+                    localPopAndExec();
+                int ns = ++nsteals;
+                ForkJoinWorkerThread thread = owner;
+                currentSteal = null;
+                if (ns < 0)           // collect on overflow
+                    transferStealCount(pool);
+                if (thread != null)
+                    thread.afterTopLevelExec();
+            }
+        }
+
+        /**
+         * Adds steal count to pool steal count if it exists, and resets.
+         */
+        final void transferStealCount(ForkJoinPool p) {
+            AuxState aux;
+            if (p != null && (aux = p.auxState) != null) {
+                long s = nsteals;
+                nsteals = 0;            // if negative, correct for overflow
+                if (s < 0) s = Integer.MAX_VALUE;
+                aux.lock();
+                try {
+                    aux.stealCount += s;
+                } finally {
+                    aux.unlock();
+                }
+            }
+        }
+
+        /**
+         * If present, removes from queue and executes the given task,
+         * or any other cancelled task. Used only by awaitJoin.
+         *
+         * @return true if queue empty and task not known to be done
+         */
+        final boolean tryRemoveAndExec(ForkJoinTask<?> task) {
+            if (task != null && task.status >= 0) {
+                int b, s, d, al; ForkJoinTask<?>[] a;
+                while ((d = (b = base) - (s = top)) < 0 &&
+                       (a = array) != null && (al = a.length) > 0) {
+                    for (;;) {      // traverse from s to b
+                        int index = --s & (al - 1);
+                        long offset = (index << ASHIFT) + ABASE;
+                        ForkJoinTask<?> t = (ForkJoinTask<?>)
+                            U.getObjectVolatile(a, offset);
+                        if (t == null)
+                            break;                   // restart
+                        else if (t == task) {
+                            boolean removed = false;
+                            if (s + 1 == top) {      // pop
+                                if (U.compareAndSwapObject(a, offset, t, null)) {
+                                    top = s;
+                                    removed = true;
+                                }
+                            }
+                            else if (base == b)      // replace with proxy
+                                removed = U.compareAndSwapObject(a, offset, t,
+                                                                 new EmptyTask());
+                            if (removed) {
+                                ForkJoinTask<?> ps = currentSteal;
+                                (currentSteal = task).doExec();
+                                currentSteal = ps;
+                            }
+                            break;
+                        }
+                        else if (t.status < 0 && s + 1 == top) {
+                            if (U.compareAndSwapObject(a, offset, t, null)) {
+                                top = s;
+                            }
+                            break;                  // was cancelled
+                        }
+                        else if (++d == 0) {
+                            if (base != b)          // rescan
+                                break;
+                            return false;
+                        }
+                    }
+                    if (task.status < 0)
+                        return false;
+                }
+            }
+            return true;
+        }
+
+        /**
+         * Pops task if in the same CC computation as the given task,
+         * in either shared or owned mode. Used only by helpComplete.
+         */
+        final CountedCompleter<?> popCC(CountedCompleter<?> task, int mode) {
+            int b = base, s = top, al; ForkJoinTask<?>[] a;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & (s - 1);
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> o = (ForkJoinTask<?>)
+                    U.getObjectVolatile(a, offset);
+                if (o instanceof CountedCompleter) {
+                    CountedCompleter<?> t = (CountedCompleter<?>)o;
+                    for (CountedCompleter<?> r = t;;) {
+                        if (r == task) {
+                            if ((mode & IS_OWNED) == 0) {
+                                boolean popped = false;
+                                if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+                                    if (top == s && array == a &&
+                                        U.compareAndSwapObject(a, offset,
+                                                               t, null)) {
+                                        popped = true;
+                                        top = s - 1;
+                                    }
+                                    U.putOrderedInt(this, QLOCK, 0);
+                                    if (popped)
+                                        return t;
+                                }
+                            }
+                            else if (U.compareAndSwapObject(a, offset,
+                                                            t, null)) {
+                                top = s - 1;
+                                return t;
+                            }
+                            break;
+                        }
+                        else if ((r = r.completer) == null) // try parent
+                            break;
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Steals and runs a task in the same CC computation as the
+         * given task if one exists and can be taken without
+         * contention. Otherwise returns a checksum/control value for
+         * use by method helpComplete.
+         *
+         * @return 1 if successful, 2 if retryable (lost to another
+         * stealer), -1 if non-empty but no matching task found, else
+         * the base index, forced negative.
+         */
+        final int pollAndExecCC(CountedCompleter<?> task) {
+            ForkJoinTask<?>[] a;
+            int b = base, s = top, al, h;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & b;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> o = (ForkJoinTask<?>)
+                    U.getObjectVolatile(a, offset);
+                if (o == null)
+                    h = 2;                      // retryable
+                else if (!(o instanceof CountedCompleter))
+                    h = -1;                     // unmatchable
+                else {
+                    CountedCompleter<?> t = (CountedCompleter<?>)o;
+                    for (CountedCompleter<?> r = t;;) {
+                        if (r == task) {
+                            if (b++ == base &&
+                                U.compareAndSwapObject(a, offset, t, null)) {
+                                base = b;
+                                t.doExec();
+                                h = 1;          // success
+                            }
+                            else
+                                h = 2;          // lost CAS
+                            break;
+                        }
+                        else if ((r = r.completer) == null) {
+                            h = -1;             // unmatched
+                            break;
+                        }
+                    }
+                }
+            }
+            else
+                h = b | Integer.MIN_VALUE;      // to sense movement on re-poll
+            return h;
+        }
+
+        /**
+         * Returns true if owned and not known to be blocked.
+         */
+        final boolean isApparentlyUnblocked() {
+            Thread wt; Thread.State s;
+            return (scanState >= 0 &&
+                    (wt = owner) != null &&
+                    (s = wt.getState()) != Thread.State.BLOCKED &&
+                    s != Thread.State.WAITING &&
+                    s != Thread.State.TIMED_WAITING);
+        }
+
+        // Unsafe mechanics. Note that some are (and must be) the same as in FJP
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long QLOCK;
+        private static final int ABASE;
+        private static final int ASHIFT;
+        static {
+            try {
+                QLOCK = U.objectFieldOffset
+                    (WorkQueue.class.getDeclaredField("qlock"));
+                ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
+                int scale = U.arrayIndexScale(ForkJoinTask[].class);
+                if ((scale & (scale - 1)) != 0)
+                    throw new Error("array index scale not a power of two");
+                ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    // static fields (initialized in static initializer below)
+
+    /**
+     * Creates a new ForkJoinWorkerThread. This factory is used unless
+     * overridden in ForkJoinPool constructors.
+     */
+    public static final ForkJoinWorkerThreadFactory
+        defaultForkJoinWorkerThreadFactory;
+
+    /**
+     * Permission required for callers of methods that may start or
+     * kill threads.  Also used as a static lock in tryInitialize.
+     */
+    static final RuntimePermission modifyThreadPermission;
+
+    /**
+     * Common (static) pool. Non-null for public use unless a static
+     * construction exception, but internal usages null-check on use
+     * to paranoically avoid potential initialization circularities
+     * as well as to simplify generated code.
+     */
+    static final ForkJoinPool common;
+
+    /**
+     * Common pool parallelism. To allow simpler use and management
+     * when common pool threads are disabled, we allow the underlying
+     * common.parallelism field to be zero, but in that case still report
+     * parallelism as 1 to reflect resulting caller-runs mechanics.
+     */
+    static final int COMMON_PARALLELISM;
+
+    /**
+     * Limit on spare thread construction in tryCompensate.
+     */
+    private static final int COMMON_MAX_SPARES;
+
+    /**
+     * Sequence number for creating workerNamePrefix.
+     */
+    private static int poolNumberSequence;
+
+    /**
+     * Returns the next sequence number. We don't expect this to
+     * ever contend, so use simple builtin sync.
+     */
+    private static final synchronized int nextPoolId() {
+        return ++poolNumberSequence;
+    }
+
+    // static configuration constants
+
+    /**
+     * Initial timeout value (in milliseconds) for the thread
+     * triggering quiescence to park waiting for new work. On timeout,
+     * the thread will instead try to shrink the number of workers.
+     * The value should be large enough to avoid overly aggressive
+     * shrinkage during most transient stalls (long GCs etc).
+     */
+    private static final long IDLE_TIMEOUT_MS = 2000L; // 2sec
+
+    /**
+     * Tolerance for idle timeouts, to cope with timer undershoots.
+     */
+    private static final long TIMEOUT_SLOP_MS =   20L; // 20ms
+
+    /**
+     * The default value for COMMON_MAX_SPARES.  Overridable using the
+     * "java.util.concurrent.ForkJoinPool.common.maximumSpares" system
+     * property.  The default value is far in excess of normal
+     * requirements, but also far short of MAX_CAP and typical OS
+     * thread limits, so allows JVMs to catch misuse/abuse before
+     * running out of resources needed to do so.
+     */
+    private static final int DEFAULT_COMMON_MAX_SPARES = 256;
+
+    /**
+     * Increment for seed generators. See class ThreadLocal for
+     * explanation.
+     */
+    private static final int SEED_INCREMENT = 0x9e3779b9;
+
+    /*
+     * Bits and masks for field ctl, packed with 4 16 bit subfields:
+     * AC: Number of active running workers minus target parallelism
+     * TC: Number of total workers minus target parallelism
+     * SS: version count and status of top waiting thread
+     * ID: poolIndex of top of Treiber stack of waiters
+     *
+     * When convenient, we can extract the lower 32 stack top bits
+     * (including version bits) as sp=(int)ctl.  The offsets of counts
+     * by the target parallelism and the positionings of fields makes
+     * it possible to perform the most common checks via sign tests of
+     * fields: When ac is negative, there are not enough active
+     * workers, when tc is negative, there are not enough total
+     * workers.  When sp is non-zero, there are waiting workers.  To
+     * deal with possibly negative fields, we use casts in and out of
+     * "short" and/or signed shifts to maintain signedness.
+     *
+     * Because it occupies uppermost bits, we can add one active count
+     * using getAndAddLong of AC_UNIT, rather than CAS, when returning
+     * from a blocked join.  Other updates entail multiple subfields
+     * and masking, requiring CAS.
+     */
+
+    // Lower and upper word masks
+    private static final long SP_MASK    = 0xffffffffL;
+    private static final long UC_MASK    = ~SP_MASK;
+
+    // Active counts
+    private static final int  AC_SHIFT   = 48;
+    private static final long AC_UNIT    = 0x0001L << AC_SHIFT;
+    private static final long AC_MASK    = 0xffffL << AC_SHIFT;
+
+    // Total counts
+    private static final int  TC_SHIFT   = 32;
+    private static final long TC_UNIT    = 0x0001L << TC_SHIFT;
+    private static final long TC_MASK    = 0xffffL << TC_SHIFT;
+    private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
+
+    // runState bits: SHUTDOWN must be negative, others arbitrary powers of two
+    private static final int  STARTED    = 1;
+    private static final int  STOP       = 1 << 1;
+    private static final int  TERMINATED = 1 << 2;
+    private static final int  SHUTDOWN   = 1 << 31;
+
+    // Instance fields
+    volatile long ctl;                   // main pool control
+    volatile int runState;
+    final int config;                    // parallelism, mode
+    AuxState auxState;                   // lock, steal counts
+    volatile WorkQueue[] workQueues;     // main registry
+    final String workerNamePrefix;       // to create worker name string
+    final ForkJoinWorkerThreadFactory factory;
+    final UncaughtExceptionHandler ueh;  // per-worker UEH
+
+    /**
+     * Instantiates fields upon first submission, or upon shutdown if
+     * no submissions. If checkTermination true, also responds to
+     * termination by external calls submitting tasks.
+     */
+    private void tryInitialize(boolean checkTermination) {
+        if (runState == 0) { // bootstrap by locking static field
+            int p = config & SMASK;
+            int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots
+            n |= n >>> 1;    // create workQueues array with size a power of two
+            n |= n >>> 2;
+            n |= n >>> 4;
+            n |= n >>> 8;
+            n |= n >>> 16;
+            n = ((n + 1) << 1) & SMASK;
+            AuxState aux = new AuxState();
+            WorkQueue[] ws = new WorkQueue[n];
+            synchronized (modifyThreadPermission) { // double-check
+                if (runState == 0) {
+                    workQueues = ws;
+                    auxState = aux;
+                    runState = STARTED;
+                }
+            }
+        }
+        if (checkTermination && runState < 0) {
+            tryTerminate(false, false); // help terminate
+            throw new RejectedExecutionException();
+        }
+    }
+
+    // Creating, registering and deregistering workers
+
+    /**
+     * Tries to construct and start one worker. Assumes that total
+     * count has already been incremented as a reservation.  Invokes
+     * deregisterWorker on any failure.
+     *
+     * @param isSpare true if this is a spare thread
+     * @return true if successful
+     */
+    private boolean createWorker(boolean isSpare) {
+        ForkJoinWorkerThreadFactory fac = factory;
+        Throwable ex = null;
+        ForkJoinWorkerThread wt = null;
+        WorkQueue q;
+        try {
+            if (fac != null && (wt = fac.newThread(this)) != null) {
+                if (isSpare && (q = wt.workQueue) != null)
+                    q.config |= SPARE_WORKER;
+                wt.start();
+                return true;
+            }
+        } catch (Throwable rex) {
+            ex = rex;
+        }
+        deregisterWorker(wt, ex);
+        return false;
+    }
+
+    /**
+     * Tries to add one worker, incrementing ctl counts before doing
+     * so, relying on createWorker to back out on failure.
+     *
+     * @param c incoming ctl value, with total count negative and no
+     * idle workers.  On CAS failure, c is refreshed and retried if
+     * this holds (otherwise, a new worker is not needed).
+     */
+    private void tryAddWorker(long c) {
+        do {
+            long nc = ((AC_MASK & (c + AC_UNIT)) |
+                       (TC_MASK & (c + TC_UNIT)));
+            if (ctl == c && U.compareAndSwapLong(this, CTL, c, nc)) {
+                createWorker(false);
+                break;
+            }
+        } while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0);
+    }
+
+    /**
+     * Callback from ForkJoinWorkerThread constructor to establish and
+     * record its WorkQueue.
+     *
+     * @param wt the worker thread
+     * @return the worker's queue
+     */
+    final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
+        UncaughtExceptionHandler handler;
+        AuxState aux;
+        wt.setDaemon(true);                           // configure thread
+        if ((handler = ueh) != null)
+            wt.setUncaughtExceptionHandler(handler);
+        WorkQueue w = new WorkQueue(this, wt);
+        int i = 0;                                    // assign a pool index
+        int mode = config & MODE_MASK;
+        if ((aux = auxState) != null) {
+            aux.lock();
+            try {
+                int s = (int)(aux.indexSeed += SEED_INCREMENT), n, m;
+                WorkQueue[] ws = workQueues;
+                if (ws != null && (n = ws.length) > 0) {
+                    i = (m = n - 1) & ((s << 1) | 1); // odd-numbered indices
+                    if (ws[i] != null) {              // collision
+                        int probes = 0;               // step by approx half n
+                        int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
+                        while (ws[i = (i + step) & m] != null) {
+                            if (++probes >= n) {
+                                workQueues = ws = Arrays.copyOf(ws, n <<= 1);
+                                m = n - 1;
+                                probes = 0;
+                            }
+                        }
+                    }
+                    w.hint = s;                       // use as random seed
+                    w.config = i | mode;
+                    w.scanState = i | (s & 0x7fff0000); // random seq bits
+                    ws[i] = w;
+                }
+            } finally {
+                aux.unlock();
+            }
+        }
+        wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1)));
+        return w;
+    }
+
+    /**
+     * Final callback from terminating worker, as well as upon failure
+     * to construct or start a worker.  Removes record of worker from
+     * array, and adjusts counts. If pool is shutting down, tries to
+     * complete termination.
+     *
+     * @param wt the worker thread, or null if construction failed
+     * @param ex the exception causing failure, or null if none
+     */
+    final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
+        WorkQueue w = null;
+        if (wt != null && (w = wt.workQueue) != null) {
+            AuxState aux; WorkQueue[] ws;          // remove index from array
+            int idx = w.config & SMASK;
+            int ns = w.nsteals;
+            if ((aux = auxState) != null) {
+                aux.lock();
+                try {
+                    if ((ws = workQueues) != null && ws.length > idx &&
+                        ws[idx] == w)
+                        ws[idx] = null;
+                    aux.stealCount += ns;
+                } finally {
+                    aux.unlock();
+                }
+            }
+        }
+        if (w == null || (w.config & UNREGISTERED) == 0) { // else pre-adjusted
+            long c;                                   // decrement counts
+            do {} while (!U.compareAndSwapLong
+                         (this, CTL, c = ctl, ((AC_MASK & (c - AC_UNIT)) |
+                                               (TC_MASK & (c - TC_UNIT)) |
+                                               (SP_MASK & c))));
+        }
+        if (w != null) {
+            w.currentSteal = null;
+            w.qlock = -1;                             // ensure set
+            w.cancelAll();                            // cancel remaining tasks
+        }
+        while (tryTerminate(false, false) >= 0) {     // possibly replace
+            WorkQueue[] ws; int wl, sp; long c;
+            if (w == null || w.array == null ||
+                (ws = workQueues) == null || (wl = ws.length) <= 0)
+                break;
+            else if ((sp = (int)(c = ctl)) != 0) {    // wake up replacement
+                if (tryRelease(c, ws[(wl - 1) & sp], AC_UNIT))
+                    break;
+            }
+            else if (ex != null && (c & ADD_WORKER) != 0L) {
+                tryAddWorker(c);                      // create replacement
+                break;
+            }
+            else                                      // don't need replacement
+                break;
+        }
+        if (ex == null)                               // help clean on way out
+            ForkJoinTask.helpExpungeStaleExceptions();
+        else                                          // rethrow
+            ForkJoinTask.rethrow(ex);
+    }
+
+    // Signalling
+
+    /**
+     * Tries to create or activate a worker if too few are active.
+     */
+    final void signalWork() {
+        for (;;) {
+            long c; int sp, i; WorkQueue v; WorkQueue[] ws;
+            if ((c = ctl) >= 0L)                      // enough workers
+                break;
+            else if ((sp = (int)c) == 0) {            // no idle workers
+                if ((c & ADD_WORKER) != 0L)           // too few workers
+                    tryAddWorker(c);
+                break;
+            }
+            else if ((ws = workQueues) == null)
+                break;                                // unstarted/terminated
+            else if (ws.length <= (i = sp & SMASK))
+                break;                                // terminated
+            else if ((v = ws[i]) == null)
+                break;                                // terminating
+            else {
+                int ns = sp & ~UNSIGNALLED;
+                int vs = v.scanState;
+                long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
+                if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
+                    v.scanState = ns;
+                    LockSupport.unpark(v.parker);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Signals and releases worker v if it is top of idle worker
+     * stack.  This performs a one-shot version of signalWork only if
+     * there is (apparently) at least one idle worker.
+     *
+     * @param c incoming ctl value
+     * @param v if non-null, a worker
+     * @param inc the increment to active count (zero when compensating)
+     * @return true if successful
+     */
+    private boolean tryRelease(long c, WorkQueue v, long inc) {
+        int sp = (int)c, ns = sp & ~UNSIGNALLED;
+        if (v != null) {
+            int vs = v.scanState;
+            long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + inc));
+            if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
+                v.scanState = ns;
+                LockSupport.unpark(v.parker);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * With approx probability of a missed signal, tries (once) to
+     * reactivate worker w (or some other worker), failing if stale or
+     * known to be already active.
+     *
+     * @param w the worker
+     * @param ws the workQueue array to use
+     * @param r random seed
+     */
+    private void tryReactivate(WorkQueue w, WorkQueue[] ws, int r) {
+        long c; int sp, wl; WorkQueue v;
+        if ((sp = (int)(c = ctl)) != 0 && w != null &&
+            ws != null && (wl = ws.length) > 0 &&
+            ((sp ^ r) & SS_SEQ) == 0 &&
+            (v = ws[(wl - 1) & sp]) != null) {
+            long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
+            int ns = sp & ~UNSIGNALLED;
+            if (w.scanState < 0 &&
+                v.scanState == sp &&
+                U.compareAndSwapLong(this, CTL, c, nc)) {
+                v.scanState = ns;
+                LockSupport.unpark(v.parker);
+            }
+        }
+    }
+
+    /**
+     * If worker w exists and is active, enqueues and sets status to inactive.
+     *
+     * @param w the worker
+     * @param ss current (non-negative) scanState
+     */
+    private void inactivate(WorkQueue w, int ss) {
+        int ns = (ss + SS_SEQ) | UNSIGNALLED;
+        long lc = ns & SP_MASK, nc, c;
+        if (w != null) {
+            w.scanState = ns;
+            do {
+                nc = lc | (UC_MASK & ((c = ctl) - AC_UNIT));
+                w.stackPred = (int)c;
+            } while (!U.compareAndSwapLong(this, CTL, c, nc));
+        }
+    }
+
+    /**
+     * Possibly blocks worker w waiting for signal, or returns
+     * negative status if the worker should terminate. May return
+     * without status change if multiple stale unparks and/or
+     * interrupts occur.
+     *
+     * @param w the calling worker
+     * @return negative if w should terminate
+     */
+    private int awaitWork(WorkQueue w) {
+        int stat = 0;
+        if (w != null && w.scanState < 0) {
+            long c = ctl;
+            if ((int)(c >> AC_SHIFT) + (config & SMASK) <= 0)
+                stat = timedAwaitWork(w, c);     // possibly quiescent
+            else if ((runState & STOP) != 0)
+                stat = w.qlock = -1;             // pool terminating
+            else if (w.scanState < 0) {
+                w.parker = Thread.currentThread();
+                if (w.scanState < 0)             // recheck after write
+                    LockSupport.park(this);
+                w.parker = null;
+                if ((runState & STOP) != 0)
+                    stat = w.qlock = -1;         // recheck
+                else if (w.scanState < 0)
+                    Thread.interrupted();        // clear status
+            }
+        }
+        return stat;
+    }
+
+    /**
+     * Possibly triggers shutdown and tries (once) to block worker
+     * when pool is (or may be) quiescent. Waits up to a duration
+     * determined by number of workers.  On timeout, if ctl has not
+     * changed, terminates the worker, which will in turn wake up
+     * another worker to possibly repeat this process.
+     *
+     * @param w the calling worker
+     * @return negative if w should terminate
+     */
+    private int timedAwaitWork(WorkQueue w, long c) {
+        int stat = 0;
+        int scale = 1 - (short)(c >>> TC_SHIFT);
+        long deadline = (((scale <= 0) ? 1 : scale) * IDLE_TIMEOUT_MS +
+                         System.currentTimeMillis());
+        if ((runState >= 0 || (stat = tryTerminate(false, false)) > 0) &&
+            w != null && w.scanState < 0) {
+            int ss; AuxState aux;
+            w.parker = Thread.currentThread();
+            if (w.scanState < 0)
+                LockSupport.parkUntil(this, deadline);
+            w.parker = null;
+            if ((runState & STOP) != 0)
+                stat = w.qlock = -1;         // pool terminating
+            else if ((ss = w.scanState) < 0 && !Thread.interrupted() &&
+                     (int)c == ss && (aux = auxState) != null && ctl == c &&
+                     deadline - System.currentTimeMillis() <= TIMEOUT_SLOP_MS) {
+                aux.lock();
+                try {                        // pre-deregister
+                    WorkQueue[] ws;
+                    int cfg = w.config, idx = cfg & SMASK;
+                    long nc = ((UC_MASK & (c - TC_UNIT)) |
+                               (SP_MASK & w.stackPred));
+                    if ((runState & STOP) == 0 &&
+                        (ws = workQueues) != null &&
+                        idx < ws.length && idx >= 0 && ws[idx] == w &&
+                        U.compareAndSwapLong(this, CTL, c, nc)) {
+                        ws[idx] = null;
+                        w.config = cfg | UNREGISTERED;
+                        stat = w.qlock = -1;
+                    }
+                } finally {
+                    aux.unlock();
+                }
+            }
+        }
+        return stat;
+    }
+
+    /**
+     * If the given worker is a spare with no queued tasks, and there
+     * are enough existing workers, drops it from ctl counts and sets
+     * its state to terminated.
+     *
+     * @param w the calling worker -- must be a spare
+     * @return true if dropped (in which case it must not process more tasks)
+     */
+    private boolean tryDropSpare(WorkQueue w) {
+        if (w != null && w.isEmpty()) {           // no local tasks
+            long c; int sp, wl; WorkQueue[] ws; WorkQueue v;
+            while ((short)((c = ctl) >> TC_SHIFT) > 0 &&
+                   ((sp = (int)c) != 0 || (int)(c >> AC_SHIFT) > 0) &&
+                   (ws = workQueues) != null && (wl = ws.length) > 0) {
+                boolean dropped, canDrop;
+                if (sp == 0) {                    // no queued workers
+                    long nc = ((AC_MASK & (c - AC_UNIT)) |
+                               (TC_MASK & (c - TC_UNIT)) | (SP_MASK & c));
+                    dropped = U.compareAndSwapLong(this, CTL, c, nc);
+                }
+                else if (
+                    (v = ws[(wl - 1) & sp]) == null || v.scanState != sp)
+                    dropped = false;              // stale; retry
+                else {
+                    long nc = v.stackPred & SP_MASK;
+                    if (w == v || w.scanState >= 0) {
+                        canDrop = true;           // w unqueued or topmost
+                        nc |= ((AC_MASK & c) |    // ensure replacement
+                               (TC_MASK & (c - TC_UNIT)));
+                    }
+                    else {                        // w may be queued
+                        canDrop = false;          // help uncover
+                        nc |= ((AC_MASK & (c + AC_UNIT)) |
+                               (TC_MASK & c));
+                    }
+                    if (U.compareAndSwapLong(this, CTL, c, nc)) {
+                        v.scanState = sp & ~UNSIGNALLED;
+                        LockSupport.unpark(v.parker);
+                        dropped = canDrop;
+                    }
+                    else
+                        dropped = false;
+                }
+                if (dropped) {                    // pre-deregister
+                    int cfg = w.config, idx = cfg & SMASK;
+                    if (idx >= 0 && idx < ws.length && ws[idx] == w)
+                        ws[idx] = null;
+                    w.config = cfg | UNREGISTERED;
+                    w.qlock = -1;
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Top-level runloop for workers, called by ForkJoinWorkerThread.run.
+     */
+    final void runWorker(WorkQueue w) {
+        w.growArray();                                  // allocate queue
+        int bound = (w.config & SPARE_WORKER) != 0 ? 0 : POLL_LIMIT;
+        long seed = w.hint * 0xdaba0b6eb09322e3L;       // initial random seed
+        if ((runState & STOP) == 0) {
+            for (long r = (seed == 0L) ? 1L : seed;;) { // ensure nonzero
+                if (bound == 0 && tryDropSpare(w))
+                    break;
+                // high bits of prev seed for step; current low bits for idx
+                int step = (int)(r >>> 48) | 1;
+                r ^= r >>> 12; r ^= r << 25; r ^= r >>> 27; // xorshift
+                if (scan(w, bound, step, (int)r) < 0 && awaitWork(w) < 0)
+                    break;
+            }
+        }
+    }
+
+    // Scanning for tasks
+
+    /**
+     * Repeatedly scans for and tries to steal and execute (via
+     * workQueue.runTask) a queued task. Each scan traverses queues in
+     * pseudorandom permutation. Upon finding a non-empty queue, makes
+     * at most the given bound attempts to re-poll (fewer if
+     * contended) on the same queue before returning (impossible
+     * scanState value) 0 to restart scan. Else returns after at least
+     * 1 and at most 32 full scans.
+     *
+     * @param w the worker (via its WorkQueue)
+     * @param bound repoll bound as bitmask (0 if spare)
+     * @param step (circular) index increment per iteration (must be odd)
+     * @param r a random seed for origin index
+     * @return negative if should await signal
+     */
+    private int scan(WorkQueue w, int bound, int step, int r) {
+        int stat = 0, wl; WorkQueue[] ws;
+        if ((ws = workQueues) != null && w != null && (wl = ws.length) > 0) {
+            for (int m = wl - 1,
+                     origin = m & r, idx = origin,
+                     npolls = 0,
+                     ss = w.scanState;;) {         // negative if inactive
+                WorkQueue q; ForkJoinTask<?>[] a; int b, al;
+                if ((q = ws[idx]) != null && (b = q.base) - q.top < 0 &&
+                    (a = q.array) != null && (al = a.length) > 0) {
+                    int index = (al - 1) & b;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getObjectVolatile(a, offset);
+                    if (t == null)
+                        break;                     // empty or busy
+                    else if (b++ != q.base)
+                        break;                     // busy
+                    else if (ss < 0) {
+                        tryReactivate(w, ws, r);
+                        break;                     // retry upon rescan
+                    }
+                    else if (!U.compareAndSwapObject(a, offset, t, null))
+                        break;                     // contended
+                    else {
+                        q.base = b;
+                        w.currentSteal = t;
+                        if (b != q.top)            // propagate signal
+                            signalWork();
+                        w.runTask(t);
+                        if (++npolls > bound)
+                            break;
+                    }
+                }
+                else if (npolls != 0)              // rescan
+                    break;
+                else if ((idx = (idx + step) & m) == origin) {
+                    if (ss < 0) {                  // await signal
+                        stat = ss;
+                        break;
+                    }
+                    else if (r >= 0) {
+                        inactivate(w, ss);
+                        break;
+                    }
+                    else
+                        r <<= 1;                   // at most 31 rescans
+                }
+            }
+        }
+        return stat;
+    }
+
+    // Joining tasks
+
+    /**
+     * Tries to steal and run tasks within the target's computation.
+     * Uses a variant of the top-level algorithm, restricted to tasks
+     * with the given task as ancestor: It prefers taking and running
+     * eligible tasks popped from the worker's own queue (via
+     * popCC). Otherwise it scans others, randomly moving on
+     * contention or execution, deciding to give up based on a
+     * checksum (via return codes from pollAndExecCC). The maxTasks
+     * argument supports external usages; internal calls use zero,
+     * allowing unbounded steps (external calls trap non-positive
+     * values).
+     *
+     * @param w caller
+     * @param maxTasks if non-zero, the maximum number of other tasks to run
+     * @return task status on exit
+     */
+    final int helpComplete(WorkQueue w, CountedCompleter<?> task,
+                           int maxTasks) {
+        WorkQueue[] ws; int s = 0, wl;
+        if ((ws = workQueues) != null && (wl = ws.length) > 1 &&
+            task != null && w != null) {
+            for (int m = wl - 1,
+                     mode = w.config,
+                     r = ~mode,                  // scanning seed
+                     origin = r & m, k = origin, // first queue to scan
+                     step = 3,                   // first scan step
+                     h = 1,                      // 1:ran, >1:contended, <0:hash
+                     oldSum = 0, checkSum = 0;;) {
+                CountedCompleter<?> p; WorkQueue q; int i;
+                if ((s = task.status) < 0)
+                    break;
+                if (h == 1 && (p = w.popCC(task, mode)) != null) {
+                    p.doExec();                  // run local task
+                    if (maxTasks != 0 && --maxTasks == 0)
+                        break;
+                    origin = k;                  // reset
+                    oldSum = checkSum = 0;
+                }
+                else {                           // poll other worker queues
+                    if ((i = k | 1) < 0 || i > m || (q = ws[i]) == null)
+                        h = 0;
+                    else if ((h = q.pollAndExecCC(task)) < 0)
+                        checkSum += h;
+                    if (h > 0) {
+                        if (h == 1 && maxTasks != 0 && --maxTasks == 0)
+                            break;
+                        step = (r >>> 16) | 3;
+                        r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
+                        k = origin = r & m;      // move and restart
+                        oldSum = checkSum = 0;
+                    }
+                    else if ((k = (k + step) & m) == origin) {
+                        if (oldSum == (oldSum = checkSum))
+                            break;
+                        checkSum = 0;
+                    }
+                }
+            }
+        }
+        return s;
+    }
+
+    /**
+     * Tries to locate and execute tasks for a stealer of the given
+     * task, or in turn one of its stealers. Traces currentSteal ->
+     * currentJoin links looking for a thread working on a descendant
+     * of the given task and with a non-empty queue to steal back and
+     * execute tasks from. The first call to this method upon a
+     * waiting join will often entail scanning/search, (which is OK
+     * because the joiner has nothing better to do), but this method
+     * leaves hints in workers to speed up subsequent calls.
+     *
+     * @param w caller
+     * @param task the task to join
+     */
+    private void helpStealer(WorkQueue w, ForkJoinTask<?> task) {
+        if (task != null && w != null) {
+            ForkJoinTask<?> ps = w.currentSteal;
+            WorkQueue[] ws; int wl, oldSum = 0;
+            outer: while (w.tryRemoveAndExec(task) && task.status >= 0 &&
+                          (ws = workQueues) != null && (wl = ws.length) > 0) {
+                ForkJoinTask<?> subtask;
+                int m = wl - 1, checkSum = 0;          // for stability check
+                WorkQueue j = w, v;                    // v is subtask stealer
+                descent: for (subtask = task; subtask.status >= 0; ) {
+                    for (int h = j.hint | 1, k = 0, i;;) {
+                        if ((v = ws[i = (h + (k << 1)) & m]) != null) {
+                            if (v.currentSteal == subtask) {
+                                j.hint = i;
+                                break;
+                            }
+                            checkSum += v.base;
+                        }
+                        if (++k > m)                   // can't find stealer
+                            break outer;
+                    }
+
+                    for (;;) {                         // help v or descend
+                        ForkJoinTask<?>[] a; int b, al;
+                        if (subtask.status < 0)        // too late to help
+                            break descent;
+                        checkSum += (b = v.base);
+                        ForkJoinTask<?> next = v.currentJoin;
+                        ForkJoinTask<?> t = null;
+                        if ((a = v.array) != null && (al = a.length) > 0) {
+                            int index = (al - 1) & b;
+                            long offset = ((long)index << ASHIFT) + ABASE;
+                            t = (ForkJoinTask<?>)
+                                U.getObjectVolatile(a, offset);
+                            if (t != null && b++ == v.base) {
+                                if (j.currentJoin != subtask ||
+                                    v.currentSteal != subtask ||
+                                    subtask.status < 0)
+                                    break descent;     // stale
+                                if (U.compareAndSwapObject(a, offset, t, null)) {
+                                    v.base = b;
+                                    w.currentSteal = t;
+                                    for (int top = w.top;;) {
+                                        t.doExec();    // help
+                                        w.currentSteal = ps;
+                                        if (task.status < 0)
+                                            break outer;
+                                        if (w.top == top)
+                                            break;     // run local tasks
+                                        if ((t = w.pop()) == null)
+                                            break descent;
+                                        w.currentSteal = t;
+                                    }
+                                }
+                            }
+                        }
+                        if (t == null && b == v.base && b - v.top >= 0) {
+                            if ((subtask = next) == null) {  // try to descend
+                                if (next == v.currentJoin &&
+                                    oldSum == (oldSum = checkSum))
+                                    break outer;
+                                break descent;
+                            }
+                            j = v;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Tries to decrement active count (sometimes implicitly) and
+     * possibly release or create a compensating worker in preparation
+     * for blocking. Returns false (retryable by caller), on
+     * contention, detected staleness, instability, or termination.
+     *
+     * @param w caller
+     */
+    private boolean tryCompensate(WorkQueue w) {
+        boolean canBlock; int wl;
+        long c = ctl;
+        WorkQueue[] ws = workQueues;
+        int pc = config & SMASK;
+        int ac = pc + (int)(c >> AC_SHIFT);
+        int tc = pc + (short)(c >> TC_SHIFT);
+        if (w == null || w.qlock < 0 || pc == 0 ||  // terminating or disabled
+            ws == null || (wl = ws.length) <= 0)
+            canBlock = false;
+        else {
+            int m = wl - 1, sp;
+            boolean busy = true;                    // validate ac
+            for (int i = 0; i <= m; ++i) {
+                int k; WorkQueue v;
+                if ((k = (i << 1) | 1) <= m && k >= 0 && (v = ws[k]) != null &&
+                    v.scanState >= 0 && v.currentSteal == null) {
+                    busy = false;
+                    break;
+                }
+            }
+            if (!busy || ctl != c)
+                canBlock = false;                   // unstable or stale
+            else if ((sp = (int)c) != 0)            // release idle worker
+                canBlock = tryRelease(c, ws[m & sp], 0L);
+            else if (tc >= pc && ac > 1 && w.isEmpty()) {
+                long nc = ((AC_MASK & (c - AC_UNIT)) |
+                           (~AC_MASK & c));         // uncompensated
+                canBlock = U.compareAndSwapLong(this, CTL, c, nc);
+            }
+            else if (tc >= MAX_CAP ||
+                     (this == common && tc >= pc + COMMON_MAX_SPARES))
+                throw new RejectedExecutionException(
+                    "Thread limit exceeded replacing blocked worker");
+            else {                                  // similar to tryAddWorker
+                boolean isSpare = (tc >= pc);
+                long nc = (AC_MASK & c) | (TC_MASK & (c + TC_UNIT));
+                canBlock = (U.compareAndSwapLong(this, CTL, c, nc) &&
+                            createWorker(isSpare)); // throws on exception
+            }
+        }
+        return canBlock;
+    }
+
+    /**
+     * Helps and/or blocks until the given task is done or timeout.
+     *
+     * @param w caller
+     * @param task the task
+     * @param deadline for timed waits, if nonzero
+     * @return task status on exit
+     */
+    final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {
+        int s = 0;
+        if (w != null) {
+            ForkJoinTask<?> prevJoin = w.currentJoin;
+            if (task != null && (s = task.status) >= 0) {
+                w.currentJoin = task;
+                CountedCompleter<?> cc = (task instanceof CountedCompleter) ?
+                    (CountedCompleter<?>)task : null;
+                for (;;) {
+                    if (cc != null)
+                        helpComplete(w, cc, 0);
+                    else
+                        helpStealer(w, task);
+                    if ((s = task.status) < 0)
+                        break;
+                    long ms, ns;
+                    if (deadline == 0L)
+                        ms = 0L;
+                    else if ((ns = deadline - System.nanoTime()) <= 0L)
+                        break;
+                    else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
+                        ms = 1L;
+                    if (tryCompensate(w)) {
+                        task.internalWait(ms);
+                        U.getAndAddLong(this, CTL, AC_UNIT);
+                    }
+                    if ((s = task.status) < 0)
+                        break;
+                }
+                w.currentJoin = prevJoin;
+            }
+        }
+        return s;
+    }
+
+    // Specialized scanning
+
+    /**
+     * Returns a (probably) non-empty steal queue, if one is found
+     * during a scan, else null.  This method must be retried by
+     * caller if, by the time it tries to use the queue, it is empty.
+     */
+    private WorkQueue findNonEmptyStealQueue() {
+        WorkQueue[] ws; int wl;  // one-shot version of scan loop
+        int r = ThreadLocalRandom.nextSecondarySeed();
+        if ((ws = workQueues) != null && (wl = ws.length) > 0) {
+            int m = wl - 1, origin = r & m;
+            for (int k = origin, oldSum = 0, checkSum = 0;;) {
+                WorkQueue q; int b;
+                if ((q = ws[k]) != null) {
+                    if ((b = q.base) - q.top < 0)
+                        return q;
+                    checkSum += b;
+                }
+                if ((k = (k + 1) & m) == origin) {
+                    if (oldSum == (oldSum = checkSum))
+                        break;
+                    checkSum = 0;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Runs tasks until {@code isQuiescent()}. We piggyback on
+     * active count ctl maintenance, but rather than blocking
+     * when tasks cannot be found, we rescan until all others cannot
+     * find tasks either.
+     */
+    final void helpQuiescePool(WorkQueue w) {
+        ForkJoinTask<?> ps = w.currentSteal; // save context
+        int wc = w.config;
+        for (boolean active = true;;) {
+            long c; WorkQueue q; ForkJoinTask<?> t;
+            if (wc >= 0 && (t = w.pop()) != null) { // run locals if LIFO
+                (w.currentSteal = t).doExec();
+                w.currentSteal = ps;
+            }
+            else if ((q = findNonEmptyStealQueue()) != null) {
+                if (!active) {      // re-establish active count
+                    active = true;
+                    U.getAndAddLong(this, CTL, AC_UNIT);
+                }
+                if ((t = q.pollAt(q.base)) != null) {
+                    (w.currentSteal = t).doExec();
+                    w.currentSteal = ps;
+                    if (++w.nsteals < 0)
+                        w.transferStealCount(this);
+                }
+            }
+            else if (active) {      // decrement active count without queuing
+                long nc = (AC_MASK & ((c = ctl) - AC_UNIT)) | (~AC_MASK & c);
+                if (U.compareAndSwapLong(this, CTL, c, nc))
+                    active = false;
+            }
+            else if ((int)((c = ctl) >> AC_SHIFT) + (config & SMASK) <= 0 &&
+                     U.compareAndSwapLong(this, CTL, c, c + AC_UNIT))
+                break;
+        }
+    }
+
+    /**
+     * Gets and removes a local or stolen task for the given worker.
+     *
+     * @return a task, if available
+     */
+    final ForkJoinTask<?> nextTaskFor(WorkQueue w) {
+        for (ForkJoinTask<?> t;;) {
+            WorkQueue q;
+            if ((t = w.nextLocalTask()) != null)
+                return t;
+            if ((q = findNonEmptyStealQueue()) == null)
+                return null;
+            if ((t = q.pollAt(q.base)) != null)
+                return t;
+        }
+    }
+
+    /**
+     * Returns a cheap heuristic guide for task partitioning when
+     * programmers, frameworks, tools, or languages have little or no
+     * idea about task granularity.  In essence, by offering this
+     * method, we ask users only about tradeoffs in overhead vs
+     * expected throughput and its variance, rather than how finely to
+     * partition tasks.
+     *
+     * In a steady state strict (tree-structured) computation, each
+     * thread makes available for stealing enough tasks for other
+     * threads to remain active. Inductively, if all threads play by
+     * the same rules, each thread should make available only a
+     * constant number of tasks.
+     *
+     * The minimum useful constant is just 1. But using a value of 1
+     * would require immediate replenishment upon each steal to
+     * maintain enough tasks, which is infeasible.  Further,
+     * partitionings/granularities of offered tasks should minimize
+     * steal rates, which in general means that threads nearer the top
+     * of computation tree should generate more than those nearer the
+     * bottom. In perfect steady state, each thread is at
+     * approximately the same level of computation tree. However,
+     * producing extra tasks amortizes the uncertainty of progress and
+     * diffusion assumptions.
+     *
+     * So, users will want to use values larger (but not much larger)
+     * than 1 to both smooth over transient shortages and hedge
+     * against uneven progress; as traded off against the cost of
+     * extra task overhead. We leave the user to pick a threshold
+     * value to compare with the results of this call to guide
+     * decisions, but recommend values such as 3.
+     *
+     * When all threads are active, it is on average OK to estimate
+     * surplus strictly locally. In steady-state, if one thread is
+     * maintaining say 2 surplus tasks, then so are others. So we can
+     * just use estimated queue length.  However, this strategy alone
+     * leads to serious mis-estimates in some non-steady-state
+     * conditions (ramp-up, ramp-down, other stalls). We can detect
+     * many of these by further considering the number of "idle"
+     * threads, that are known to have zero queued tasks, so
+     * compensate by a factor of (#idle/#active) threads.
+     */
+    static int getSurplusQueuedTaskCount() {
+        Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
+            int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).config & SMASK;
+            int n = (q = wt.workQueue).top - q.base;
+            int a = (int)(pool.ctl >> AC_SHIFT) + p;
+            return n - (a > (p >>>= 1) ? 0 :
+                        a > (p >>>= 1) ? 1 :
+                        a > (p >>>= 1) ? 2 :
+                        a > (p >>>= 1) ? 4 :
+                        8);
+        }
+        return 0;
+    }
+
+    //  Termination
+
+    /**
+     * Possibly initiates and/or completes termination.
+     *
+     * @param now if true, unconditionally terminate, else only
+     * if no work and no active workers
+     * @param enable if true, terminate when next possible
+     * @return -1: terminating/terminated, 0: retry if internal caller, else 1
+     */
+    private int tryTerminate(boolean now, boolean enable) {
+        int rs; // 3 phases: try to set SHUTDOWN, then STOP, then TERMINATED
+
+        while ((rs = runState) >= 0) {
+            if (!enable || this == common)        // cannot shutdown
+                return 1;
+            else if (rs == 0)
+                tryInitialize(false);             // ensure initialized
+            else
+                U.compareAndSwapInt(this, RUNSTATE, rs, rs | SHUTDOWN);
+        }
+
+        if ((rs & STOP) == 0) {                   // try to initiate termination
+            if (!now) {                           // check quiescence
+                for (long oldSum = 0L;;) {        // repeat until stable
+                    WorkQueue[] ws; WorkQueue w; int b;
+                    long checkSum = ctl;
+                    if ((int)(checkSum >> AC_SHIFT) + (config & SMASK) > 0)
+                        return 0;                 // still active workers
+                    if ((ws = workQueues) != null) {
+                        for (int i = 0; i < ws.length; ++i) {
+                            if ((w = ws[i]) != null) {
+                                checkSum += (b = w.base);
+                                if (w.currentSteal != null || b != w.top)
+                                    return 0;     // retry if internal caller
+                            }
+                        }
+                    }
+                    if (oldSum == (oldSum = checkSum))
+                        break;
+                }
+            }
+            do {} while (!U.compareAndSwapInt(this, RUNSTATE,
+                                              rs = runState, rs | STOP));
+        }
+
+        for (long oldSum = 0L;;) {                // repeat until stable
+            WorkQueue[] ws; WorkQueue w; ForkJoinWorkerThread wt;
+            long checkSum = ctl;
+            if ((ws = workQueues) != null) {      // help terminate others
+                for (int i = 0; i < ws.length; ++i) {
+                    if ((w = ws[i]) != null) {
+                        w.cancelAll();            // clear queues
+                        checkSum += w.base;
+                        if (w.qlock >= 0) {
+                            w.qlock = -1;         // racy set OK
+                            if ((wt = w.owner) != null) {
+                                try {             // unblock join or park
+                                    wt.interrupt();
+                                } catch (Throwable ignore) {
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if (oldSum == (oldSum = checkSum))
+                break;
+        }
+
+        if ((short)(ctl >>> TC_SHIFT) + (config & SMASK) <= 0) {
+            runState = (STARTED | SHUTDOWN | STOP | TERMINATED); // final write
+            synchronized (this) {
+                notifyAll();                      // for awaitTermination
+            }
+        }
+
+        return -1;
+    }
+
+    // External operations
+
+    /**
+     * Constructs and tries to install a new external queue,
+     * failing if the workQueues array already has a queue at
+     * the given index.
+     *
+     * @param index the index of the new queue
+     */
+    private void tryCreateExternalQueue(int index) {
+        AuxState aux;
+        if ((aux = auxState) != null && index >= 0) {
+            WorkQueue q = new WorkQueue(this, null);
+            q.config = index;
+            q.scanState = ~UNSIGNALLED;
+            q.qlock = 1;                   // lock queue
+            boolean installed = false;
+            aux.lock();
+            try {                          // lock pool to install
+                WorkQueue[] ws;
+                if ((ws = workQueues) != null && index < ws.length &&
+                    ws[index] == null) {
+                    ws[index] = q;         // else throw away
+                    installed = true;
+                }
+            } finally {
+                aux.unlock();
+            }
+            if (installed) {
+                try {
+                    q.growArray();
+                } finally {
+                    q.qlock = 0;
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds the given task to a submission queue at submitter's
+     * current queue. Also performs secondary initialization upon the
+     * first submission of the first task to the pool, and detects
+     * first submission by an external thread and creates a new shared
+     * queue if the one at index if empty or contended.
+     *
+     * @param task the task. Caller must ensure non-null.
+     */
+    final void externalPush(ForkJoinTask<?> task) {
+        int r;                            // initialize caller's probe
+        if ((r = ThreadLocalRandom.getProbe()) == 0) {
+            ThreadLocalRandom.localInit();
+            r = ThreadLocalRandom.getProbe();
+        }
+        for (;;) {
+            WorkQueue q; int wl, k, stat;
+            int rs = runState;
+            WorkQueue[] ws = workQueues;
+            if (rs <= 0 || ws == null || (wl = ws.length) <= 0)
+                tryInitialize(true);
+            else if ((q = ws[k = (wl - 1) & r & SQMASK]) == null)
+                tryCreateExternalQueue(k);
+            else if ((stat = q.sharedPush(task)) < 0)
+                break;
+            else if (stat == 0) {
+                signalWork();
+                break;
+            }
+            else                          // move if busy
+                r = ThreadLocalRandom.advanceProbe(r);
+        }
+    }
+
+    /**
+     * Pushes a possibly-external submission.
+     */
+    private <T> ForkJoinTask<T> externalSubmit(ForkJoinTask<T> task) {
+        Thread t; ForkJoinWorkerThread w; WorkQueue q;
+        if (task == null)
+            throw new NullPointerException();
+        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
+            (w = (ForkJoinWorkerThread)t).pool == this &&
+            (q = w.workQueue) != null)
+            q.push(task);
+        else
+            externalPush(task);
+        return task;
+    }
+
+    /**
+     * Returns common pool queue for an external thread.
+     */
+    static WorkQueue commonSubmitterQueue() {
+        ForkJoinPool p = common;
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; int wl;
+        return (p != null && (ws = p.workQueues) != null &&
+                (wl = ws.length) > 0) ?
+            ws[(wl - 1) & r & SQMASK] : null;
+    }
+
+    /**
+     * Performs tryUnpush for an external submitter.
+     */
+    final boolean tryExternalUnpush(ForkJoinTask<?> task) {
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; WorkQueue w; int wl;
+        return ((ws = workQueues) != null &&
+                (wl = ws.length) > 0 &&
+                (w = ws[(wl - 1) & r & SQMASK]) != null &&
+                w.trySharedUnpush(task));
+    }
+
+    /**
+     * Performs helpComplete for an external submitter.
+     */
+    final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
+        WorkQueue[] ws; int wl;
+        int r = ThreadLocalRandom.getProbe();
+        return ((ws = workQueues) != null && (wl = ws.length) > 0) ?
+            helpComplete(ws[(wl - 1) & r & SQMASK], task, maxTasks) : 0;
+    }
+
+    // Exported methods
+
+    // Constructors
+
+    /**
+     * Creates a {@code ForkJoinPool} with parallelism equal to {@link
+     * java.lang.Runtime#availableProcessors}, using the {@linkplain
+     * #defaultForkJoinWorkerThreadFactory default thread factory},
+     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+     *
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public ForkJoinPool() {
+        this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
+             defaultForkJoinWorkerThreadFactory, null, false);
+    }
+
+    /**
+     * Creates a {@code ForkJoinPool} with the indicated parallelism
+     * level, the {@linkplain
+     * #defaultForkJoinWorkerThreadFactory default thread factory},
+     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+     *
+     * @param parallelism the parallelism level
+     * @throws IllegalArgumentException if parallelism less than or
+     *         equal to zero, or greater than implementation limit
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public ForkJoinPool(int parallelism) {
+        this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
+    }
+
+    /**
+     * Creates a {@code ForkJoinPool} with the given parameters.
+     *
+     * @param parallelism the parallelism level. For default value,
+     * use {@link java.lang.Runtime#availableProcessors}.
+     * @param factory the factory for creating new threads. For default value,
+     * use {@link #defaultForkJoinWorkerThreadFactory}.
+     * @param handler the handler for internal worker threads that
+     * terminate due to unrecoverable errors encountered while executing
+     * tasks. For default value, use {@code null}.
+     * @param asyncMode if true,
+     * establishes local first-in-first-out scheduling mode for forked
+     * tasks that are never joined. This mode may be more appropriate
+     * than default locally stack-based mode in applications in which
+     * worker threads only process event-style asynchronous tasks.
+     * For default value, use {@code false}.
+     * @throws IllegalArgumentException if parallelism less than or
+     *         equal to zero, or greater than implementation limit
+     * @throws NullPointerException if the factory is null
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public ForkJoinPool(int parallelism,
+                        ForkJoinWorkerThreadFactory factory,
+                        UncaughtExceptionHandler handler,
+                        boolean asyncMode) {
+        this(checkParallelism(parallelism),
+             checkFactory(factory),
+             handler,
+             asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
+             "ForkJoinPool-" + nextPoolId() + "-worker-");
+        checkPermission();
+    }
+
+    private static int checkParallelism(int parallelism) {
+        if (parallelism <= 0 || parallelism > MAX_CAP)
+            throw new IllegalArgumentException();
+        return parallelism;
+    }
+
+    private static ForkJoinWorkerThreadFactory checkFactory
+        (ForkJoinWorkerThreadFactory factory) {
+        if (factory == null)
+            throw new NullPointerException();
+        return factory;
+    }
+
+    /**
+     * Creates a {@code ForkJoinPool} with the given parameters, without
+     * any security checks or parameter validation.  Invoked directly by
+     * makeCommonPool.
+     */
+    private ForkJoinPool(int parallelism,
+                         ForkJoinWorkerThreadFactory factory,
+                         UncaughtExceptionHandler handler,
+                         int mode,
+                         String workerNamePrefix) {
+        this.workerNamePrefix = workerNamePrefix;
+        this.factory = factory;
+        this.ueh = handler;
+        this.config = (parallelism & SMASK) | mode;
+        long np = (long)(-parallelism); // offset ctl counts
+        this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
+    }
+
+    /**
+     * Returns the common pool instance. This pool is statically
+     * constructed; its run state is unaffected by attempts to {@link
+     * #shutdown} or {@link #shutdownNow}. However this pool and any
+     * ongoing processing are automatically terminated upon program
+     * {@link System#exit}.  Any program that relies on asynchronous
+     * task processing to complete before program termination should
+     * invoke {@code commonPool().}{@link #awaitQuiescence awaitQuiescence},
+     * before exit.
+     *
+     * @return the common pool instance
+     * @since 1.8
+     */
+    public static ForkJoinPool commonPool() {
+        // assert common != null : "static init error";
+        return common;
+    }
+
+    // Execution methods
+
+    /**
+     * Performs the given task, returning its result upon completion.
+     * If the computation encounters an unchecked Exception or Error,
+     * it is rethrown as the outcome of this invocation.  Rethrown
+     * exceptions behave in the same way as regular exceptions, but,
+     * when possible, contain stack traces (as displayed for example
+     * using {@code ex.printStackTrace()}) of both the current thread
+     * as well as the thread actually encountering the exception;
+     * minimally only the latter.
+     *
+     * @param task the task
+     * @param <T> the type of the task's result
+     * @return the task's result
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> T invoke(ForkJoinTask<T> task) {
+        if (task == null)
+            throw new NullPointerException();
+        externalSubmit(task);
+        return task.join();
+    }
+
+    /**
+     * Arranges for (asynchronous) execution of the given task.
+     *
+     * @param task the task
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public void execute(ForkJoinTask<?> task) {
+        externalSubmit(task);
+    }
+
+    // AbstractExecutorService methods
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public void execute(Runnable task) {
+        if (task == null)
+            throw new NullPointerException();
+        ForkJoinTask<?> job;
+        if (task instanceof ForkJoinTask<?>) // avoid re-wrap
+            job = (ForkJoinTask<?>) task;
+        else
+            job = new ForkJoinTask.RunnableExecuteAction(task);
+        externalSubmit(job);
+    }
+
+    /**
+     * Submits a ForkJoinTask for execution.
+     *
+     * @param task the task to submit
+     * @param <T> the type of the task's result
+     * @return the task
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
+        return externalSubmit(task);
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> ForkJoinTask<T> submit(Callable<T> task) {
+        return externalSubmit(new ForkJoinTask.AdaptedCallable<T>(task));
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> ForkJoinTask<T> submit(Runnable task, T result) {
+        return externalSubmit(new ForkJoinTask.AdaptedRunnable<T>(task, result));
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public ForkJoinTask<?> submit(Runnable task) {
+        if (task == null)
+            throw new NullPointerException();
+        ForkJoinTask<?> job;
+        if (task instanceof ForkJoinTask<?>) // avoid re-wrap
+            job = (ForkJoinTask<?>) task;
+        else
+            job = new ForkJoinTask.AdaptedRunnableAction(task);
+        return externalSubmit(job);
+    }
+
+    /**
+     * @throws NullPointerException       {@inheritDoc}
+     * @throws RejectedExecutionException {@inheritDoc}
+     */
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
+        // In previous versions of this class, this method constructed
+        // a task to run ForkJoinTask.invokeAll, but now external
+        // invocation of multiple tasks is at least as efficient.
+        ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+
+        try {
+            for (Callable<T> t : tasks) {
+                ForkJoinTask<T> f = new ForkJoinTask.AdaptedCallable<T>(t);
+                futures.add(f);
+                externalSubmit(f);
+            }
+            for (int i = 0, size = futures.size(); i < size; i++)
+                ((ForkJoinTask<?>)futures.get(i)).quietlyJoin();
+            return futures;
+        } catch (Throwable t) {
+            for (int i = 0, size = futures.size(); i < size; i++)
+                futures.get(i).cancel(false);
+            throw t;
+        }
+    }
+
+    /**
+     * Returns the factory used for constructing new workers.
+     *
+     * @return the factory used for constructing new workers
+     */
+    public ForkJoinWorkerThreadFactory getFactory() {
+        return factory;
+    }
+
+    /**
+     * Returns the handler for internal worker threads that terminate
+     * due to unrecoverable errors encountered while executing tasks.
+     *
+     * @return the handler, or {@code null} if none
+     */
+    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
+        return ueh;
+    }
+
+    /**
+     * Returns the targeted parallelism level of this pool.
+     *
+     * @return the targeted parallelism level of this pool
+     */
+    public int getParallelism() {
+        int par;
+        return ((par = config & SMASK) > 0) ? par : 1;
+    }
+
+    /**
+     * Returns the targeted parallelism level of the common pool.
+     *
+     * @return the targeted parallelism level of the common pool
+     * @since 1.8
+     */
+    public static int getCommonPoolParallelism() {
+        return COMMON_PARALLELISM;
+    }
+
+    /**
+     * Returns the number of worker threads that have started but not
+     * yet terminated.  The result returned by this method may differ
+     * from {@link #getParallelism} when threads are created to
+     * maintain parallelism when others are cooperatively blocked.
+     *
+     * @return the number of worker threads
+     */
+    public int getPoolSize() {
+        return (config & SMASK) + (short)(ctl >>> TC_SHIFT);
+    }
+
+    /**
+     * Returns {@code true} if this pool uses local first-in-first-out
+     * scheduling mode for forked tasks that are never joined.
+     *
+     * @return {@code true} if this pool uses async mode
+     */
+    public boolean getAsyncMode() {
+        return (config & FIFO_QUEUE) != 0;
+    }
+
+    /**
+     * Returns an estimate of the number of worker threads that are
+     * not blocked waiting to join tasks or for other managed
+     * synchronization. This method may overestimate the
+     * number of running threads.
+     *
+     * @return the number of worker threads
+     */
+    public int getRunningThreadCount() {
+        int rc = 0;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 1; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null && w.isApparentlyUnblocked())
+                    ++rc;
+            }
+        }
+        return rc;
+    }
+
+    /**
+     * Returns an estimate of the number of threads that are currently
+     * stealing or executing tasks. This method may overestimate the
+     * number of active threads.
+     *
+     * @return the number of active threads
+     */
+    public int getActiveThreadCount() {
+        int r = (config & SMASK) + (int)(ctl >> AC_SHIFT);
+        return (r <= 0) ? 0 : r; // suppress momentarily negative values
+    }
+
+    /**
+     * Returns {@code true} if all worker threads are currently idle.
+     * An idle worker is one that cannot obtain a task to execute
+     * because none are available to steal from other threads, and
+     * there are no pending submissions to the pool. This method is
+     * conservative; it might not return {@code true} immediately upon
+     * idleness of all threads, but will eventually become true if
+     * threads remain inactive.
+     *
+     * @return {@code true} if all threads are currently idle
+     */
+    public boolean isQuiescent() {
+        return (config & SMASK) + (int)(ctl >> AC_SHIFT) <= 0;
+    }
+
+    /**
+     * Returns an estimate of the total number of tasks stolen from
+     * one thread's work queue by another. The reported value
+     * underestimates the actual total number of steals when the pool
+     * is not quiescent. This value may be useful for monitoring and
+     * tuning fork/join programs: in general, steal counts should be
+     * high enough to keep threads busy, but low enough to avoid
+     * overhead and contention across threads.
+     *
+     * @return the number of steals
+     */
+    public long getStealCount() {
+        AuxState sc = auxState;
+        long count = (sc == null) ? 0L : sc.stealCount;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 1; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null)
+                    count += w.nsteals;
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Returns an estimate of the total number of tasks currently held
+     * in queues by worker threads (but not including tasks submitted
+     * to the pool that have not begun executing). This value is only
+     * an approximation, obtained by iterating across all threads in
+     * the pool. This method may be useful for tuning task
+     * granularities.
+     *
+     * @return the number of queued tasks
+     */
+    public long getQueuedTaskCount() {
+        long count = 0;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 1; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null)
+                    count += w.queueSize();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Returns an estimate of the number of tasks submitted to this
+     * pool that have not yet begun executing.  This method may take
+     * time proportional to the number of submissions.
+     *
+     * @return the number of queued submissions
+     */
+    public int getQueuedSubmissionCount() {
+        int count = 0;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null)
+                    count += w.queueSize();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Returns {@code true} if there are any tasks submitted to this
+     * pool that have not yet begun executing.
+     *
+     * @return {@code true} if there are any queued submissions
+     */
+    public boolean hasQueuedSubmissions() {
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null && !w.isEmpty())
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes and returns the next unexecuted submission if one is
+     * available.  This method may be useful in extensions to this
+     * class that re-assign work in systems with multiple pools.
+     *
+     * @return the next submission, or {@code null} if none
+     */
+    protected ForkJoinTask<?> pollSubmission() {
+        WorkQueue[] ws; int wl; WorkQueue w; ForkJoinTask<?> t;
+        int r = ThreadLocalRandom.nextSecondarySeed();
+        if ((ws = workQueues) != null && (wl = ws.length) > 0) {
+            for (int m = wl - 1, i = 0; i < wl; ++i) {
+                if ((w = ws[(i << 1) & m]) != null && (t = w.poll()) != null)
+                    return t;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Removes all available unexecuted submitted and forked tasks
+     * from scheduling queues and adds them to the given collection,
+     * without altering their execution status. These may include
+     * artificially generated or wrapped tasks. This method is
+     * designed to be invoked only when the pool is known to be
+     * quiescent. Invocations at other times may not remove all
+     * tasks. A failure encountered while attempting to add elements
+     * to collection {@code c} may result in elements being in
+     * neither, either or both collections when the associated
+     * exception is thrown.  The behavior of this operation is
+     * undefined if the specified collection is modified while the
+     * operation is in progress.
+     *
+     * @param c the collection to transfer elements into
+     * @return the number of elements transferred
+     */
+    protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
+        int count = 0;
+        WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; ++i) {
+                if ((w = ws[i]) != null) {
+                    while ((t = w.poll()) != null) {
+                        c.add(t);
+                        ++count;
+                    }
+                }
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Returns a string identifying this pool, as well as its state,
+     * including indications of run state, parallelism level, and
+     * worker and task counts.
+     *
+     * @return a string identifying this pool, as well as its state
+     */
+    public String toString() {
+        // Use a single pass through workQueues to collect counts
+        long qt = 0L, qs = 0L; int rc = 0;
+        AuxState sc = auxState;
+        long st = (sc == null) ? 0L : sc.stealCount;
+        long c = ctl;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; ++i) {
+                if ((w = ws[i]) != null) {
+                    int size = w.queueSize();
+                    if ((i & 1) == 0)
+                        qs += size;
+                    else {
+                        qt += size;
+                        st += w.nsteals;
+                        if (w.isApparentlyUnblocked())
+                            ++rc;
+                    }
+                }
+            }
+        }
+        int pc = (config & SMASK);
+        int tc = pc + (short)(c >>> TC_SHIFT);
+        int ac = pc + (int)(c >> AC_SHIFT);
+        if (ac < 0) // ignore transient negative
+            ac = 0;
+        int rs = runState;
+        String level = ((rs & TERMINATED) != 0 ? "Terminated" :
+                        (rs & STOP)       != 0 ? "Terminating" :
+                        (rs & SHUTDOWN)   != 0 ? "Shutting down" :
+                        "Running");
+        return super.toString() +
+            "[" + level +
+            ", parallelism = " + pc +
+            ", size = " + tc +
+            ", active = " + ac +
+            ", running = " + rc +
+            ", steals = " + st +
+            ", tasks = " + qt +
+            ", submissions = " + qs +
+            "]";
+    }
+
+    /**
+     * Possibly initiates an orderly shutdown in which previously
+     * submitted tasks are executed, but no new tasks will be
+     * accepted. Invocation has no effect on execution state if this
+     * is the {@link #commonPool()}, and no additional effect if
+     * already shut down.  Tasks that are in the process of being
+     * submitted concurrently during the course of this method may or
+     * may not be rejected.
+     *
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public void shutdown() {
+        checkPermission();
+        tryTerminate(false, true);
+    }
+
+    /**
+     * Possibly attempts to cancel and/or stop all tasks, and reject
+     * all subsequently submitted tasks.  Invocation has no effect on
+     * execution state if this is the {@link #commonPool()}, and no
+     * additional effect if already shut down. Otherwise, tasks that
+     * are in the process of being submitted or executed concurrently
+     * during the course of this method may or may not be
+     * rejected. This method cancels both existing and unexecuted
+     * tasks, in order to permit termination in the presence of task
+     * dependencies. So the method always returns an empty list
+     * (unlike the case for some other Executors).
+     *
+     * @return an empty list
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public List<Runnable> shutdownNow() {
+        checkPermission();
+        tryTerminate(true, true);
+        return Collections.emptyList();
+    }
+
+    /**
+     * Returns {@code true} if all tasks have completed following shut down.
+     *
+     * @return {@code true} if all tasks have completed following shut down
+     */
+    public boolean isTerminated() {
+        return (runState & TERMINATED) != 0;
+    }
+
+    /**
+     * Returns {@code true} if the process of termination has
+     * commenced but not yet completed.  This method may be useful for
+     * debugging. A return of {@code true} reported a sufficient
+     * period after shutdown may indicate that submitted tasks have
+     * ignored or suppressed interruption, or are waiting for I/O,
+     * causing this executor not to properly terminate. (See the
+     * advisory notes for class {@link ForkJoinTask} stating that
+     * tasks should not normally entail blocking operations.  But if
+     * they do, they must abort them on interrupt.)
+     *
+     * @return {@code true} if terminating but not yet terminated
+     */
+    public boolean isTerminating() {
+        int rs = runState;
+        return (rs & STOP) != 0 && (rs & TERMINATED) == 0;
+    }
+
+    /**
+     * Returns {@code true} if this pool has been shut down.
+     *
+     * @return {@code true} if this pool has been shut down
+     */
+    public boolean isShutdown() {
+        return (runState & SHUTDOWN) != 0;
+    }
+
+    /**
+     * Blocks until all tasks have completed execution after a
+     * shutdown request, or the timeout occurs, or the current thread
+     * is interrupted, whichever happens first. Because the {@link
+     * #commonPool()} never terminates until program shutdown, when
+     * applied to the common pool, this method is equivalent to {@link
+     * #awaitQuiescence(long, TimeUnit)} but always returns {@code false}.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return {@code true} if this executor terminated and
+     *         {@code false} if the timeout elapsed before termination
+     * @throws InterruptedException if interrupted while waiting
+     */
+    public boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (this == common) {
+            awaitQuiescence(timeout, unit);
+            return false;
+        }
+        long nanos = unit.toNanos(timeout);
+        if (isTerminated())
+            return true;
+        if (nanos <= 0L)
+            return false;
+        long deadline = System.nanoTime() + nanos;
+        synchronized (this) {
+            for (;;) {
+                if (isTerminated())
+                    return true;
+                if (nanos <= 0L)
+                    return false;
+                long millis = TimeUnit.NANOSECONDS.toMillis(nanos);
+                wait(millis > 0L ? millis : 1L);
+                nanos = deadline - System.nanoTime();
+            }
+        }
+    }
+
+    /**
+     * If called by a ForkJoinTask operating in this pool, equivalent
+     * in effect to {@link ForkJoinTask#helpQuiesce}. Otherwise,
+     * waits and/or attempts to assist performing tasks until this
+     * pool {@link #isQuiescent} or the indicated timeout elapses.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return {@code true} if quiescent; {@code false} if the
+     * timeout elapsed.
+     */
+    public boolean awaitQuiescence(long timeout, TimeUnit unit) {
+        long nanos = unit.toNanos(timeout);
+        ForkJoinWorkerThread wt;
+        Thread thread = Thread.currentThread();
+        if ((thread instanceof ForkJoinWorkerThread) &&
+            (wt = (ForkJoinWorkerThread)thread).pool == this) {
+            helpQuiescePool(wt.workQueue);
+            return true;
+        }
+        long startTime = System.nanoTime();
+        WorkQueue[] ws;
+        int r = 0, wl;
+        boolean found = true;
+        while (!isQuiescent() && (ws = workQueues) != null &&
+               (wl = ws.length) > 0) {
+            if (!found) {
+                if ((System.nanoTime() - startTime) > nanos)
+                    return false;
+                Thread.yield(); // cannot block
+            }
+            found = false;
+            for (int m = wl - 1, j = (m + 1) << 2; j >= 0; --j) {
+                ForkJoinTask<?> t; WorkQueue q; int b, k;
+                if ((k = r++ & m) <= m && k >= 0 && (q = ws[k]) != null &&
+                    (b = q.base) - q.top < 0) {
+                    found = true;
+                    if ((t = q.pollAt(b)) != null)
+                        t.doExec();
+                    break;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Waits and/or attempts to assist performing tasks indefinitely
+     * until the {@link #commonPool()} {@link #isQuiescent}.
+     */
+    static void quiesceCommonPool() {
+        common.awaitQuiescence(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+    }
+
+    /**
+     * Interface for extending managed parallelism for tasks running
+     * in {@link ForkJoinPool}s.
+     *
+     * <p>A {@code ManagedBlocker} provides two methods.  Method
+     * {@link #isReleasable} must return {@code true} if blocking is
+     * not necessary. Method {@link #block} blocks the current thread
+     * if necessary (perhaps internally invoking {@code isReleasable}
+     * before actually blocking). These actions are performed by any
+     * thread invoking {@link ForkJoinPool#managedBlock(ManagedBlocker)}.
+     * The unusual methods in this API accommodate synchronizers that
+     * may, but don't usually, block for long periods. Similarly, they
+     * allow more efficient internal handling of cases in which
+     * additional workers may be, but usually are not, needed to
+     * ensure sufficient parallelism.  Toward this end,
+     * implementations of method {@code isReleasable} must be amenable
+     * to repeated invocation.
+     *
+     * <p>For example, here is a ManagedBlocker based on a
+     * ReentrantLock:
+     * <pre> {@code
+     * class ManagedLocker implements ManagedBlocker {
+     *   final ReentrantLock lock;
+     *   boolean hasLock = false;
+     *   ManagedLocker(ReentrantLock lock) { this.lock = lock; }
+     *   public boolean block() {
+     *     if (!hasLock)
+     *       lock.lock();
+     *     return true;
+     *   }
+     *   public boolean isReleasable() {
+     *     return hasLock || (hasLock = lock.tryLock());
+     *   }
+     * }}</pre>
+     *
+     * <p>Here is a class that possibly blocks waiting for an
+     * item on a given queue:
+     * <pre> {@code
+     * class QueueTaker<E> implements ManagedBlocker {
+     *   final BlockingQueue<E> queue;
+     *   volatile E item = null;
+     *   QueueTaker(BlockingQueue<E> q) { this.queue = q; }
+     *   public boolean block() throws InterruptedException {
+     *     if (item == null)
+     *       item = queue.take();
+     *     return true;
+     *   }
+     *   public boolean isReleasable() {
+     *     return item != null || (item = queue.poll()) != null;
+     *   }
+     *   public E getItem() { // call after pool.managedBlock completes
+     *     return item;
+     *   }
+     * }}</pre>
+     */
+    public static interface ManagedBlocker {
+        /**
+         * Possibly blocks the current thread, for example waiting for
+         * a lock or condition.
+         *
+         * @return {@code true} if no additional blocking is necessary
+         * (i.e., if isReleasable would return true)
+         * @throws InterruptedException if interrupted while waiting
+         * (the method is not required to do so, but is allowed to)
+         */
+        boolean block() throws InterruptedException;
+
+        /**
+         * Returns {@code true} if blocking is unnecessary.
+         * @return {@code true} if blocking is unnecessary
+         */
+        boolean isReleasable();
+    }
+
+    /**
+     * Runs the given possibly blocking task.  When {@linkplain
+     * ForkJoinTask#inForkJoinPool() running in a ForkJoinPool}, this
+     * method possibly arranges for a spare thread to be activated if
+     * necessary to ensure sufficient parallelism while the current
+     * thread is blocked in {@link ManagedBlocker#block blocker.block()}.
+     *
+     * <p>This method repeatedly calls {@code blocker.isReleasable()} and
+     * {@code blocker.block()} until either method returns {@code true}.
+     * Every call to {@code blocker.block()} is preceded by a call to
+     * {@code blocker.isReleasable()} that returned {@code false}.
+     *
+     * <p>If not running in a ForkJoinPool, this method is
+     * behaviorally equivalent to
+     * <pre> {@code
+     * while (!blocker.isReleasable())
+     *   if (blocker.block())
+     *     break;}</pre>
+     *
+     * If running in a ForkJoinPool, the pool may first be expanded to
+     * ensure sufficient parallelism available during the call to
+     * {@code blocker.block()}.
+     *
+     * @param blocker the blocker task
+     * @throws InterruptedException if {@code blocker.block()} did so
+     */
+    public static void managedBlock(ManagedBlocker blocker)
+        throws InterruptedException {
+        ForkJoinPool p;
+        ForkJoinWorkerThread wt;
+        Thread t = Thread.currentThread();
+        if ((t instanceof ForkJoinWorkerThread) &&
+            (p = (wt = (ForkJoinWorkerThread)t).pool) != null) {
+            WorkQueue w = wt.workQueue;
+            while (!blocker.isReleasable()) {
+                if (p.tryCompensate(w)) {
+                    try {
+                        do {} while (!blocker.isReleasable() &&
+                                     !blocker.block());
+                    } finally {
+                        U.getAndAddLong(p, CTL, AC_UNIT);
+                    }
+                    break;
+                }
+            }
+        }
+        else {
+            do {} while (!blocker.isReleasable() &&
+                         !blocker.block());
+        }
+    }
+
+    // AbstractExecutorService overrides.  These rely on undocumented
+    // fact that ForkJoinTask.adapt returns ForkJoinTasks that also
+    // implement RunnableFuture.
+
+    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
+        return new ForkJoinTask.AdaptedRunnable<T>(runnable, value);
+    }
+
+    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
+        return new ForkJoinTask.AdaptedCallable<T>(callable);
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long CTL;
+    private static final long RUNSTATE;
+    private static final int ABASE;
+    private static final int ASHIFT;
+
+    static {
+        try {
+            CTL = U.objectFieldOffset
+                (ForkJoinPool.class.getDeclaredField("ctl"));
+            RUNSTATE = U.objectFieldOffset
+                (ForkJoinPool.class.getDeclaredField("runState"));
+            ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
+            int scale = U.arrayIndexScale(ForkJoinTask[].class);
+            if ((scale & (scale - 1)) != 0)
+                throw new Error("array index scale not a power of two");
+            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+
+        int commonMaxSpares = DEFAULT_COMMON_MAX_SPARES;
+        try {
+            String p = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.maximumSpares");
+            if (p != null)
+                commonMaxSpares = Integer.parseInt(p);
+        } catch (Exception ignore) {}
+        COMMON_MAX_SPARES = commonMaxSpares;
+
+        defaultForkJoinWorkerThreadFactory =
+            new DefaultForkJoinWorkerThreadFactory();
+        modifyThreadPermission = new RuntimePermission("modifyThread");
+
+        common = java.security.AccessController.doPrivileged
+            (new java.security.PrivilegedAction<ForkJoinPool>() {
+                public ForkJoinPool run() { return makeCommonPool(); }});
+
+        // report 1 even if threads disabled
+        COMMON_PARALLELISM = Math.max(common.config & SMASK, 1);
+    }
+
+    /**
+     * Creates and returns the common pool, respecting user settings
+     * specified via system properties.
+     */
+    static ForkJoinPool makeCommonPool() {
+        int parallelism = -1;
+        ForkJoinWorkerThreadFactory factory = null;
+        UncaughtExceptionHandler handler = null;
+        try {  // ignore exceptions in accessing/parsing properties
+            String pp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.parallelism");
+            String fp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.threadFactory");
+            String hp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
+            if (pp != null)
+                parallelism = Integer.parseInt(pp);
+            if (fp != null)
+                factory = ((ForkJoinWorkerThreadFactory)ClassLoader.
+                           getSystemClassLoader().loadClass(fp).newInstance());
+            if (hp != null)
+                handler = ((UncaughtExceptionHandler)ClassLoader.
+                           getSystemClassLoader().loadClass(hp).newInstance());
+        } catch (Exception ignore) {
+        }
+        if (factory == null) {
+            if (System.getSecurityManager() == null)
+                factory = defaultForkJoinWorkerThreadFactory;
+            else // use security-managed default
+                factory = new InnocuousForkJoinWorkerThreadFactory();
+        }
+        if (parallelism < 0 && // default 1 less than #cores
+            (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
+            parallelism = 1;
+        if (parallelism > MAX_CAP)
+            parallelism = MAX_CAP;
+        return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
+                                "ForkJoinPool.commonPool-worker-");
+    }
+
+    /**
+     * Factory for innocuous worker threads.
+     */
+    private static final class InnocuousForkJoinWorkerThreadFactory
+        implements ForkJoinWorkerThreadFactory {
+
+        /**
+         * An ACC to restrict permissions for the factory itself.
+         * The constructed workers have no permissions set.
+         */
+        private static final AccessControlContext innocuousAcc;
+        static {
+            Permissions innocuousPerms = new Permissions();
+            innocuousPerms.add(modifyThreadPermission);
+            innocuousPerms.add(new RuntimePermission(
+                                   "enableContextClassLoaderOverride"));
+            innocuousPerms.add(new RuntimePermission(
+                                   "modifyThreadGroup"));
+            innocuousAcc = new AccessControlContext(new ProtectionDomain[] {
+                    new ProtectionDomain(null, innocuousPerms)
+                });
+        }
+
+        public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
+            return java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<ForkJoinWorkerThread>() {
+                    public ForkJoinWorkerThread run() {
+                        return new ForkJoinWorkerThread.
+                            InnocuousForkJoinWorkerThread(pool);
+                    }}, innocuousAcc);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/ForkJoinTask.java b/java/util/concurrent/ForkJoinTask.java
new file mode 100644
index 0000000..efccfa5
--- /dev/null
+++ b/java/util/concurrent/ForkJoinTask.java
@@ -0,0 +1,1534 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.io.Serializable;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// removed java 9 code
+// END android-note
+
+/**
+ * Abstract base class for tasks that run within a {@link ForkJoinPool}.
+ * A {@code ForkJoinTask} is a thread-like entity that is much
+ * lighter weight than a normal thread.  Huge numbers of tasks and
+ * subtasks may be hosted by a small number of actual threads in a
+ * ForkJoinPool, at the price of some usage limitations.
+ *
+ * <p>A "main" {@code ForkJoinTask} begins execution when it is
+ * explicitly submitted to a {@link ForkJoinPool}, or, if not already
+ * engaged in a ForkJoin computation, commenced in the {@link
+ * ForkJoinPool#commonPool()} via {@link #fork}, {@link #invoke}, or
+ * related methods.  Once started, it will usually in turn start other
+ * subtasks.  As indicated by the name of this class, many programs
+ * using {@code ForkJoinTask} employ only methods {@link #fork} and
+ * {@link #join}, or derivatives such as {@link
+ * #invokeAll(ForkJoinTask...) invokeAll}.  However, this class also
+ * provides a number of other methods that can come into play in
+ * advanced usages, as well as extension mechanics that allow support
+ * of new forms of fork/join processing.
+ *
+ * <p>A {@code ForkJoinTask} is a lightweight form of {@link Future}.
+ * The efficiency of {@code ForkJoinTask}s stems from a set of
+ * restrictions (that are only partially statically enforceable)
+ * reflecting their main use as computational tasks calculating pure
+ * functions or operating on purely isolated objects.  The primary
+ * coordination mechanisms are {@link #fork}, that arranges
+ * asynchronous execution, and {@link #join}, that doesn't proceed
+ * until the task's result has been computed.  Computations should
+ * ideally avoid {@code synchronized} methods or blocks, and should
+ * minimize other blocking synchronization apart from joining other
+ * tasks or using synchronizers such as Phasers that are advertised to
+ * cooperate with fork/join scheduling. Subdividable tasks should also
+ * not perform blocking I/O, and should ideally access variables that
+ * are completely independent of those accessed by other running
+ * tasks. These guidelines are loosely enforced by not permitting
+ * checked exceptions such as {@code IOExceptions} to be
+ * thrown. However, computations may still encounter unchecked
+ * exceptions, that are rethrown to callers attempting to join
+ * them. These exceptions may additionally include {@link
+ * RejectedExecutionException} stemming from internal resource
+ * exhaustion, such as failure to allocate internal task
+ * queues. Rethrown exceptions behave in the same way as regular
+ * exceptions, but, when possible, contain stack traces (as displayed
+ * for example using {@code ex.printStackTrace()}) of both the thread
+ * that initiated the computation as well as the thread actually
+ * encountering the exception; minimally only the latter.
+ *
+ * <p>It is possible to define and use ForkJoinTasks that may block,
+ * but doing do requires three further considerations: (1) Completion
+ * of few if any <em>other</em> tasks should be dependent on a task
+ * that blocks on external synchronization or I/O. Event-style async
+ * tasks that are never joined (for example, those subclassing {@link
+ * CountedCompleter}) often fall into this category.  (2) To minimize
+ * resource impact, tasks should be small; ideally performing only the
+ * (possibly) blocking action. (3) Unless the {@link
+ * ForkJoinPool.ManagedBlocker} API is used, or the number of possibly
+ * blocked tasks is known to be less than the pool's {@link
+ * ForkJoinPool#getParallelism} level, the pool cannot guarantee that
+ * enough threads will be available to ensure progress or good
+ * performance.
+ *
+ * <p>The primary method for awaiting completion and extracting
+ * results of a task is {@link #join}, but there are several variants:
+ * The {@link Future#get} methods support interruptible and/or timed
+ * waits for completion and report results using {@code Future}
+ * conventions. Method {@link #invoke} is semantically
+ * equivalent to {@code fork(); join()} but always attempts to begin
+ * execution in the current thread. The "<em>quiet</em>" forms of
+ * these methods do not extract results or report exceptions. These
+ * may be useful when a set of tasks are being executed, and you need
+ * to delay processing of results or exceptions until all complete.
+ * Method {@code invokeAll} (available in multiple versions)
+ * performs the most common form of parallel invocation: forking a set
+ * of tasks and joining them all.
+ *
+ * <p>In the most typical usages, a fork-join pair act like a call
+ * (fork) and return (join) from a parallel recursive function. As is
+ * the case with other forms of recursive calls, returns (joins)
+ * should be performed innermost-first. For example, {@code a.fork();
+ * b.fork(); b.join(); a.join();} is likely to be substantially more
+ * efficient than joining {@code a} before {@code b}.
+ *
+ * <p>The execution status of tasks may be queried at several levels
+ * of detail: {@link #isDone} is true if a task completed in any way
+ * (including the case where a task was cancelled without executing);
+ * {@link #isCompletedNormally} is true if a task completed without
+ * cancellation or encountering an exception; {@link #isCancelled} is
+ * true if the task was cancelled (in which case {@link #getException}
+ * returns a {@link java.util.concurrent.CancellationException}); and
+ * {@link #isCompletedAbnormally} is true if a task was either
+ * cancelled or encountered an exception, in which case {@link
+ * #getException} will return either the encountered exception or
+ * {@link java.util.concurrent.CancellationException}.
+ *
+ * <p>The ForkJoinTask class is not usually directly subclassed.
+ * Instead, you subclass one of the abstract classes that support a
+ * particular style of fork/join processing, typically {@link
+ * RecursiveAction} for most computations that do not return results,
+ * {@link RecursiveTask} for those that do, and {@link
+ * CountedCompleter} for those in which completed actions trigger
+ * other actions.  Normally, a concrete ForkJoinTask subclass declares
+ * fields comprising its parameters, established in a constructor, and
+ * then defines a {@code compute} method that somehow uses the control
+ * methods supplied by this base class.
+ *
+ * <p>Method {@link #join} and its variants are appropriate for use
+ * only when completion dependencies are acyclic; that is, the
+ * parallel computation can be described as a directed acyclic graph
+ * (DAG). Otherwise, executions may encounter a form of deadlock as
+ * tasks cyclically wait for each other.  However, this framework
+ * supports other methods and techniques (for example the use of
+ * {@link Phaser}, {@link #helpQuiesce}, and {@link #complete}) that
+ * may be of use in constructing custom subclasses for problems that
+ * are not statically structured as DAGs. To support such usages, a
+ * ForkJoinTask may be atomically <em>tagged</em> with a {@code short}
+ * value using {@link #setForkJoinTaskTag} or {@link
+ * #compareAndSetForkJoinTaskTag} and checked using {@link
+ * #getForkJoinTaskTag}. The ForkJoinTask implementation does not use
+ * these {@code protected} methods or tags for any purpose, but they
+ * may be of use in the construction of specialized subclasses.  For
+ * example, parallel graph traversals can use the supplied methods to
+ * avoid revisiting nodes/tasks that have already been processed.
+ * (Method names for tagging are bulky in part to encourage definition
+ * of methods that reflect their usage patterns.)
+ *
+ * <p>Most base support methods are {@code final}, to prevent
+ * overriding of implementations that are intrinsically tied to the
+ * underlying lightweight task scheduling framework.  Developers
+ * creating new basic styles of fork/join processing should minimally
+ * implement {@code protected} methods {@link #exec}, {@link
+ * #setRawResult}, and {@link #getRawResult}, while also introducing
+ * an abstract computational method that can be implemented in its
+ * subclasses, possibly relying on other {@code protected} methods
+ * provided by this class.
+ *
+ * <p>ForkJoinTasks should perform relatively small amounts of
+ * computation. Large tasks should be split into smaller subtasks,
+ * usually via recursive decomposition. As a very rough rule of thumb,
+ * a task should perform more than 100 and less than 10000 basic
+ * computational steps, and should avoid indefinite looping. If tasks
+ * are too big, then parallelism cannot improve throughput. If too
+ * small, then memory and internal task maintenance overhead may
+ * overwhelm processing.
+ *
+ * <p>This class provides {@code adapt} methods for {@link Runnable}
+ * and {@link Callable}, that may be of use when mixing execution of
+ * {@code ForkJoinTasks} with other kinds of tasks. When all tasks are
+ * of this form, consider using a pool constructed in <em>asyncMode</em>.
+ *
+ * <p>ForkJoinTasks are {@code Serializable}, which enables them to be
+ * used in extensions such as remote execution frameworks. It is
+ * sensible to serialize tasks only before or after, but not during,
+ * execution. Serialization is not relied on during execution itself.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
+
+    /*
+     * See the internal documentation of class ForkJoinPool for a
+     * general implementation overview.  ForkJoinTasks are mainly
+     * responsible for maintaining their "status" field amidst relays
+     * to methods in ForkJoinWorkerThread and ForkJoinPool.
+     *
+     * The methods of this class are more-or-less layered into
+     * (1) basic status maintenance
+     * (2) execution and awaiting completion
+     * (3) user-level methods that additionally report results.
+     * This is sometimes hard to see because this file orders exported
+     * methods in a way that flows well in javadocs.
+     */
+
+    /*
+     * The status field holds run control status bits packed into a
+     * single int to minimize footprint and to ensure atomicity (via
+     * CAS).  Status is initially zero, and takes on nonnegative
+     * values until completed, upon which status (anded with
+     * DONE_MASK) holds value NORMAL, CANCELLED, or EXCEPTIONAL. Tasks
+     * undergoing blocking waits by other threads have the SIGNAL bit
+     * set.  Completion of a stolen task with SIGNAL set awakens any
+     * waiters via notifyAll. Even though suboptimal for some
+     * purposes, we use basic builtin wait/notify to take advantage of
+     * "monitor inflation" in JVMs that we would otherwise need to
+     * emulate to avoid adding further per-task bookkeeping overhead.
+     * We want these monitors to be "fat", i.e., not use biasing or
+     * thin-lock techniques, so use some odd coding idioms that tend
+     * to avoid them, mainly by arranging that every synchronized
+     * block performs a wait, notifyAll or both.
+     *
+     * These control bits occupy only (some of) the upper half (16
+     * bits) of status field. The lower bits are used for user-defined
+     * tags.
+     */
+
+    /** The run status of this task */
+    volatile int status; // accessed directly by pool and workers
+    static final int DONE_MASK   = 0xf0000000;  // mask out non-completion bits
+    static final int NORMAL      = 0xf0000000;  // must be negative
+    static final int CANCELLED   = 0xc0000000;  // must be < NORMAL
+    static final int EXCEPTIONAL = 0x80000000;  // must be < CANCELLED
+    static final int SIGNAL      = 0x00010000;  // must be >= 1 << 16
+    static final int SMASK       = 0x0000ffff;  // short bits for tags
+
+    /**
+     * Marks completion and wakes up threads waiting to join this
+     * task.
+     *
+     * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL
+     * @return completion status on exit
+     */
+    private int setCompletion(int completion) {
+        for (int s;;) {
+            if ((s = status) < 0)
+                return s;
+            if (U.compareAndSwapInt(this, STATUS, s, s | completion)) {
+                if ((s >>> 16) != 0)
+                    synchronized (this) { notifyAll(); }
+                return completion;
+            }
+        }
+    }
+
+    /**
+     * Primary execution method for stolen tasks. Unless done, calls
+     * exec and records status if completed, but doesn't wait for
+     * completion otherwise.
+     *
+     * @return status on exit from this method
+     */
+    final int doExec() {
+        int s; boolean completed;
+        if ((s = status) >= 0) {
+            try {
+                completed = exec();
+            } catch (Throwable rex) {
+                return setExceptionalCompletion(rex);
+            }
+            if (completed)
+                s = setCompletion(NORMAL);
+        }
+        return s;
+    }
+
+    /**
+     * If not done, sets SIGNAL status and performs Object.wait(timeout).
+     * This task may or may not be done on exit. Ignores interrupts.
+     *
+     * @param timeout using Object.wait conventions.
+     */
+    final void internalWait(long timeout) {
+        int s;
+        if ((s = status) >= 0 && // force completer to issue notify
+            U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+            synchronized (this) {
+                if (status >= 0)
+                    try { wait(timeout); } catch (InterruptedException ie) { }
+                else
+                    notifyAll();
+            }
+        }
+    }
+
+    /**
+     * Blocks a non-worker-thread until completion.
+     * @return status upon completion
+     */
+    private int externalAwaitDone() {
+        int s = ((this instanceof CountedCompleter) ? // try helping
+                 ForkJoinPool.common.externalHelpComplete(
+                     (CountedCompleter<?>)this, 0) :
+                 ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0);
+        if (s >= 0 && (s = status) >= 0) {
+            boolean interrupted = false;
+            do {
+                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                    synchronized (this) {
+                        if (status >= 0) {
+                            try {
+                                wait(0L);
+                            } catch (InterruptedException ie) {
+                                interrupted = true;
+                            }
+                        }
+                        else
+                            notifyAll();
+                    }
+                }
+            } while ((s = status) >= 0);
+            if (interrupted)
+                Thread.currentThread().interrupt();
+        }
+        return s;
+    }
+
+    /**
+     * Blocks a non-worker-thread until completion or interruption.
+     */
+    private int externalInterruptibleAwaitDone() throws InterruptedException {
+        int s;
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if ((s = status) >= 0 &&
+            (s = ((this instanceof CountedCompleter) ?
+                  ForkJoinPool.common.externalHelpComplete(
+                      (CountedCompleter<?>)this, 0) :
+                  ForkJoinPool.common.tryExternalUnpush(this) ? doExec() :
+                  0)) >= 0) {
+            while ((s = status) >= 0) {
+                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                    synchronized (this) {
+                        if (status >= 0)
+                            wait(0L);
+                        else
+                            notifyAll();
+                    }
+                }
+            }
+        }
+        return s;
+    }
+
+    /**
+     * Implementation for join, get, quietlyJoin. Directly handles
+     * only cases of already-completed, external wait, and
+     * unfork+exec.  Others are relayed to ForkJoinPool.awaitJoin.
+     *
+     * @return status upon completion
+     */
+    private int doJoin() {
+        int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;
+        return (s = status) < 0 ? s :
+            ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            (w = (wt = (ForkJoinWorkerThread)t).workQueue).
+            tryUnpush(this) && (s = doExec()) < 0 ? s :
+            wt.pool.awaitJoin(w, this, 0L) :
+            externalAwaitDone();
+    }
+
+    /**
+     * Implementation for invoke, quietlyInvoke.
+     *
+     * @return status upon completion
+     */
+    private int doInvoke() {
+        int s; Thread t; ForkJoinWorkerThread wt;
+        return (s = doExec()) < 0 ? s :
+            ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            (wt = (ForkJoinWorkerThread)t).pool.
+            awaitJoin(wt.workQueue, this, 0L) :
+            externalAwaitDone();
+    }
+
+    // Exception table support
+
+    /**
+     * Table of exceptions thrown by tasks, to enable reporting by
+     * callers. Because exceptions are rare, we don't directly keep
+     * them with task objects, but instead use a weak ref table.  Note
+     * that cancellation exceptions don't appear in the table, but are
+     * instead recorded as status values.
+     *
+     * Note: These statics are initialized below in static block.
+     */
+    private static final ExceptionNode[] exceptionTable;
+    private static final ReentrantLock exceptionTableLock;
+    private static final ReferenceQueue<Object> exceptionTableRefQueue;
+
+    /**
+     * Fixed capacity for exceptionTable.
+     */
+    private static final int EXCEPTION_MAP_CAPACITY = 32;
+
+    /**
+     * Key-value nodes for exception table.  The chained hash table
+     * uses identity comparisons, full locking, and weak references
+     * for keys. The table has a fixed capacity because it only
+     * maintains task exceptions long enough for joiners to access
+     * them, so should never become very large for sustained
+     * periods. However, since we do not know when the last joiner
+     * completes, we must use weak references and expunge them. We do
+     * so on each operation (hence full locking). Also, some thread in
+     * any ForkJoinPool will call helpExpungeStaleExceptions when its
+     * pool becomes isQuiescent.
+     */
+    static final class ExceptionNode extends WeakReference<ForkJoinTask<?>> {
+        final Throwable ex;
+        ExceptionNode next;
+        final long thrower;  // use id not ref to avoid weak cycles
+        final int hashCode;  // store task hashCode before weak ref disappears
+        ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next,
+                      ReferenceQueue<Object> exceptionTableRefQueue) {
+            super(task, exceptionTableRefQueue);
+            this.ex = ex;
+            this.next = next;
+            this.thrower = Thread.currentThread().getId();
+            this.hashCode = System.identityHashCode(task);
+        }
+    }
+
+    /**
+     * Records exception and sets status.
+     *
+     * @return status on exit
+     */
+    final int recordExceptionalCompletion(Throwable ex) {
+        int s;
+        if ((s = status) >= 0) {
+            int h = System.identityHashCode(this);
+            final ReentrantLock lock = exceptionTableLock;
+            lock.lock();
+            try {
+                expungeStaleExceptions();
+                ExceptionNode[] t = exceptionTable;
+                int i = h & (t.length - 1);
+                for (ExceptionNode e = t[i]; ; e = e.next) {
+                    if (e == null) {
+                        t[i] = new ExceptionNode(this, ex, t[i],
+                                                 exceptionTableRefQueue);
+                        break;
+                    }
+                    if (e.get() == this) // already present
+                        break;
+                }
+            } finally {
+                lock.unlock();
+            }
+            s = setCompletion(EXCEPTIONAL);
+        }
+        return s;
+    }
+
+    /**
+     * Records exception and possibly propagates.
+     *
+     * @return status on exit
+     */
+    private int setExceptionalCompletion(Throwable ex) {
+        int s = recordExceptionalCompletion(ex);
+        if ((s & DONE_MASK) == EXCEPTIONAL)
+            internalPropagateException(ex);
+        return s;
+    }
+
+    /**
+     * Hook for exception propagation support for tasks with completers.
+     */
+    void internalPropagateException(Throwable ex) {
+    }
+
+    /**
+     * Cancels, ignoring any exceptions thrown by cancel. Used during
+     * worker and pool shutdown. Cancel is spec'ed not to throw any
+     * exceptions, but if it does anyway, we have no recourse during
+     * shutdown, so guard against this case.
+     */
+    static final void cancelIgnoringExceptions(ForkJoinTask<?> t) {
+        if (t != null && t.status >= 0) {
+            try {
+                t.cancel(false);
+            } catch (Throwable ignore) {
+            }
+        }
+    }
+
+    /**
+     * Removes exception node and clears status.
+     */
+    private void clearExceptionalCompletion() {
+        int h = System.identityHashCode(this);
+        final ReentrantLock lock = exceptionTableLock;
+        lock.lock();
+        try {
+            ExceptionNode[] t = exceptionTable;
+            int i = h & (t.length - 1);
+            ExceptionNode e = t[i];
+            ExceptionNode pred = null;
+            while (e != null) {
+                ExceptionNode next = e.next;
+                if (e.get() == this) {
+                    if (pred == null)
+                        t[i] = next;
+                    else
+                        pred.next = next;
+                    break;
+                }
+                pred = e;
+                e = next;
+            }
+            expungeStaleExceptions();
+            status = 0;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns a rethrowable exception for this task, if available.
+     * To provide accurate stack traces, if the exception was not
+     * thrown by the current thread, we try to create a new exception
+     * of the same type as the one thrown, but with the recorded
+     * exception as its cause. If there is no such constructor, we
+     * instead try to use a no-arg constructor, followed by initCause,
+     * to the same effect. If none of these apply, or any fail due to
+     * other exceptions, we return the recorded exception, which is
+     * still correct, although it may contain a misleading stack
+     * trace.
+     *
+     * @return the exception, or null if none
+     */
+    private Throwable getThrowableException() {
+        int h = System.identityHashCode(this);
+        ExceptionNode e;
+        final ReentrantLock lock = exceptionTableLock;
+        lock.lock();
+        try {
+            expungeStaleExceptions();
+            ExceptionNode[] t = exceptionTable;
+            e = t[h & (t.length - 1)];
+            while (e != null && e.get() != this)
+                e = e.next;
+        } finally {
+            lock.unlock();
+        }
+        Throwable ex;
+        if (e == null || (ex = e.ex) == null)
+            return null;
+        if (e.thrower != Thread.currentThread().getId()) {
+            try {
+                Constructor<?> noArgCtor = null;
+                // public ctors only
+                for (Constructor<?> c : ex.getClass().getConstructors()) {
+                    Class<?>[] ps = c.getParameterTypes();
+                    if (ps.length == 0)
+                        noArgCtor = c;
+                    else if (ps.length == 1 && ps[0] == Throwable.class)
+                        return (Throwable)c.newInstance(ex);
+                }
+                if (noArgCtor != null) {
+                    Throwable wx = (Throwable)noArgCtor.newInstance();
+                    wx.initCause(ex);
+                    return wx;
+                }
+            } catch (Exception ignore) {
+            }
+        }
+        return ex;
+    }
+
+    /**
+     * Polls stale refs and removes them. Call only while holding lock.
+     */
+    private static void expungeStaleExceptions() {
+        for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
+            if (x instanceof ExceptionNode) {
+                int hashCode = ((ExceptionNode)x).hashCode;
+                ExceptionNode[] t = exceptionTable;
+                int i = hashCode & (t.length - 1);
+                ExceptionNode e = t[i];
+                ExceptionNode pred = null;
+                while (e != null) {
+                    ExceptionNode next = e.next;
+                    if (e == x) {
+                        if (pred == null)
+                            t[i] = next;
+                        else
+                            pred.next = next;
+                        break;
+                    }
+                    pred = e;
+                    e = next;
+                }
+            }
+        }
+    }
+
+    /**
+     * If lock is available, polls stale refs and removes them.
+     * Called from ForkJoinPool when pools become quiescent.
+     */
+    static final void helpExpungeStaleExceptions() {
+        final ReentrantLock lock = exceptionTableLock;
+        if (lock.tryLock()) {
+            try {
+                expungeStaleExceptions();
+            } finally {
+                lock.unlock();
+            }
+        }
+    }
+
+    /**
+     * A version of "sneaky throw" to relay exceptions.
+     */
+    static void rethrow(Throwable ex) {
+        ForkJoinTask.<RuntimeException>uncheckedThrow(ex);
+    }
+
+    /**
+     * The sneaky part of sneaky throw, relying on generics
+     * limitations to evade compiler complaints about rethrowing
+     * unchecked exceptions.
+     */
+    @SuppressWarnings("unchecked") static <T extends Throwable>
+    void uncheckedThrow(Throwable t) throws T {
+        if (t != null)
+            throw (T)t; // rely on vacuous cast
+        else
+            throw new Error("Unknown Exception");
+    }
+
+    /**
+     * Throws exception, if any, associated with the given status.
+     */
+    private void reportException(int s) {
+        if (s == CANCELLED)
+            throw new CancellationException();
+        if (s == EXCEPTIONAL)
+            rethrow(getThrowableException());
+    }
+
+    // public methods
+
+    /**
+     * Arranges to asynchronously execute this task in the pool the
+     * current task is running in, if applicable, or using the {@link
+     * ForkJoinPool#commonPool()} if not {@link #inForkJoinPool}.  While
+     * it is not necessarily enforced, it is a usage error to fork a
+     * task more than once unless it has completed and been
+     * reinitialized.  Subsequent modifications to the state of this
+     * task or any data it operates on are not necessarily
+     * consistently observable by any thread other than the one
+     * executing it unless preceded by a call to {@link #join} or
+     * related methods, or a call to {@link #isDone} returning {@code
+     * true}.
+     *
+     * @return {@code this}, to simplify usage
+     */
+    public final ForkJoinTask<V> fork() {
+        Thread t;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            ((ForkJoinWorkerThread)t).workQueue.push(this);
+        else
+            ForkJoinPool.common.externalPush(this);
+        return this;
+    }
+
+    /**
+     * Returns the result of the computation when it {@link #isDone is
+     * done}.  This method differs from {@link #get()} in that
+     * abnormal completion results in {@code RuntimeException} or
+     * {@code Error}, not {@code ExecutionException}, and that
+     * interrupts of the calling thread do <em>not</em> cause the
+     * method to abruptly return by throwing {@code
+     * InterruptedException}.
+     *
+     * @return the computed result
+     */
+    public final V join() {
+        int s;
+        if ((s = doJoin() & DONE_MASK) != NORMAL)
+            reportException(s);
+        return getRawResult();
+    }
+
+    /**
+     * Commences performing this task, awaits its completion if
+     * necessary, and returns its result, or throws an (unchecked)
+     * {@code RuntimeException} or {@code Error} if the underlying
+     * computation did so.
+     *
+     * @return the computed result
+     */
+    public final V invoke() {
+        int s;
+        if ((s = doInvoke() & DONE_MASK) != NORMAL)
+            reportException(s);
+        return getRawResult();
+    }
+
+    /**
+     * Forks the given tasks, returning when {@code isDone} holds for
+     * each task or an (unchecked) exception is encountered, in which
+     * case the exception is rethrown. If more than one task
+     * encounters an exception, then this method throws any one of
+     * these exceptions. If any task encounters an exception, the
+     * other may be cancelled. However, the execution status of
+     * individual tasks is not guaranteed upon exceptional return. The
+     * status of each task may be obtained using {@link
+     * #getException()} and related methods to check if they have been
+     * cancelled, completed normally or exceptionally, or left
+     * unprocessed.
+     *
+     * @param t1 the first task
+     * @param t2 the second task
+     * @throws NullPointerException if any task is null
+     */
+    public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) {
+        int s1, s2;
+        t2.fork();
+        if ((s1 = t1.doInvoke() & DONE_MASK) != NORMAL)
+            t1.reportException(s1);
+        if ((s2 = t2.doJoin() & DONE_MASK) != NORMAL)
+            t2.reportException(s2);
+    }
+
+    /**
+     * Forks the given tasks, returning when {@code isDone} holds for
+     * each task or an (unchecked) exception is encountered, in which
+     * case the exception is rethrown. If more than one task
+     * encounters an exception, then this method throws any one of
+     * these exceptions. If any task encounters an exception, others
+     * may be cancelled. However, the execution status of individual
+     * tasks is not guaranteed upon exceptional return. The status of
+     * each task may be obtained using {@link #getException()} and
+     * related methods to check if they have been cancelled, completed
+     * normally or exceptionally, or left unprocessed.
+     *
+     * @param tasks the tasks
+     * @throws NullPointerException if any task is null
+     */
+    public static void invokeAll(ForkJoinTask<?>... tasks) {
+        Throwable ex = null;
+        int last = tasks.length - 1;
+        for (int i = last; i >= 0; --i) {
+            ForkJoinTask<?> t = tasks[i];
+            if (t == null) {
+                if (ex == null)
+                    ex = new NullPointerException();
+            }
+            else if (i != 0)
+                t.fork();
+            else if (t.doInvoke() < NORMAL && ex == null)
+                ex = t.getException();
+        }
+        for (int i = 1; i <= last; ++i) {
+            ForkJoinTask<?> t = tasks[i];
+            if (t != null) {
+                if (ex != null)
+                    t.cancel(false);
+                else if (t.doJoin() < NORMAL)
+                    ex = t.getException();
+            }
+        }
+        if (ex != null)
+            rethrow(ex);
+    }
+
+    /**
+     * Forks all tasks in the specified collection, returning when
+     * {@code isDone} holds for each task or an (unchecked) exception
+     * is encountered, in which case the exception is rethrown. If
+     * more than one task encounters an exception, then this method
+     * throws any one of these exceptions. If any task encounters an
+     * exception, others may be cancelled. However, the execution
+     * status of individual tasks is not guaranteed upon exceptional
+     * return. The status of each task may be obtained using {@link
+     * #getException()} and related methods to check if they have been
+     * cancelled, completed normally or exceptionally, or left
+     * unprocessed.
+     *
+     * @param tasks the collection of tasks
+     * @param <T> the type of the values returned from the tasks
+     * @return the tasks argument, to simplify usage
+     * @throws NullPointerException if tasks or any element are null
+     */
+    public static <T extends ForkJoinTask<?>> Collection<T> invokeAll(Collection<T> tasks) {
+        if (!(tasks instanceof RandomAccess) || !(tasks instanceof List<?>)) {
+            invokeAll(tasks.toArray(new ForkJoinTask<?>[tasks.size()]));
+            return tasks;
+        }
+        @SuppressWarnings("unchecked")
+        List<? extends ForkJoinTask<?>> ts =
+            (List<? extends ForkJoinTask<?>>) tasks;
+        Throwable ex = null;
+        int last = ts.size() - 1;
+        for (int i = last; i >= 0; --i) {
+            ForkJoinTask<?> t = ts.get(i);
+            if (t == null) {
+                if (ex == null)
+                    ex = new NullPointerException();
+            }
+            else if (i != 0)
+                t.fork();
+            else if (t.doInvoke() < NORMAL && ex == null)
+                ex = t.getException();
+        }
+        for (int i = 1; i <= last; ++i) {
+            ForkJoinTask<?> t = ts.get(i);
+            if (t != null) {
+                if (ex != null)
+                    t.cancel(false);
+                else if (t.doJoin() < NORMAL)
+                    ex = t.getException();
+            }
+        }
+        if (ex != null)
+            rethrow(ex);
+        return tasks;
+    }
+
+    /**
+     * Attempts to cancel execution of this task. This attempt will
+     * fail if the task has already completed or could not be
+     * cancelled for some other reason. If successful, and this task
+     * has not started when {@code cancel} is called, execution of
+     * this task is suppressed. After this method returns
+     * successfully, unless there is an intervening call to {@link
+     * #reinitialize}, subsequent calls to {@link #isCancelled},
+     * {@link #isDone}, and {@code cancel} will return {@code true}
+     * and calls to {@link #join} and related methods will result in
+     * {@code CancellationException}.
+     *
+     * <p>This method may be overridden in subclasses, but if so, must
+     * still ensure that these properties hold. In particular, the
+     * {@code cancel} method itself must not throw exceptions.
+     *
+     * <p>This method is designed to be invoked by <em>other</em>
+     * tasks. To terminate the current task, you can just return or
+     * throw an unchecked exception from its computation method, or
+     * invoke {@link #completeExceptionally(Throwable)}.
+     *
+     * @param mayInterruptIfRunning this value has no effect in the
+     * default implementation because interrupts are not used to
+     * control cancellation.
+     *
+     * @return {@code true} if this task is now cancelled
+     */
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        return (setCompletion(CANCELLED) & DONE_MASK) == CANCELLED;
+    }
+
+    public final boolean isDone() {
+        return status < 0;
+    }
+
+    public final boolean isCancelled() {
+        return (status & DONE_MASK) == CANCELLED;
+    }
+
+    /**
+     * Returns {@code true} if this task threw an exception or was cancelled.
+     *
+     * @return {@code true} if this task threw an exception or was cancelled
+     */
+    public final boolean isCompletedAbnormally() {
+        return status < NORMAL;
+    }
+
+    /**
+     * Returns {@code true} if this task completed without throwing an
+     * exception and was not cancelled.
+     *
+     * @return {@code true} if this task completed without throwing an
+     * exception and was not cancelled
+     */
+    public final boolean isCompletedNormally() {
+        return (status & DONE_MASK) == NORMAL;
+    }
+
+    /**
+     * Returns the exception thrown by the base computation, or a
+     * {@code CancellationException} if cancelled, or {@code null} if
+     * none or if the method has not yet completed.
+     *
+     * @return the exception, or {@code null} if none
+     */
+    public final Throwable getException() {
+        int s = status & DONE_MASK;
+        return ((s >= NORMAL)    ? null :
+                (s == CANCELLED) ? new CancellationException() :
+                getThrowableException());
+    }
+
+    /**
+     * Completes this task abnormally, and if not already aborted or
+     * cancelled, causes it to throw the given exception upon
+     * {@code join} and related operations. This method may be used
+     * to induce exceptions in asynchronous tasks, or to force
+     * completion of tasks that would not otherwise complete.  Its use
+     * in other situations is discouraged.  This method is
+     * overridable, but overridden versions must invoke {@code super}
+     * implementation to maintain guarantees.
+     *
+     * @param ex the exception to throw. If this exception is not a
+     * {@code RuntimeException} or {@code Error}, the actual exception
+     * thrown will be a {@code RuntimeException} with cause {@code ex}.
+     */
+    public void completeExceptionally(Throwable ex) {
+        setExceptionalCompletion((ex instanceof RuntimeException) ||
+                                 (ex instanceof Error) ? ex :
+                                 new RuntimeException(ex));
+    }
+
+    /**
+     * Completes this task, and if not already aborted or cancelled,
+     * returning the given value as the result of subsequent
+     * invocations of {@code join} and related operations. This method
+     * may be used to provide results for asynchronous tasks, or to
+     * provide alternative handling for tasks that would not otherwise
+     * complete normally. Its use in other situations is
+     * discouraged. This method is overridable, but overridden
+     * versions must invoke {@code super} implementation to maintain
+     * guarantees.
+     *
+     * @param value the result value for this task
+     */
+    public void complete(V value) {
+        try {
+            setRawResult(value);
+        } catch (Throwable rex) {
+            setExceptionalCompletion(rex);
+            return;
+        }
+        setCompletion(NORMAL);
+    }
+
+    /**
+     * Completes this task normally without setting a value. The most
+     * recent value established by {@link #setRawResult} (or {@code
+     * null} by default) will be returned as the result of subsequent
+     * invocations of {@code join} and related operations.
+     *
+     * @since 1.8
+     */
+    public final void quietlyComplete() {
+        setCompletion(NORMAL);
+    }
+
+    /**
+     * Waits if necessary for the computation to complete, and then
+     * retrieves its result.
+     *
+     * @return the computed result
+     * @throws CancellationException if the computation was cancelled
+     * @throws ExecutionException if the computation threw an
+     * exception
+     * @throws InterruptedException if the current thread is not a
+     * member of a ForkJoinPool and was interrupted while waiting
+     */
+    public final V get() throws InterruptedException, ExecutionException {
+        int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
+            doJoin() : externalInterruptibleAwaitDone();
+        if ((s &= DONE_MASK) == CANCELLED)
+            throw new CancellationException();
+        if (s == EXCEPTIONAL)
+            throw new ExecutionException(getThrowableException());
+        return getRawResult();
+    }
+
+    /**
+     * Waits if necessary for at most the given time for the computation
+     * to complete, and then retrieves its result, if available.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return the computed result
+     * @throws CancellationException if the computation was cancelled
+     * @throws ExecutionException if the computation threw an
+     * exception
+     * @throws InterruptedException if the current thread is not a
+     * member of a ForkJoinPool and was interrupted while waiting
+     * @throws TimeoutException if the wait timed out
+     */
+    public final V get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        int s;
+        long nanos = unit.toNanos(timeout);
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if ((s = status) >= 0 && nanos > 0L) {
+            long d = System.nanoTime() + nanos;
+            long deadline = (d == 0L) ? 1L : d; // avoid 0
+            Thread t = Thread.currentThread();
+            if (t instanceof ForkJoinWorkerThread) {
+                ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
+                s = wt.pool.awaitJoin(wt.workQueue, this, deadline);
+            }
+            else if ((s = ((this instanceof CountedCompleter) ?
+                           ForkJoinPool.common.externalHelpComplete(
+                               (CountedCompleter<?>)this, 0) :
+                           ForkJoinPool.common.tryExternalUnpush(this) ?
+                           doExec() : 0)) >= 0) {
+                long ns, ms; // measure in nanosecs, but wait in millisecs
+                while ((s = status) >= 0 &&
+                       (ns = deadline - System.nanoTime()) > 0L) {
+                    if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
+                        U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                        synchronized (this) {
+                            if (status >= 0)
+                                wait(ms); // OK to throw InterruptedException
+                            else
+                                notifyAll();
+                        }
+                    }
+                }
+            }
+        }
+        if (s >= 0)
+            s = status;
+        if ((s &= DONE_MASK) != NORMAL) {
+            if (s == CANCELLED)
+                throw new CancellationException();
+            if (s != EXCEPTIONAL)
+                throw new TimeoutException();
+            throw new ExecutionException(getThrowableException());
+        }
+        return getRawResult();
+    }
+
+    /**
+     * Joins this task, without returning its result or throwing its
+     * exception. This method may be useful when processing
+     * collections of tasks when some have been cancelled or otherwise
+     * known to have aborted.
+     */
+    public final void quietlyJoin() {
+        doJoin();
+    }
+
+    /**
+     * Commences performing this task and awaits its completion if
+     * necessary, without returning its result or throwing its
+     * exception.
+     */
+    public final void quietlyInvoke() {
+        doInvoke();
+    }
+
+    /**
+     * Possibly executes tasks until the pool hosting the current task
+     * {@linkplain ForkJoinPool#isQuiescent is quiescent}.  This
+     * method may be of use in designs in which many tasks are forked,
+     * but none are explicitly joined, instead executing them until
+     * all are processed.
+     */
+    public static void helpQuiesce() {
+        Thread t;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
+            ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
+            wt.pool.helpQuiescePool(wt.workQueue);
+        }
+        else
+            ForkJoinPool.quiesceCommonPool();
+    }
+
+    /**
+     * Resets the internal bookkeeping state of this task, allowing a
+     * subsequent {@code fork}. This method allows repeated reuse of
+     * this task, but only if reuse occurs when this task has either
+     * never been forked, or has been forked, then completed and all
+     * outstanding joins of this task have also completed. Effects
+     * under any other usage conditions are not guaranteed.
+     * This method may be useful when executing
+     * pre-constructed trees of subtasks in loops.
+     *
+     * <p>Upon completion of this method, {@code isDone()} reports
+     * {@code false}, and {@code getException()} reports {@code
+     * null}. However, the value returned by {@code getRawResult} is
+     * unaffected. To clear this value, you can invoke {@code
+     * setRawResult(null)}.
+     */
+    public void reinitialize() {
+        if ((status & DONE_MASK) == EXCEPTIONAL)
+            clearExceptionalCompletion();
+        else
+            status = 0;
+    }
+
+    /**
+     * Returns the pool hosting the current thread, or {@code null}
+     * if the current thread is executing outside of any ForkJoinPool.
+     *
+     * <p>This method returns {@code null} if and only if {@link
+     * #inForkJoinPool} returns {@code false}.
+     *
+     * @return the pool, or {@code null} if none
+     */
+    public static ForkJoinPool getPool() {
+        Thread t = Thread.currentThread();
+        return (t instanceof ForkJoinWorkerThread) ?
+            ((ForkJoinWorkerThread) t).pool : null;
+    }
+
+    /**
+     * Returns {@code true} if the current thread is a {@link
+     * ForkJoinWorkerThread} executing as a ForkJoinPool computation.
+     *
+     * @return {@code true} if the current thread is a {@link
+     * ForkJoinWorkerThread} executing as a ForkJoinPool computation,
+     * or {@code false} otherwise
+     */
+    public static boolean inForkJoinPool() {
+        return Thread.currentThread() instanceof ForkJoinWorkerThread;
+    }
+
+    /**
+     * Tries to unschedule this task for execution. This method will
+     * typically (but is not guaranteed to) succeed if this task is
+     * the most recently forked task by the current thread, and has
+     * not commenced executing in another thread.  This method may be
+     * useful when arranging alternative local processing of tasks
+     * that could have been, but were not, stolen.
+     *
+     * @return {@code true} if unforked
+     */
+    public boolean tryUnfork() {
+        Thread t;
+        return (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+                ((ForkJoinWorkerThread)t).workQueue.tryUnpush(this) :
+                ForkJoinPool.common.tryExternalUnpush(this));
+    }
+
+    /**
+     * Returns an estimate of the number of tasks that have been
+     * forked by the current worker thread but not yet executed. This
+     * value may be useful for heuristic decisions about whether to
+     * fork other tasks.
+     *
+     * @return the number of tasks
+     */
+    public static int getQueuedTaskCount() {
+        Thread t; ForkJoinPool.WorkQueue q;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            q = ((ForkJoinWorkerThread)t).workQueue;
+        else
+            q = ForkJoinPool.commonSubmitterQueue();
+        return (q == null) ? 0 : q.queueSize();
+    }
+
+    /**
+     * Returns an estimate of how many more locally queued tasks are
+     * held by the current worker thread than there are other worker
+     * threads that might steal them, or zero if this thread is not
+     * operating in a ForkJoinPool. This value may be useful for
+     * heuristic decisions about whether to fork other tasks. In many
+     * usages of ForkJoinTasks, at steady state, each worker should
+     * aim to maintain a small constant surplus (for example, 3) of
+     * tasks, and to process computations locally if this threshold is
+     * exceeded.
+     *
+     * @return the surplus number of tasks, which may be negative
+     */
+    public static int getSurplusQueuedTaskCount() {
+        return ForkJoinPool.getSurplusQueuedTaskCount();
+    }
+
+    // Extension methods
+
+    /**
+     * Returns the result that would be returned by {@link #join}, even
+     * if this task completed abnormally, or {@code null} if this task
+     * is not known to have been completed.  This method is designed
+     * to aid debugging, as well as to support extensions. Its use in
+     * any other context is discouraged.
+     *
+     * @return the result, or {@code null} if not completed
+     */
+    public abstract V getRawResult();
+
+    /**
+     * Forces the given value to be returned as a result.  This method
+     * is designed to support extensions, and should not in general be
+     * called otherwise.
+     *
+     * @param value the value
+     */
+    protected abstract void setRawResult(V value);
+
+    /**
+     * Immediately performs the base action of this task and returns
+     * true if, upon return from this method, this task is guaranteed
+     * to have completed normally. This method may return false
+     * otherwise, to indicate that this task is not necessarily
+     * complete (or is not known to be complete), for example in
+     * asynchronous actions that require explicit invocations of
+     * completion methods. This method may also throw an (unchecked)
+     * exception to indicate abnormal exit. This method is designed to
+     * support extensions, and should not in general be called
+     * otherwise.
+     *
+     * @return {@code true} if this task is known to have completed normally
+     */
+    protected abstract boolean exec();
+
+    /**
+     * Returns, but does not unschedule or execute, a task queued by
+     * the current thread but not yet executed, if one is immediately
+     * available. There is no guarantee that this task will actually
+     * be polled or executed next. Conversely, this method may return
+     * null even if a task exists but cannot be accessed without
+     * contention with other threads.  This method is designed
+     * primarily to support extensions, and is unlikely to be useful
+     * otherwise.
+     *
+     * @return the next task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> peekNextLocalTask() {
+        Thread t; ForkJoinPool.WorkQueue q;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            q = ((ForkJoinWorkerThread)t).workQueue;
+        else
+            q = ForkJoinPool.commonSubmitterQueue();
+        return (q == null) ? null : q.peek();
+    }
+
+    /**
+     * Unschedules and returns, without executing, the next task
+     * queued by the current thread but not yet executed, if the
+     * current thread is operating in a ForkJoinPool.  This method is
+     * designed primarily to support extensions, and is unlikely to be
+     * useful otherwise.
+     *
+     * @return the next task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> pollNextLocalTask() {
+        Thread t;
+        return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            ((ForkJoinWorkerThread)t).workQueue.nextLocalTask() :
+            null;
+    }
+
+    /**
+     * If the current thread is operating in a ForkJoinPool,
+     * unschedules and returns, without executing, the next task
+     * queued by the current thread but not yet executed, if one is
+     * available, or if not available, a task that was forked by some
+     * other thread, if available. Availability may be transient, so a
+     * {@code null} result does not necessarily imply quiescence of
+     * the pool this task is operating in.  This method is designed
+     * primarily to support extensions, and is unlikely to be useful
+     * otherwise.
+     *
+     * @return a task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> pollTask() {
+        Thread t; ForkJoinWorkerThread wt;
+        return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            (wt = (ForkJoinWorkerThread)t).pool.nextTaskFor(wt.workQueue) :
+            null;
+    }
+
+    /**
+     * If the current thread is operating in a ForkJoinPool,
+     * unschedules and returns, without executing, a task externally
+     * submitted to the pool, if one is available. Availability may be
+     * transient, so a {@code null} result does not necessarily imply
+     * quiescence of the pool.  This method is designed primarily to
+     * support extensions, and is unlikely to be useful otherwise.
+     *
+     * @return a task, or {@code null} if none are available
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    protected static ForkJoinTask<?> pollSubmission() {
+        Thread t;
+        return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            ((ForkJoinWorkerThread)t).pool.pollSubmission() : null;
+    }
+
+    // tag operations
+
+    /**
+     * Returns the tag for this task.
+     *
+     * @return the tag for this task
+     * @since 1.8
+     */
+    public final short getForkJoinTaskTag() {
+        return (short)status;
+    }
+
+    /**
+     * Atomically sets the tag value for this task and returns the old value.
+     *
+     * @param newValue the new tag value
+     * @return the previous value of the tag
+     * @since 1.8
+     */
+    public final short setForkJoinTaskTag(short newValue) {
+        for (int s;;) {
+            if (U.compareAndSwapInt(this, STATUS, s = status,
+                                    (s & ~SMASK) | (newValue & SMASK)))
+                return (short)s;
+        }
+    }
+
+    /**
+     * Atomically conditionally sets the tag value for this task.
+     * Among other applications, tags can be used as visit markers
+     * in tasks operating on graphs, as in methods that check: {@code
+     * if (task.compareAndSetForkJoinTaskTag((short)0, (short)1))}
+     * before processing, otherwise exiting because the node has
+     * already been visited.
+     *
+     * @param expect the expected tag value
+     * @param update the new tag value
+     * @return {@code true} if successful; i.e., the current value was
+     * equal to {@code expect} and was changed to {@code update}.
+     * @since 1.8
+     */
+    public final boolean compareAndSetForkJoinTaskTag(short expect, short update) {
+        for (int s;;) {
+            if ((short)(s = status) != expect)
+                return false;
+            if (U.compareAndSwapInt(this, STATUS, s,
+                                    (s & ~SMASK) | (update & SMASK)))
+                return true;
+        }
+    }
+
+    /**
+     * Adapter for Runnables. This implements RunnableFuture
+     * to be compliant with AbstractExecutorService constraints
+     * when used in ForkJoinPool.
+     */
+    static final class AdaptedRunnable<T> extends ForkJoinTask<T>
+        implements RunnableFuture<T> {
+        final Runnable runnable;
+        T result;
+        AdaptedRunnable(Runnable runnable, T result) {
+            if (runnable == null) throw new NullPointerException();
+            this.runnable = runnable;
+            this.result = result; // OK to set this even before completion
+        }
+        public final T getRawResult() { return result; }
+        public final void setRawResult(T v) { result = v; }
+        public final boolean exec() { runnable.run(); return true; }
+        public final void run() { invoke(); }
+        private static final long serialVersionUID = 5232453952276885070L;
+    }
+
+    /**
+     * Adapter for Runnables without results.
+     */
+    static final class AdaptedRunnableAction extends ForkJoinTask<Void>
+        implements RunnableFuture<Void> {
+        final Runnable runnable;
+        AdaptedRunnableAction(Runnable runnable) {
+            if (runnable == null) throw new NullPointerException();
+            this.runnable = runnable;
+        }
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) { }
+        public final boolean exec() { runnable.run(); return true; }
+        public final void run() { invoke(); }
+        private static final long serialVersionUID = 5232453952276885070L;
+    }
+
+    /**
+     * Adapter for Runnables in which failure forces worker exception.
+     */
+    static final class RunnableExecuteAction extends ForkJoinTask<Void> {
+        final Runnable runnable;
+        RunnableExecuteAction(Runnable runnable) {
+            if (runnable == null) throw new NullPointerException();
+            this.runnable = runnable;
+        }
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) { }
+        public final boolean exec() { runnable.run(); return true; }
+        void internalPropagateException(Throwable ex) {
+            rethrow(ex); // rethrow outside exec() catches.
+        }
+        private static final long serialVersionUID = 5232453952276885070L;
+    }
+
+    /**
+     * Adapter for Callables.
+     */
+    static final class AdaptedCallable<T> extends ForkJoinTask<T>
+        implements RunnableFuture<T> {
+        final Callable<? extends T> callable;
+        T result;
+        AdaptedCallable(Callable<? extends T> callable) {
+            if (callable == null) throw new NullPointerException();
+            this.callable = callable;
+        }
+        public final T getRawResult() { return result; }
+        public final void setRawResult(T v) { result = v; }
+        public final boolean exec() {
+            try {
+                result = callable.call();
+                return true;
+            } catch (RuntimeException rex) {
+                throw rex;
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        public final void run() { invoke(); }
+        private static final long serialVersionUID = 2838392045355241008L;
+    }
+
+    /**
+     * Returns a new {@code ForkJoinTask} that performs the {@code run}
+     * method of the given {@code Runnable} as its action, and returns
+     * a null result upon {@link #join}.
+     *
+     * @param runnable the runnable action
+     * @return the task
+     */
+    public static ForkJoinTask<?> adapt(Runnable runnable) {
+        return new AdaptedRunnableAction(runnable);
+    }
+
+    /**
+     * Returns a new {@code ForkJoinTask} that performs the {@code run}
+     * method of the given {@code Runnable} as its action, and returns
+     * the given result upon {@link #join}.
+     *
+     * @param runnable the runnable action
+     * @param result the result upon completion
+     * @param <T> the type of the result
+     * @return the task
+     */
+    public static <T> ForkJoinTask<T> adapt(Runnable runnable, T result) {
+        return new AdaptedRunnable<T>(runnable, result);
+    }
+
+    /**
+     * Returns a new {@code ForkJoinTask} that performs the {@code call}
+     * method of the given {@code Callable} as its action, and returns
+     * its result upon {@link #join}, translating any checked exceptions
+     * encountered into {@code RuntimeException}.
+     *
+     * @param callable the callable action
+     * @param <T> the type of the callable's result
+     * @return the task
+     */
+    public static <T> ForkJoinTask<T> adapt(Callable<? extends T> callable) {
+        return new AdaptedCallable<T>(callable);
+    }
+
+    // Serialization support
+
+    private static final long serialVersionUID = -7721805057305804111L;
+
+    /**
+     * Saves this task to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData the current run status and the exception thrown
+     * during execution, or {@code null} if none
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        s.defaultWriteObject();
+        s.writeObject(getException());
+    }
+
+    /**
+     * Reconstitutes this task from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        Object ex = s.readObject();
+        if (ex != null)
+            setExceptionalCompletion((Throwable)ex);
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATUS;
+
+    static {
+        exceptionTableLock = new ReentrantLock();
+        exceptionTableRefQueue = new ReferenceQueue<Object>();
+        exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
+        try {
+            STATUS = U.objectFieldOffset
+                (ForkJoinTask.class.getDeclaredField("status"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/ForkJoinWorkerThread.java b/java/util/concurrent/ForkJoinWorkerThread.java
new file mode 100644
index 0000000..e98ba99
--- /dev/null
+++ b/java/util/concurrent/ForkJoinWorkerThread.java
@@ -0,0 +1,273 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+
+/**
+ * A thread managed by a {@link ForkJoinPool}, which executes
+ * {@link ForkJoinTask}s.
+ * This class is subclassable solely for the sake of adding
+ * functionality -- there are no overridable methods dealing with
+ * scheduling or execution.  However, you can override initialization
+ * and termination methods surrounding the main task processing loop.
+ * If you do create such a subclass, you will also need to supply a
+ * custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to
+ * {@linkplain ForkJoinPool#ForkJoinPool use it} in a {@code ForkJoinPool}.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public class ForkJoinWorkerThread extends Thread {
+    /*
+     * ForkJoinWorkerThreads are managed by ForkJoinPools and perform
+     * ForkJoinTasks. For explanation, see the internal documentation
+     * of class ForkJoinPool.
+     *
+     * This class just maintains links to its pool and WorkQueue.  The
+     * pool field is set immediately upon construction, but the
+     * workQueue field is not set until a call to registerWorker
+     * completes. This leads to a visibility race, that is tolerated
+     * by requiring that the workQueue field is only accessed by the
+     * owning thread.
+     *
+     * Support for (non-public) subclass InnocuousForkJoinWorkerThread
+     * requires that we break quite a lot of encapsulation (via Unsafe)
+     * both here and in the subclass to access and set Thread fields.
+     */
+
+    final ForkJoinPool pool;                // the pool this thread works in
+    final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics
+
+    /**
+     * Creates a ForkJoinWorkerThread operating in the given pool.
+     *
+     * @param pool the pool this thread works in
+     * @throws NullPointerException if pool is null
+     */
+    protected ForkJoinWorkerThread(ForkJoinPool pool) {
+        // Use a placeholder until a useful name can be set in registerWorker
+        super("aForkJoinWorkerThread");
+        this.pool = pool;
+        this.workQueue = pool.registerWorker(this);
+    }
+
+    /**
+     * Version for InnocuousForkJoinWorkerThread.
+     */
+    ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
+                         AccessControlContext acc) {
+        super(threadGroup, null, "aForkJoinWorkerThread");
+        U.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, acc);
+        eraseThreadLocals(); // clear before registering
+        this.pool = pool;
+        this.workQueue = pool.registerWorker(this);
+    }
+
+    /**
+     * Returns the pool hosting this thread.
+     *
+     * @return the pool
+     */
+    public ForkJoinPool getPool() {
+        return pool;
+    }
+
+    /**
+     * Returns the unique index number of this thread in its pool.
+     * The returned value ranges from zero to the maximum number of
+     * threads (minus one) that may exist in the pool, and does not
+     * change during the lifetime of the thread.  This method may be
+     * useful for applications that track status or collect results
+     * per-worker-thread rather than per-task.
+     *
+     * @return the index number
+     */
+    public int getPoolIndex() {
+        return workQueue.getPoolIndex();
+    }
+
+    /**
+     * Initializes internal state after construction but before
+     * processing any tasks. If you override this method, you must
+     * invoke {@code super.onStart()} at the beginning of the method.
+     * Initialization requires care: Most fields must have legal
+     * default values, to ensure that attempted accesses from other
+     * threads work correctly even before this thread starts
+     * processing tasks.
+     */
+    protected void onStart() {
+    }
+
+    /**
+     * Performs cleanup associated with termination of this worker
+     * thread.  If you override this method, you must invoke
+     * {@code super.onTermination} at the end of the overridden method.
+     *
+     * @param exception the exception causing this thread to abort due
+     * to an unrecoverable error, or {@code null} if completed normally
+     */
+    protected void onTermination(Throwable exception) {
+    }
+
+    /**
+     * This method is required to be public, but should never be
+     * called explicitly. It performs the main run loop to execute
+     * {@link ForkJoinTask}s.
+     */
+    public void run() {
+        if (workQueue.array == null) { // only run once
+            Throwable exception = null;
+            try {
+                onStart();
+                pool.runWorker(workQueue);
+            } catch (Throwable ex) {
+                exception = ex;
+            } finally {
+                try {
+                    onTermination(exception);
+                } catch (Throwable ex) {
+                    if (exception == null)
+                        exception = ex;
+                } finally {
+                    pool.deregisterWorker(this, exception);
+                }
+            }
+        }
+    }
+
+    /**
+     * Erases ThreadLocals by nulling out Thread maps.
+     */
+    final void eraseThreadLocals() {
+        U.putObject(this, THREADLOCALS, null);
+        U.putObject(this, INHERITABLETHREADLOCALS, null);
+    }
+
+    /**
+     * Non-public hook method for InnocuousForkJoinWorkerThread.
+     */
+    void afterTopLevelExec() {
+    }
+
+    // Set up to allow setting thread fields in constructor
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long THREADLOCALS;
+    private static final long INHERITABLETHREADLOCALS;
+    private static final long INHERITEDACCESSCONTROLCONTEXT;
+    static {
+        try {
+            THREADLOCALS = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocals"));
+            INHERITABLETHREADLOCALS = U.objectFieldOffset
+                (Thread.class.getDeclaredField("inheritableThreadLocals"));
+            INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
+                (Thread.class.getDeclaredField("inheritedAccessControlContext"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    /**
+     * A worker thread that has no permissions, is not a member of any
+     * user-defined ThreadGroup, and erases all ThreadLocals after
+     * running each top-level task.
+     */
+    static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
+        /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
+        private static final ThreadGroup innocuousThreadGroup =
+            createThreadGroup();
+
+        /** An AccessControlContext supporting no privileges */
+        private static final AccessControlContext INNOCUOUS_ACC =
+            new AccessControlContext(
+                new ProtectionDomain[] {
+                    new ProtectionDomain(null, null)
+                });
+
+        InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
+            super(pool, innocuousThreadGroup, INNOCUOUS_ACC);
+        }
+
+        @Override // to erase ThreadLocals
+        void afterTopLevelExec() {
+            eraseThreadLocals();
+        }
+
+        @Override // to always report system loader
+        public ClassLoader getContextClassLoader() {
+            return ClassLoader.getSystemClassLoader();
+        }
+
+        @Override // to silently fail
+        public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }
+
+        @Override // paranoically
+        public void setContextClassLoader(ClassLoader cl) {
+            throw new SecurityException("setContextClassLoader");
+        }
+
+        /**
+         * Returns a new group with the system ThreadGroup (the
+         * topmost, parent-less group) as parent.  Uses Unsafe to
+         * traverse Thread.group and ThreadGroup.parent fields.
+         */
+        private static ThreadGroup createThreadGroup() {
+            try {
+                sun.misc.Unsafe u = sun.misc.Unsafe.getUnsafe();
+                long tg = u.objectFieldOffset
+                    (Thread.class.getDeclaredField("group"));
+                long gp = u.objectFieldOffset
+                    (ThreadGroup.class.getDeclaredField("parent"));
+                ThreadGroup group = (ThreadGroup)
+                    u.getObject(Thread.currentThread(), tg);
+                while (group != null) {
+                    ThreadGroup parent = (ThreadGroup)u.getObject(group, gp);
+                    if (parent == null)
+                        return new ThreadGroup(group,
+                                               "InnocuousForkJoinWorkerThreadGroup");
+                    group = parent;
+                }
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+            // fall through if null as cannot-happen safeguard
+            throw new Error("Cannot create ThreadGroup");
+        }
+    }
+
+}
diff --git a/java/util/concurrent/Future.java b/java/util/concurrent/Future.java
new file mode 100644
index 0000000..9bd05d6
--- /dev/null
+++ b/java/util/concurrent/Future.java
@@ -0,0 +1,170 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@code Future} represents the result of an asynchronous
+ * computation.  Methods are provided to check if the computation is
+ * complete, to wait for its completion, and to retrieve the result of
+ * the computation.  The result can only be retrieved using method
+ * {@code get} when the computation has completed, blocking if
+ * necessary until it is ready.  Cancellation is performed by the
+ * {@code cancel} method.  Additional methods are provided to
+ * determine if the task completed normally or was cancelled. Once a
+ * computation has completed, the computation cannot be cancelled.
+ * If you would like to use a {@code Future} for the sake
+ * of cancellability but not provide a usable result, you can
+ * declare types of the form {@code Future<?>} and
+ * return {@code null} as a result of the underlying task.
+ *
+ * <p>
+ * <b>Sample Usage</b> (Note that the following classes are all
+ * made-up.)
+ *
+ * <pre> {@code
+ * interface ArchiveSearcher { String search(String target); }
+ * class App {
+ *   ExecutorService executor = ...
+ *   ArchiveSearcher searcher = ...
+ *   void showSearch(final String target)
+ *       throws InterruptedException {
+ *     Future<String> future
+ *       = executor.submit(new Callable<String>() {
+ *         public String call() {
+ *             return searcher.search(target);
+ *         }});
+ *     displayOtherThings(); // do other things while searching
+ *     try {
+ *       displayText(future.get()); // use future
+ *     } catch (ExecutionException ex) { cleanup(); return; }
+ *   }
+ * }}</pre>
+ *
+ * The {@link FutureTask} class is an implementation of {@code Future} that
+ * implements {@code Runnable}, and so may be executed by an {@code Executor}.
+ * For example, the above construction with {@code submit} could be replaced by:
+ * <pre> {@code
+ * FutureTask<String> future =
+ *   new FutureTask<>(new Callable<String>() {
+ *     public String call() {
+ *       return searcher.search(target);
+ *   }});
+ * executor.execute(future);}</pre>
+ *
+ * <p>Memory consistency effects: Actions taken by the asynchronous computation
+ * <a href="package-summary.html#MemoryVisibility"> <i>happen-before</i></a>
+ * actions following the corresponding {@code Future.get()} in another thread.
+ *
+ * @see FutureTask
+ * @see Executor
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future's {@code get} method
+ */
+public interface Future<V> {
+
+    /**
+     * Attempts to cancel execution of this task.  This attempt will
+     * fail if the task has already completed, has already been cancelled,
+     * or could not be cancelled for some other reason. If successful,
+     * and this task has not started when {@code cancel} is called,
+     * this task should never run.  If the task has already started,
+     * then the {@code mayInterruptIfRunning} parameter determines
+     * whether the thread executing this task should be interrupted in
+     * an attempt to stop the task.
+     *
+     * <p>After this method returns, subsequent calls to {@link #isDone} will
+     * always return {@code true}.  Subsequent calls to {@link #isCancelled}
+     * will always return {@code true} if this method returned {@code true}.
+     *
+     * @param mayInterruptIfRunning {@code true} if the thread executing this
+     * task should be interrupted; otherwise, in-progress tasks are allowed
+     * to complete
+     * @return {@code false} if the task could not be cancelled,
+     * typically because it has already completed normally;
+     * {@code true} otherwise
+     */
+    boolean cancel(boolean mayInterruptIfRunning);
+
+    /**
+     * Returns {@code true} if this task was cancelled before it completed
+     * normally.
+     *
+     * @return {@code true} if this task was cancelled before it completed
+     */
+    boolean isCancelled();
+
+    /**
+     * Returns {@code true} if this task completed.
+     *
+     * Completion may be due to normal termination, an exception, or
+     * cancellation -- in all of these cases, this method will return
+     * {@code true}.
+     *
+     * @return {@code true} if this task completed
+     */
+    boolean isDone();
+
+    /**
+     * Waits if necessary for the computation to complete, and then
+     * retrieves its result.
+     *
+     * @return the computed result
+     * @throws CancellationException if the computation was cancelled
+     * @throws ExecutionException if the computation threw an
+     * exception
+     * @throws InterruptedException if the current thread was interrupted
+     * while waiting
+     */
+    V get() throws InterruptedException, ExecutionException;
+
+    /**
+     * Waits if necessary for at most the given time for the computation
+     * to complete, and then retrieves its result, if available.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return the computed result
+     * @throws CancellationException if the computation was cancelled
+     * @throws ExecutionException if the computation threw an
+     * exception
+     * @throws InterruptedException if the current thread was interrupted
+     * while waiting
+     * @throws TimeoutException if the wait timed out
+     */
+    V get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException;
+}
diff --git a/java/util/concurrent/FutureTask.java b/java/util/concurrent/FutureTask.java
new file mode 100644
index 0000000..62c2bfc
--- /dev/null
+++ b/java/util/concurrent/FutureTask.java
@@ -0,0 +1,508 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.locks.LockSupport;
+
+/**
+ * A cancellable asynchronous computation.  This class provides a base
+ * implementation of {@link Future}, with methods to start and cancel
+ * a computation, query to see if the computation is complete, and
+ * retrieve the result of the computation.  The result can only be
+ * retrieved when the computation has completed; the {@code get}
+ * methods will block if the computation has not yet completed.  Once
+ * the computation has completed, the computation cannot be restarted
+ * or cancelled (unless the computation is invoked using
+ * {@link #runAndReset}).
+ *
+ * <p>A {@code FutureTask} can be used to wrap a {@link Callable} or
+ * {@link Runnable} object.  Because {@code FutureTask} implements
+ * {@code Runnable}, a {@code FutureTask} can be submitted to an
+ * {@link Executor} for execution.
+ *
+ * <p>In addition to serving as a standalone class, this class provides
+ * {@code protected} functionality that may be useful when creating
+ * customized task classes.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The result type returned by this FutureTask's {@code get} methods
+ */
+public class FutureTask<V> implements RunnableFuture<V> {
+    /*
+     * Revision notes: This differs from previous versions of this
+     * class that relied on AbstractQueuedSynchronizer, mainly to
+     * avoid surprising users about retaining interrupt status during
+     * cancellation races. Sync control in the current design relies
+     * on a "state" field updated via CAS to track completion, along
+     * with a simple Treiber stack to hold waiting threads.
+     *
+     * Style note: As usual, we bypass overhead of using
+     * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
+     */
+
+    /**
+     * The run state of this task, initially NEW.  The run state
+     * transitions to a terminal state only in methods set,
+     * setException, and cancel.  During completion, state may take on
+     * transient values of COMPLETING (while outcome is being set) or
+     * INTERRUPTING (only while interrupting the runner to satisfy a
+     * cancel(true)). Transitions from these intermediate to final
+     * states use cheaper ordered/lazy writes because values are unique
+     * and cannot be further modified.
+     *
+     * Possible state transitions:
+     * NEW -> COMPLETING -> NORMAL
+     * NEW -> COMPLETING -> EXCEPTIONAL
+     * NEW -> CANCELLED
+     * NEW -> INTERRUPTING -> INTERRUPTED
+     */
+    private volatile int state;
+    private static final int NEW          = 0;
+    private static final int COMPLETING   = 1;
+    private static final int NORMAL       = 2;
+    private static final int EXCEPTIONAL  = 3;
+    private static final int CANCELLED    = 4;
+    private static final int INTERRUPTING = 5;
+    private static final int INTERRUPTED  = 6;
+
+    /** The underlying callable; nulled out after running */
+    private Callable<V> callable;
+    /** The result to return or exception to throw from get() */
+    private Object outcome; // non-volatile, protected by state reads/writes
+    /** The thread running the callable; CASed during run() */
+    private volatile Thread runner;
+    /** Treiber stack of waiting threads */
+    private volatile WaitNode waiters;
+
+    /**
+     * Returns result or throws exception for completed task.
+     *
+     * @param s completed state value
+     */
+    @SuppressWarnings("unchecked")
+    private V report(int s) throws ExecutionException {
+        Object x = outcome;
+        if (s == NORMAL)
+            return (V)x;
+        if (s >= CANCELLED)
+            throw new CancellationException();
+        throw new ExecutionException((Throwable)x);
+    }
+
+    /**
+     * Creates a {@code FutureTask} that will, upon running, execute the
+     * given {@code Callable}.
+     *
+     * @param  callable the callable task
+     * @throws NullPointerException if the callable is null
+     */
+    public FutureTask(Callable<V> callable) {
+        if (callable == null)
+            throw new NullPointerException();
+        this.callable = callable;
+        this.state = NEW;       // ensure visibility of callable
+    }
+
+    /**
+     * Creates a {@code FutureTask} that will, upon running, execute the
+     * given {@code Runnable}, and arrange that {@code get} will return the
+     * given result on successful completion.
+     *
+     * @param runnable the runnable task
+     * @param result the result to return on successful completion. If
+     * you don't need a particular result, consider using
+     * constructions of the form:
+     * {@code Future<?> f = new FutureTask<Void>(runnable, null)}
+     * @throws NullPointerException if the runnable is null
+     */
+    public FutureTask(Runnable runnable, V result) {
+        this.callable = Executors.callable(runnable, result);
+        this.state = NEW;       // ensure visibility of callable
+    }
+
+    public boolean isCancelled() {
+        return state >= CANCELLED;
+    }
+
+    public boolean isDone() {
+        return state != NEW;
+    }
+
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        if (!(state == NEW &&
+              U.compareAndSwapInt(this, STATE, NEW,
+                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
+            return false;
+        try {    // in case call to interrupt throws exception
+            if (mayInterruptIfRunning) {
+                try {
+                    Thread t = runner;
+                    if (t != null)
+                        t.interrupt();
+                } finally { // final state
+                    U.putOrderedInt(this, STATE, INTERRUPTED);
+                }
+            }
+        } finally {
+            finishCompletion();
+        }
+        return true;
+    }
+
+    /**
+     * @throws CancellationException {@inheritDoc}
+     */
+    public V get() throws InterruptedException, ExecutionException {
+        int s = state;
+        if (s <= COMPLETING)
+            s = awaitDone(false, 0L);
+        return report(s);
+    }
+
+    /**
+     * @throws CancellationException {@inheritDoc}
+     */
+    public V get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        if (unit == null)
+            throw new NullPointerException();
+        int s = state;
+        if (s <= COMPLETING &&
+            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
+            throw new TimeoutException();
+        return report(s);
+    }
+
+    /**
+     * Protected method invoked when this task transitions to state
+     * {@code isDone} (whether normally or via cancellation). The
+     * default implementation does nothing.  Subclasses may override
+     * this method to invoke completion callbacks or perform
+     * bookkeeping. Note that you can query status inside the
+     * implementation of this method to determine whether this task
+     * has been cancelled.
+     */
+    protected void done() { }
+
+    /**
+     * Sets the result of this future to the given value unless
+     * this future has already been set or has been cancelled.
+     *
+     * <p>This method is invoked internally by the {@link #run} method
+     * upon successful completion of the computation.
+     *
+     * @param v the value
+     */
+    protected void set(V v) {
+        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+            outcome = v;
+            U.putOrderedInt(this, STATE, NORMAL); // final state
+            finishCompletion();
+        }
+    }
+
+    /**
+     * Causes this future to report an {@link ExecutionException}
+     * with the given throwable as its cause, unless this future has
+     * already been set or has been cancelled.
+     *
+     * <p>This method is invoked internally by the {@link #run} method
+     * upon failure of the computation.
+     *
+     * @param t the cause of failure
+     */
+    protected void setException(Throwable t) {
+        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+            outcome = t;
+            U.putOrderedInt(this, STATE, EXCEPTIONAL); // final state
+            finishCompletion();
+        }
+    }
+
+    public void run() {
+        if (state != NEW ||
+            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+            return;
+        try {
+            Callable<V> c = callable;
+            if (c != null && state == NEW) {
+                V result;
+                boolean ran;
+                try {
+                    result = c.call();
+                    ran = true;
+                } catch (Throwable ex) {
+                    result = null;
+                    ran = false;
+                    setException(ex);
+                }
+                if (ran)
+                    set(result);
+            }
+        } finally {
+            // runner must be non-null until state is settled to
+            // prevent concurrent calls to run()
+            runner = null;
+            // state must be re-read after nulling runner to prevent
+            // leaked interrupts
+            int s = state;
+            if (s >= INTERRUPTING)
+                handlePossibleCancellationInterrupt(s);
+        }
+    }
+
+    /**
+     * Executes the computation without setting its result, and then
+     * resets this future to initial state, failing to do so if the
+     * computation encounters an exception or is cancelled.  This is
+     * designed for use with tasks that intrinsically execute more
+     * than once.
+     *
+     * @return {@code true} if successfully run and reset
+     */
+    protected boolean runAndReset() {
+        if (state != NEW ||
+            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+            return false;
+        boolean ran = false;
+        int s = state;
+        try {
+            Callable<V> c = callable;
+            if (c != null && s == NEW) {
+                try {
+                    c.call(); // don't set result
+                    ran = true;
+                } catch (Throwable ex) {
+                    setException(ex);
+                }
+            }
+        } finally {
+            // runner must be non-null until state is settled to
+            // prevent concurrent calls to run()
+            runner = null;
+            // state must be re-read after nulling runner to prevent
+            // leaked interrupts
+            s = state;
+            if (s >= INTERRUPTING)
+                handlePossibleCancellationInterrupt(s);
+        }
+        return ran && s == NEW;
+    }
+
+    /**
+     * Ensures that any interrupt from a possible cancel(true) is only
+     * delivered to a task while in run or runAndReset.
+     */
+    private void handlePossibleCancellationInterrupt(int s) {
+        // It is possible for our interrupter to stall before getting a
+        // chance to interrupt us.  Let's spin-wait patiently.
+        if (s == INTERRUPTING)
+            while (state == INTERRUPTING)
+                Thread.yield(); // wait out pending interrupt
+
+        // assert state == INTERRUPTED;
+
+        // We want to clear any interrupt we may have received from
+        // cancel(true).  However, it is permissible to use interrupts
+        // as an independent mechanism for a task to communicate with
+        // its caller, and there is no way to clear only the
+        // cancellation interrupt.
+        //
+        // Thread.interrupted();
+    }
+
+    /**
+     * Simple linked list nodes to record waiting threads in a Treiber
+     * stack.  See other classes such as Phaser and SynchronousQueue
+     * for more detailed explanation.
+     */
+    static final class WaitNode {
+        volatile Thread thread;
+        volatile WaitNode next;
+        WaitNode() { thread = Thread.currentThread(); }
+    }
+
+    /**
+     * Removes and signals all waiting threads, invokes done(), and
+     * nulls out callable.
+     */
+    private void finishCompletion() {
+        // assert state > COMPLETING;
+        for (WaitNode q; (q = waiters) != null;) {
+            if (U.compareAndSwapObject(this, WAITERS, q, null)) {
+                for (;;) {
+                    Thread t = q.thread;
+                    if (t != null) {
+                        q.thread = null;
+                        LockSupport.unpark(t);
+                    }
+                    WaitNode next = q.next;
+                    if (next == null)
+                        break;
+                    q.next = null; // unlink to help gc
+                    q = next;
+                }
+                break;
+            }
+        }
+
+        done();
+
+        callable = null;        // to reduce footprint
+    }
+
+    /**
+     * Awaits completion or aborts on interrupt or timeout.
+     *
+     * @param timed true if use timed waits
+     * @param nanos time to wait, if timed
+     * @return state upon completion or at timeout
+     */
+    private int awaitDone(boolean timed, long nanos)
+        throws InterruptedException {
+        // The code below is very delicate, to achieve these goals:
+        // - call nanoTime exactly once for each call to park
+        // - if nanos <= 0L, return promptly without allocation or nanoTime
+        // - if nanos == Long.MIN_VALUE, don't underflow
+        // - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
+        //   and we suffer a spurious wakeup, we will do no worse than
+        //   to park-spin for a while
+        long startTime = 0L;    // Special value 0L means not yet parked
+        WaitNode q = null;
+        boolean queued = false;
+        for (;;) {
+            int s = state;
+            if (s > COMPLETING) {
+                if (q != null)
+                    q.thread = null;
+                return s;
+            }
+            else if (s == COMPLETING)
+                // We may have already promised (via isDone) that we are done
+                // so never return empty-handed or throw InterruptedException
+                Thread.yield();
+            else if (Thread.interrupted()) {
+                removeWaiter(q);
+                throw new InterruptedException();
+            }
+            else if (q == null) {
+                if (timed && nanos <= 0L)
+                    return s;
+                q = new WaitNode();
+            }
+            else if (!queued)
+                queued = U.compareAndSwapObject(this, WAITERS,
+                                                q.next = waiters, q);
+            else if (timed) {
+                final long parkNanos;
+                if (startTime == 0L) { // first time
+                    startTime = System.nanoTime();
+                    if (startTime == 0L)
+                        startTime = 1L;
+                    parkNanos = nanos;
+                } else {
+                    long elapsed = System.nanoTime() - startTime;
+                    if (elapsed >= nanos) {
+                        removeWaiter(q);
+                        return state;
+                    }
+                    parkNanos = nanos - elapsed;
+                }
+                // nanoTime may be slow; recheck before parking
+                if (state < COMPLETING)
+                    LockSupport.parkNanos(this, parkNanos);
+            }
+            else
+                LockSupport.park(this);
+        }
+    }
+
+    /**
+     * Tries to unlink a timed-out or interrupted wait node to avoid
+     * accumulating garbage.  Internal nodes are simply unspliced
+     * without CAS since it is harmless if they are traversed anyway
+     * by releasers.  To avoid effects of unsplicing from already
+     * removed nodes, the list is retraversed in case of an apparent
+     * race.  This is slow when there are a lot of nodes, but we don't
+     * expect lists to be long enough to outweigh higher-overhead
+     * schemes.
+     */
+    private void removeWaiter(WaitNode node) {
+        if (node != null) {
+            node.thread = null;
+            retry:
+            for (;;) {          // restart on removeWaiter race
+                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
+                    s = q.next;
+                    if (q.thread != null)
+                        pred = q;
+                    else if (pred != null) {
+                        pred.next = s;
+                        if (pred.thread == null) // check for race
+                            continue retry;
+                    }
+                    else if (!U.compareAndSwapObject(this, WAITERS, q, s))
+                        continue retry;
+                }
+                break;
+            }
+        }
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
+    private static final long RUNNER;
+    private static final long WAITERS;
+    static {
+        try {
+            STATE = U.objectFieldOffset
+                (FutureTask.class.getDeclaredField("state"));
+            RUNNER = U.objectFieldOffset
+                (FutureTask.class.getDeclaredField("runner"));
+            WAITERS = U.objectFieldOffset
+                (FutureTask.class.getDeclaredField("waiters"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+
+}
diff --git a/java/util/concurrent/Helpers.java b/java/util/concurrent/Helpers.java
new file mode 100644
index 0000000..369da0e
--- /dev/null
+++ b/java/util/concurrent/Helpers.java
@@ -0,0 +1,118 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Martin Buchholz with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as
+ * explained at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+
+/** Shared implementation code for java.util.concurrent. */
+class Helpers {
+    private Helpers() {}                // non-instantiable
+
+    /**
+     * An implementation of Collection.toString() suitable for classes
+     * with locks.  Instead of holding a lock for the entire duration of
+     * toString(), or acquiring a lock for each call to Iterator.next(),
+     * we hold the lock only during the call to toArray() (less
+     * disruptive to other threads accessing the collection) and follows
+     * the maxim "Never call foreign code while holding a lock".
+     */
+    static String collectionToString(Collection<?> c) {
+        final Object[] a = c.toArray();
+        final int size = a.length;
+        if (size == 0)
+            return "[]";
+        int charLength = 0;
+
+        // Replace every array element with its string representation
+        for (int i = 0; i < size; i++) {
+            Object e = a[i];
+            // Extreme compatibility with AbstractCollection.toString()
+            String s = (e == c) ? "(this Collection)" : objectToString(e);
+            a[i] = s;
+            charLength += s.length();
+        }
+
+        return toString(a, size, charLength);
+    }
+
+    /**
+     * Like Arrays.toString(), but caller guarantees that size > 0,
+     * each element with index 0 <= i < size is a non-null String,
+     * and charLength is the sum of the lengths of the input Strings.
+     */
+    static String toString(Object[] a, int size, int charLength) {
+        // assert a != null;
+        // assert size > 0;
+
+        // Copy each string into a perfectly sized char[]
+        // Length of [ , , , ] == 2 * size
+        final char[] chars = new char[charLength + 2 * size];
+        chars[0] = '[';
+        int j = 1;
+        for (int i = 0; i < size; i++) {
+            if (i > 0) {
+                chars[j++] = ',';
+                chars[j++] = ' ';
+            }
+            String s = (String) a[i];
+            int len = s.length();
+            s.getChars(0, len, chars, j);
+            j += len;
+        }
+        chars[j] = ']';
+        // assert j == chars.length - 1;
+        return new String(chars);
+    }
+
+    /** Optimized form of: key + "=" + val */
+    static String mapEntryToString(Object key, Object val) {
+        final String k, v;
+        final int klen, vlen;
+        final char[] chars =
+            new char[(klen = (k = objectToString(key)).length()) +
+                     (vlen = (v = objectToString(val)).length()) + 1];
+        k.getChars(0, klen, chars, 0);
+        chars[klen] = '=';
+        v.getChars(0, vlen, chars, klen + 1);
+        return new String(chars);
+    }
+
+    private static String objectToString(Object x) {
+        // Extreme compatibility with StringBuilder.append(null)
+        String s;
+        return (x == null || (s = x.toString()) == null) ? "null" : s;
+    }
+}
diff --git a/java/util/concurrent/LinkedBlockingDeque.java b/java/util/concurrent/LinkedBlockingDeque.java
new file mode 100644
index 0000000..9829c9c
--- /dev/null
+++ b/java/util/concurrent/LinkedBlockingDeque.java
@@ -0,0 +1,1315 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on
+ * linked nodes.
+ *
+ * <p>The optional capacity bound constructor argument serves as a
+ * way to prevent excessive expansion. The capacity, if unspecified,
+ * is equal to {@link Integer#MAX_VALUE}.  Linked nodes are
+ * dynamically created upon each insertion unless this would bring the
+ * deque above capacity.
+ *
+ * <p>Most operations run in constant time (ignoring time spent
+ * blocking).  Exceptions include {@link #remove(Object) remove},
+ * {@link #removeFirstOccurrence removeFirstOccurrence}, {@link
+ * #removeLastOccurrence removeLastOccurrence}, {@link #contains
+ * contains}, {@link #iterator iterator.remove()}, and the bulk
+ * operations, all of which run in linear time.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * @since 1.6
+ * @author  Doug Lea
+ * @param <E> the type of elements held in this deque
+ */
+public class LinkedBlockingDeque<E>
+    extends AbstractQueue<E>
+    implements BlockingDeque<E>, java.io.Serializable {
+
+    /*
+     * Implemented as a simple doubly-linked list protected by a
+     * single lock and using conditions to manage blocking.
+     *
+     * To implement weakly consistent iterators, it appears we need to
+     * keep all Nodes GC-reachable from a predecessor dequeued Node.
+     * That would cause two problems:
+     * - allow a rogue Iterator to cause unbounded memory retention
+     * - cause cross-generational linking of old Nodes to new Nodes if
+     *   a Node was tenured while live, which generational GCs have a
+     *   hard time dealing with, causing repeated major collections.
+     * However, only non-deleted Nodes need to be reachable from
+     * dequeued Nodes, and reachability does not necessarily have to
+     * be of the kind understood by the GC.  We use the trick of
+     * linking a Node that has just been dequeued to itself.  Such a
+     * self-link implicitly means to jump to "first" (for next links)
+     * or "last" (for prev links).
+     */
+
+    /*
+     * We have "diamond" multiple interface/abstract class inheritance
+     * here, and that introduces ambiguities. Often we want the
+     * BlockingDeque javadoc combined with the AbstractQueue
+     * implementation, so a lot of method specs are duplicated here.
+     */
+
+    private static final long serialVersionUID = -387911632671998426L;
+
+    /** Doubly-linked list node class */
+    static final class Node<E> {
+        /**
+         * The item, or null if this node has been removed.
+         */
+        E item;
+
+        /**
+         * One of:
+         * - the real predecessor Node
+         * - this Node, meaning the predecessor is tail
+         * - null, meaning there is no predecessor
+         */
+        Node<E> prev;
+
+        /**
+         * One of:
+         * - the real successor Node
+         * - this Node, meaning the successor is head
+         * - null, meaning there is no successor
+         */
+        Node<E> next;
+
+        Node(E x) {
+            item = x;
+        }
+    }
+
+    /**
+     * 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;
+
+    /** Number of items in the deque */
+    private transient int count;
+
+    /** Maximum number of items in the deque */
+    private final int capacity;
+
+    /** Main lock guarding all access */
+    final ReentrantLock lock = new ReentrantLock();
+
+    /** Condition for waiting takes */
+    private final Condition notEmpty = lock.newCondition();
+
+    /** Condition for waiting puts */
+    private final Condition notFull = lock.newCondition();
+
+    /**
+     * Creates a {@code LinkedBlockingDeque} with a capacity of
+     * {@link Integer#MAX_VALUE}.
+     */
+    public LinkedBlockingDeque() {
+        this(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity.
+     *
+     * @param capacity the capacity of this deque
+     * @throws IllegalArgumentException if {@code capacity} is less than 1
+     */
+    public LinkedBlockingDeque(int capacity) {
+        if (capacity <= 0) throw new IllegalArgumentException();
+        this.capacity = capacity;
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingDeque} with a capacity of
+     * {@link Integer#MAX_VALUE}, initially containing the elements of
+     * the given collection, added in traversal order of the
+     * collection's iterator.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public LinkedBlockingDeque(Collection<? extends E> c) {
+        this(Integer.MAX_VALUE);
+        final ReentrantLock lock = this.lock;
+        lock.lock(); // Never contended, but necessary for visibility
+        try {
+            for (E e : c) {
+                if (e == null)
+                    throw new NullPointerException();
+                if (!linkLast(new Node<E>(e)))
+                    throw new IllegalStateException("Deque full");
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+
+    // Basic linking and unlinking operations, called only while holding lock
+
+    /**
+     * Links node as first element, or returns false if full.
+     */
+    private boolean linkFirst(Node<E> node) {
+        // assert lock.isHeldByCurrentThread();
+        if (count >= capacity)
+            return false;
+        Node<E> f = first;
+        node.next = f;
+        first = node;
+        if (last == null)
+            last = node;
+        else
+            f.prev = node;
+        ++count;
+        notEmpty.signal();
+        return true;
+    }
+
+    /**
+     * Links node as last element, or returns false if full.
+     */
+    private boolean linkLast(Node<E> node) {
+        // assert lock.isHeldByCurrentThread();
+        if (count >= capacity)
+            return false;
+        Node<E> l = last;
+        node.prev = l;
+        last = node;
+        if (first == null)
+            first = node;
+        else
+            l.next = node;
+        ++count;
+        notEmpty.signal();
+        return true;
+    }
+
+    /**
+     * Removes and returns first element, or null if empty.
+     */
+    private E unlinkFirst() {
+        // assert lock.isHeldByCurrentThread();
+        Node<E> f = first;
+        if (f == null)
+            return null;
+        Node<E> n = f.next;
+        E item = f.item;
+        f.item = null;
+        f.next = f; // help GC
+        first = n;
+        if (n == null)
+            last = null;
+        else
+            n.prev = null;
+        --count;
+        notFull.signal();
+        return item;
+    }
+
+    /**
+     * Removes and returns last element, or null if empty.
+     */
+    private E unlinkLast() {
+        // assert lock.isHeldByCurrentThread();
+        Node<E> l = last;
+        if (l == null)
+            return null;
+        Node<E> p = l.prev;
+        E item = l.item;
+        l.item = null;
+        l.prev = l; // help GC
+        last = p;
+        if (p == null)
+            first = null;
+        else
+            p.next = null;
+        --count;
+        notFull.signal();
+        return item;
+    }
+
+    /**
+     * Unlinks x.
+     */
+    void unlink(Node<E> x) {
+        // assert lock.isHeldByCurrentThread();
+        Node<E> p = x.prev;
+        Node<E> n = x.next;
+        if (p == null) {
+            unlinkFirst();
+        } else if (n == null) {
+            unlinkLast();
+        } else {
+            p.next = n;
+            n.prev = p;
+            x.item = null;
+            // Don't mess with x's links.  They may still be in use by
+            // an iterator.
+            --count;
+            notFull.signal();
+        }
+    }
+
+    // BlockingDeque methods
+
+    /**
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void addFirst(E e) {
+        if (!offerFirst(e))
+            throw new IllegalStateException("Deque full");
+    }
+
+    /**
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException  {@inheritDoc}
+     */
+    public void addLast(E e) {
+        if (!offerLast(e))
+            throw new IllegalStateException("Deque full");
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offerFirst(E e) {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return linkFirst(node);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offerLast(E e) {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return linkLast(node);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public void putFirst(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            while (!linkFirst(node))
+                notFull.await();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public void putLast(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            while (!linkLast(node))
+                notFull.await();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public boolean offerFirst(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (!linkFirst(node)) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public boolean offerLast(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (!linkLast(node)) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeFirst() {
+        E x = pollFirst();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeLast() {
+        E x = pollLast();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    public E pollFirst() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return unlinkFirst();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E pollLast() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return unlinkLast();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E takeFirst() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            E x;
+            while ( (x = unlinkFirst()) == null)
+                notEmpty.await();
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E takeLast() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            E x;
+            while ( (x = unlinkLast()) == null)
+                notEmpty.await();
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E pollFirst(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            E x;
+            while ( (x = unlinkFirst()) == null) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E pollLast(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            E x;
+            while ( (x = unlinkLast()) == null) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getFirst() {
+        E x = peekFirst();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getLast() {
+        E x = peekLast();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    public E peekFirst() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (first == null) ? null : first.item;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E peekLast() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (last == null) ? null : last.item;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public boolean removeFirstOccurrence(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> p = first; p != null; p = p.next) {
+                if (o.equals(p.item)) {
+                    unlink(p);
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public boolean removeLastOccurrence(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> p = last; p != null; p = p.prev) {
+                if (o.equals(p.item)) {
+                    unlink(p);
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // BlockingQueue methods
+
+    /**
+     * Inserts the specified element at the end of this deque unless it would
+     * violate capacity restrictions.  When using a capacity-restricted deque,
+     * it is generally preferable to use method {@link #offer(Object) offer}.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        return offerLast(e);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        putLast(e);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        return offerLast(e, timeout, unit);
+    }
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque.
+     * This method differs from {@link #poll poll} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    public E remove() {
+        return removeFirst();
+    }
+
+    public E poll() {
+        return pollFirst();
+    }
+
+    public E take() throws InterruptedException {
+        return takeFirst();
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        return pollFirst(timeout, unit);
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque.  This method differs from {@link #peek peek} only in that
+     * it throws an exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst() getFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    public E element() {
+        return getFirst();
+    }
+
+    public E peek() {
+        return peekFirst();
+    }
+
+    /**
+     * Returns the number of additional elements that this deque can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking. This is always equal to the initial capacity of this deque
+     * less the current {@code size} of this deque.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     */
+    public int remainingCapacity() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return capacity - count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = Math.min(maxElements, count);
+            for (int i = 0; i < n; i++) {
+                c.add(first.item);   // In this order, in case add() throws.
+                unlinkFirst();
+            }
+            return n;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // Stack methods
+
+    /**
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void push(E e) {
+        addFirst(e);
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E pop() {
+        return removeFirst();
+    }
+
+    // Collection methods
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to
+     * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if this deque changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        return removeFirstOccurrence(o);
+    }
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this deque
+     * @return {@code true} if this deque contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> p = first; p != null; p = p.next)
+                if (o.equals(p.item))
+                    return true;
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /*
+     * TODO: Add support for more efficient bulk operations.
+     *
+     * We don't want to acquire the lock for every iteration, but we
+     * also want other threads a chance to interact with the
+     * collection, especially when count is close to capacity.
+     */
+
+//     /**
+//      * Adds all of the elements in the specified collection to this
+//      * queue.  Attempts to addAll of a queue to itself result in
+//      * {@code IllegalArgumentException}. Further, the behavior of
+//      * this operation is undefined if the specified collection is
+//      * modified while the operation is in progress.
+//      *
+//      * @param c collection containing elements to be added to this queue
+//      * @return {@code true} if this queue changed as a result of the call
+//      * @throws ClassCastException            {@inheritDoc}
+//      * @throws NullPointerException          {@inheritDoc}
+//      * @throws IllegalArgumentException      {@inheritDoc}
+//      * @throws IllegalStateException if this deque is full
+//      * @see #add(Object)
+//      */
+//     public boolean addAll(Collection<? extends E> c) {
+//         if (c == null)
+//             throw new NullPointerException();
+//         if (c == this)
+//             throw new IllegalArgumentException();
+//         final ReentrantLock lock = this.lock;
+//         lock.lock();
+//         try {
+//             boolean modified = false;
+//             for (E e : c)
+//                 if (linkLast(e))
+//                     modified = true;
+//             return modified;
+//         } finally {
+//             lock.unlock();
+//         }
+//     }
+
+    /**
+     * Returns an array containing all of the elements in this deque, in
+     * proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this deque.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this deque
+     */
+    @SuppressWarnings("unchecked")
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            Object[] a = new Object[count];
+            int k = 0;
+            for (Node<E> p = first; p != null; p = p.next)
+                a[k++] = p.item;
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the deque fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this deque.
+     *
+     * <p>If this deque fits in the specified array with room to spare
+     * (i.e., the array has more elements than this deque), the element in
+     * the array immediately following the end of the deque is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a deque known to contain only strings.
+     * The following code can be used to dump the deque into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the deque are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this deque
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this deque
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (a.length < count)
+                a = (T[])java.lang.reflect.Array.newInstance
+                    (a.getClass().getComponentType(), count);
+
+            int k = 0;
+            for (Node<E> p = first; p != null; p = p.next)
+                a[k++] = (T)p.item;
+            if (a.length > k)
+                a[k] = null;
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * Atomically removes all of the elements from this deque.
+     * The deque will be empty after this call returns.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> f = first; f != null; ) {
+                f.item = null;
+                Node<E> n = f.next;
+                f.prev = null;
+                f.next = null;
+                f = n;
+            }
+            first = last = null;
+            count = 0;
+            notFull.signalAll();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in reverse
+     * sequential order.  The elements will be returned in order from
+     * last (tail) to first (head).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in reverse order
+     */
+    public Iterator<E> descendingIterator() {
+        return new DescendingItr();
+    }
+
+    /**
+     * Base class for LinkedBlockingDeque iterators.
+     */
+    private abstract class AbstractItr implements Iterator<E> {
+        /**
+         * The next node to return in next().
+         */
+        Node<E> next;
+
+        /**
+         * nextItem holds on to item fields because once we claim that
+         * an element exists in hasNext(), we must return item read
+         * under lock (in advance()) even if it was in the process of
+         * being removed when hasNext() was called.
+         */
+        E nextItem;
+
+        /**
+         * Node returned by most recent call to next. Needed by remove.
+         * Reset to null if this element is deleted by a call to remove.
+         */
+        private Node<E> lastRet;
+
+        abstract Node<E> firstNode();
+        abstract Node<E> nextNode(Node<E> n);
+
+        AbstractItr() {
+            // set to initial position
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            lock.lock();
+            try {
+                next = firstNode();
+                nextItem = (next == null) ? null : next.item;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        /**
+         * Returns the successor node of the given non-null, but
+         * possibly previously deleted, node.
+         */
+        private Node<E> succ(Node<E> n) {
+            // Chains of deleted nodes ending in null or self-links
+            // are possible if multiple interior nodes are removed.
+            for (;;) {
+                Node<E> s = nextNode(n);
+                if (s == null)
+                    return null;
+                else if (s.item != null)
+                    return s;
+                else if (s == n)
+                    return firstNode();
+                else
+                    n = s;
+            }
+        }
+
+        /**
+         * Advances next.
+         */
+        void advance() {
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            lock.lock();
+            try {
+                // assert next != null;
+                next = succ(next);
+                nextItem = (next == null) ? null : next.item;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        public E next() {
+            if (next == null)
+                throw new NoSuchElementException();
+            lastRet = next;
+            E x = nextItem;
+            advance();
+            return x;
+        }
+
+        public void remove() {
+            Node<E> n = lastRet;
+            if (n == null)
+                throw new IllegalStateException();
+            lastRet = null;
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            lock.lock();
+            try {
+                if (n.item != null)
+                    unlink(n);
+            } finally {
+                lock.unlock();
+            }
+        }
+    }
+
+    /** Forward iterator */
+    private class Itr extends AbstractItr {
+        Node<E> firstNode() { return first; }
+        Node<E> nextNode(Node<E> n) { return n.next; }
+    }
+
+    /** Descending iterator */
+    private class DescendingItr extends AbstractItr {
+        Node<E> firstNode() { return last; }
+        Node<E> nextNode(Node<E> n) { return n.prev; }
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class LBDSpliterator<E> implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final LinkedBlockingDeque<E> queue;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        long est;           // size estimate
+        LBDSpliterator(LinkedBlockingDeque<E> queue) {
+            this.queue = queue;
+            this.est = queue.size();
+        }
+
+        public long estimateSize() { return est; }
+
+        public Spliterator<E> trySplit() {
+            Node<E> h;
+            final LinkedBlockingDeque<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((h = current) != null || (h = q.first) != null) &&
+                h.next != null) {
+                Object[] a = new Object[n];
+                final ReentrantLock lock = q.lock;
+                int i = 0;
+                Node<E> p = current;
+                lock.lock();
+                try {
+                    if (p != null || (p = q.first) != null) {
+                        do {
+                            if ((a[i] = p.item) != null)
+                                ++i;
+                        } while ((p = p.next) != null && i < n);
+                    }
+                } finally {
+                    lock.unlock();
+                }
+                if ((current = p) == null) {
+                    est = 0L;
+                    exhausted = true;
+                }
+                else if ((est -= i) < 0L)
+                    est = 0L;
+                if (i > 0) {
+                    batch = i;
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingDeque<E> q = this.queue;
+            final ReentrantLock lock = q.lock;
+            if (!exhausted) {
+                exhausted = true;
+                Node<E> p = current;
+                do {
+                    E e = null;
+                    lock.lock();
+                    try {
+                        if (p == null)
+                            p = q.first;
+                        while (p != null) {
+                            e = p.item;
+                            p = p.next;
+                            if (e != null)
+                                break;
+                        }
+                    } finally {
+                        lock.unlock();
+                    }
+                    if (e != null)
+                        action.accept(e);
+                } while (p != null);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingDeque<E> q = this.queue;
+            final ReentrantLock lock = q.lock;
+            if (!exhausted) {
+                E e = null;
+                lock.lock();
+                try {
+                    if (current == null)
+                        current = q.first;
+                    while (current != null) {
+                        e = current.item;
+                        current = current.next;
+                        if (e != null)
+                            break;
+                    }
+                } finally {
+                    lock.unlock();
+                }
+                if (current == null)
+                    exhausted = true;
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this deque.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new LBDSpliterator<E>(this);
+    }
+
+    /**
+     * Saves this deque to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The capacity (int), followed by elements (each an
+     * {@code Object}) in the proper order, followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            // Write out capacity and any hidden stuff
+            s.defaultWriteObject();
+            // Write out all elements in the proper order.
+            for (Node<E> p = first; p != null; p = p.next)
+                s.writeObject(p.item);
+            // Use trailing null as sentinel
+            s.writeObject(null);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Reconstitutes this deque from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        count = 0;
+        first = null;
+        last = null;
+        // Read in all elements and place in queue
+        for (;;) {
+            @SuppressWarnings("unchecked")
+            E item = (E)s.readObject();
+            if (item == null)
+                break;
+            add(item);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/LinkedBlockingQueue.java b/java/util/concurrent/LinkedBlockingQueue.java
new file mode 100644
index 0000000..cf2d447
--- /dev/null
+++ b/java/util/concurrent/LinkedBlockingQueue.java
@@ -0,0 +1,1015 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
+ * linked nodes.
+ * This queue orders elements FIFO (first-in-first-out).
+ * The <em>head</em> of the queue is that element that has been on the
+ * queue the longest time.
+ * The <em>tail</em> of the queue is that element that has been on the
+ * queue the shortest time. New elements
+ * are inserted at the tail of the queue, and the queue retrieval
+ * operations obtain elements at the head of the queue.
+ * Linked queues typically have higher throughput than array-based queues but
+ * less predictable performance in most concurrent applications.
+ *
+ * <p>The optional capacity bound constructor argument serves as a
+ * way to prevent excessive queue expansion. The capacity, if unspecified,
+ * is equal to {@link Integer#MAX_VALUE}.  Linked nodes are
+ * dynamically created upon each insertion unless this would bring the
+ * queue above capacity.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class LinkedBlockingQueue<E> extends AbstractQueue<E>
+        implements BlockingQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = -6903933977591709194L;
+
+    /*
+     * A variant of the "two lock queue" algorithm.  The putLock gates
+     * entry to put (and offer), and has an associated condition for
+     * waiting puts.  Similarly for the takeLock.  The "count" field
+     * that they both rely on is maintained as an atomic to avoid
+     * needing to get both locks in most cases. Also, to minimize need
+     * for puts to get takeLock and vice-versa, cascading notifies are
+     * used. When a put notices that it has enabled at least one take,
+     * it signals taker. That taker in turn signals others if more
+     * items have been entered since the signal. And symmetrically for
+     * takes signalling puts. Operations such as remove(Object) and
+     * iterators acquire both locks.
+     *
+     * Visibility between writers and readers is provided as follows:
+     *
+     * Whenever an element is enqueued, the putLock is acquired and
+     * count updated.  A subsequent reader guarantees visibility to the
+     * enqueued Node by either acquiring the putLock (via fullyLock)
+     * or by acquiring the takeLock, and then reading n = count.get();
+     * this gives visibility to the first n items.
+     *
+     * To implement weakly consistent iterators, it appears we need to
+     * keep all Nodes GC-reachable from a predecessor dequeued Node.
+     * That would cause two problems:
+     * - allow a rogue Iterator to cause unbounded memory retention
+     * - cause cross-generational linking of old Nodes to new Nodes if
+     *   a Node was tenured while live, which generational GCs have a
+     *   hard time dealing with, causing repeated major collections.
+     * However, only non-deleted Nodes need to be reachable from
+     * dequeued Nodes, and reachability does not necessarily have to
+     * be of the kind understood by the GC.  We use the trick of
+     * linking a Node that has just been dequeued to itself.  Such a
+     * self-link implicitly means to advance to head.next.
+     */
+
+    /**
+     * Linked list node class.
+     */
+    static class Node<E> {
+        E item;
+
+        /**
+         * One of:
+         * - the real successor Node
+         * - this Node, meaning the successor is head.next
+         * - null, meaning there is no successor (this is the last node)
+         */
+        Node<E> next;
+
+        Node(E x) { item = x; }
+    }
+
+    /** The capacity bound, or Integer.MAX_VALUE if none */
+    private final int capacity;
+
+    /** Current number of elements */
+    private final AtomicInteger count = new AtomicInteger();
+
+    /**
+     * Head of linked list.
+     * Invariant: head.item == null
+     */
+    transient Node<E> head;
+
+    /**
+     * Tail of linked list.
+     * Invariant: last.next == null
+     */
+    private transient Node<E> last;
+
+    /** Lock held by take, poll, etc */
+    private final ReentrantLock takeLock = new ReentrantLock();
+
+    /** Wait queue for waiting takes */
+    private final Condition notEmpty = takeLock.newCondition();
+
+    /** Lock held by put, offer, etc */
+    private final ReentrantLock putLock = new ReentrantLock();
+
+    /** Wait queue for waiting puts */
+    private final Condition notFull = putLock.newCondition();
+
+    /**
+     * Signals a waiting take. Called only from put/offer (which do not
+     * otherwise ordinarily lock takeLock.)
+     */
+    private void signalNotEmpty() {
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+    }
+
+    /**
+     * Signals a waiting put. Called only from take/poll.
+     */
+    private void signalNotFull() {
+        final ReentrantLock putLock = this.putLock;
+        putLock.lock();
+        try {
+            notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+    }
+
+    /**
+     * Links node at end of queue.
+     *
+     * @param node the node
+     */
+    private void enqueue(Node<E> node) {
+        // assert putLock.isHeldByCurrentThread();
+        // assert last.next == null;
+        last = last.next = node;
+    }
+
+    /**
+     * Removes a node from head of queue.
+     *
+     * @return the node
+     */
+    private E dequeue() {
+        // assert takeLock.isHeldByCurrentThread();
+        // assert head.item == null;
+        Node<E> h = head;
+        Node<E> first = h.next;
+        h.next = h; // help GC
+        head = first;
+        E x = first.item;
+        first.item = null;
+        return x;
+    }
+
+    /**
+     * Locks to prevent both puts and takes.
+     */
+    void fullyLock() {
+        putLock.lock();
+        takeLock.lock();
+    }
+
+    /**
+     * Unlocks to allow both puts and takes.
+     */
+    void fullyUnlock() {
+        takeLock.unlock();
+        putLock.unlock();
+    }
+
+//     /**
+//      * Tells whether both locks are held by current thread.
+//      */
+//     boolean isFullyLocked() {
+//         return (putLock.isHeldByCurrentThread() &&
+//                 takeLock.isHeldByCurrentThread());
+//     }
+
+    /**
+     * Creates a {@code LinkedBlockingQueue} with a capacity of
+     * {@link Integer#MAX_VALUE}.
+     */
+    public LinkedBlockingQueue() {
+        this(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
+     *
+     * @param capacity the capacity of this queue
+     * @throws IllegalArgumentException if {@code capacity} is not greater
+     *         than zero
+     */
+    public LinkedBlockingQueue(int capacity) {
+        if (capacity <= 0) throw new IllegalArgumentException();
+        this.capacity = capacity;
+        last = head = new Node<E>(null);
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingQueue} with a capacity of
+     * {@link Integer#MAX_VALUE}, initially containing the elements of the
+     * given collection,
+     * added in traversal order of the collection's iterator.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public LinkedBlockingQueue(Collection<? extends E> c) {
+        this(Integer.MAX_VALUE);
+        final ReentrantLock putLock = this.putLock;
+        putLock.lock(); // Never contended, but necessary for visibility
+        try {
+            int n = 0;
+            for (E e : c) {
+                if (e == null)
+                    throw new NullPointerException();
+                if (n == capacity)
+                    throw new IllegalStateException("Queue full");
+                enqueue(new Node<E>(e));
+                ++n;
+            }
+            count.set(n);
+        } finally {
+            putLock.unlock();
+        }
+    }
+
+    // this doc comment is overridden to remove the reference to collections
+    // greater in size than Integer.MAX_VALUE
+    /**
+     * Returns the number of elements in this queue.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        return count.get();
+    }
+
+    // this doc comment is a modified copy of the inherited doc comment,
+    // without the reference to unlimited queues.
+    /**
+     * Returns the number of additional elements that this queue can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking. This is always equal to the initial capacity of this queue
+     * less the current {@code size} of this queue.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     */
+    public int remainingCapacity() {
+        return capacity - count.get();
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting if
+     * necessary for space to become available.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        // Note: convention in all put/take/etc is to preset local var
+        // holding count negative to indicate failure unless set.
+        int c = -1;
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock putLock = this.putLock;
+        final AtomicInteger count = this.count;
+        putLock.lockInterruptibly();
+        try {
+            /*
+             * Note that count is used in wait guard even though it is
+             * not protected by lock. This works because count can
+             * only decrease at this point (all other puts are shut
+             * out by lock), and we (or some other waiting put) are
+             * signalled if it ever changes from capacity. Similarly
+             * for all other uses of count in other wait guards.
+             */
+            while (count.get() == capacity) {
+                notFull.await();
+            }
+            enqueue(node);
+            c = count.getAndIncrement();
+            if (c + 1 < capacity)
+                notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting if
+     * necessary up to the specified wait time for space to become available.
+     *
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before space is available
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+
+        if (e == null) throw new NullPointerException();
+        long nanos = unit.toNanos(timeout);
+        int c = -1;
+        final ReentrantLock putLock = this.putLock;
+        final AtomicInteger count = this.count;
+        putLock.lockInterruptibly();
+        try {
+            while (count.get() == capacity) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            enqueue(new Node<E>(e));
+            c = count.getAndIncrement();
+            if (c + 1 < capacity)
+                notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue if it is
+     * possible to do so immediately without exceeding the queue's capacity,
+     * returning {@code true} upon success and {@code false} if this queue
+     * is full.
+     * When using a capacity-restricted queue, this method is generally
+     * preferable to method {@link BlockingQueue#add add}, which can fail to
+     * insert an element only by throwing an exception.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null) throw new NullPointerException();
+        final AtomicInteger count = this.count;
+        if (count.get() == capacity)
+            return false;
+        int c = -1;
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock putLock = this.putLock;
+        putLock.lock();
+        try {
+            if (count.get() < capacity) {
+                enqueue(node);
+                c = count.getAndIncrement();
+                if (c + 1 < capacity)
+                    notFull.signal();
+            }
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+        return c >= 0;
+    }
+
+    public E take() throws InterruptedException {
+        E x;
+        int c = -1;
+        final AtomicInteger count = this.count;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lockInterruptibly();
+        try {
+            while (count.get() == 0) {
+                notEmpty.await();
+            }
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        E x = null;
+        int c = -1;
+        long nanos = unit.toNanos(timeout);
+        final AtomicInteger count = this.count;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lockInterruptibly();
+        try {
+            while (count.get() == 0) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    public E poll() {
+        final AtomicInteger count = this.count;
+        if (count.get() == 0)
+            return null;
+        E x = null;
+        int c = -1;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            if (count.get() > 0) {
+                x = dequeue();
+                c = count.getAndDecrement();
+                if (c > 1)
+                    notEmpty.signal();
+            }
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    public E peek() {
+        if (count.get() == 0)
+            return null;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            return (count.get() > 0) ? head.next.item : null;
+        } finally {
+            takeLock.unlock();
+        }
+    }
+
+    /**
+     * Unlinks interior Node p with predecessor trail.
+     */
+    void unlink(Node<E> p, Node<E> trail) {
+        // assert isFullyLocked();
+        // p.next is not changed, to allow iterators that are
+        // traversing p to maintain their weak-consistency guarantee.
+        p.item = null;
+        trail.next = p.next;
+        if (last == p)
+            last = trail;
+        if (count.getAndDecrement() == capacity)
+            notFull.signal();
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.
+     * Returns {@code true} if this queue contained the specified element
+     * (or equivalently, if this queue changed as a result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        if (o == null) return false;
+        fullyLock();
+        try {
+            for (Node<E> trail = head, p = trail.next;
+                 p != null;
+                 trail = p, p = p.next) {
+                if (o.equals(p.item)) {
+                    unlink(p, trail);
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o == null) return false;
+        fullyLock();
+        try {
+            for (Node<E> p = head.next; p != null; p = p.next)
+                if (o.equals(p.item))
+                    return true;
+            return false;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        fullyLock();
+        try {
+            int size = count.get();
+            Object[] a = new Object[size];
+            int k = 0;
+            for (Node<E> p = head.next; p != null; p = p.next)
+                a[k++] = p.item;
+            return a;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        fullyLock();
+        try {
+            int size = count.get();
+            if (a.length < size)
+                a = (T[])java.lang.reflect.Array.newInstance
+                    (a.getClass().getComponentType(), size);
+
+            int k = 0;
+            for (Node<E> p = head.next; p != null; p = p.next)
+                a[k++] = (T)p.item;
+            if (a.length > k)
+                a[k] = null;
+            return a;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * Atomically removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        fullyLock();
+        try {
+            for (Node<E> p, h = head; (p = h.next) != null; h = p) {
+                h.next = h;
+                p.item = null;
+            }
+            head = last;
+            // assert head.item == null && head.next == null;
+            if (count.getAndSet(0) == capacity)
+                notFull.signal();
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        boolean signalNotFull = false;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            int n = Math.min(maxElements, count.get());
+            // count.get provides visibility to first n Nodes
+            Node<E> h = head;
+            int i = 0;
+            try {
+                while (i < n) {
+                    Node<E> p = h.next;
+                    c.add(p.item);
+                    p.item = null;
+                    h.next = h;
+                    h = p;
+                    ++i;
+                }
+                return n;
+            } finally {
+                // Restore invariants even if c.add() threw
+                if (i > 0) {
+                    // assert h.item == null;
+                    head = h;
+                    signalNotFull = (count.getAndAdd(-i) == capacity);
+                }
+            }
+        } finally {
+            takeLock.unlock();
+            if (signalNotFull)
+                signalNotFull();
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    private class Itr implements Iterator<E> {
+        /*
+         * Basic weakly-consistent iterator.  At all times hold the next
+         * item to hand out so that if hasNext() reports true, we will
+         * still have it to return even if lost race with a take etc.
+         */
+
+        private Node<E> current;
+        private Node<E> lastRet;
+        private E currentElement;
+
+        Itr() {
+            fullyLock();
+            try {
+                current = head.next;
+                if (current != null)
+                    currentElement = current.item;
+            } finally {
+                fullyUnlock();
+            }
+        }
+
+        public boolean hasNext() {
+            return current != null;
+        }
+
+        public E next() {
+            fullyLock();
+            try {
+                if (current == null)
+                    throw new NoSuchElementException();
+                lastRet = current;
+                E item = null;
+                // Unlike other traversal methods, iterators must handle both:
+                // - dequeued nodes (p.next == p)
+                // - (possibly multiple) interior removed nodes (p.item == null)
+                for (Node<E> p = current, q;; p = q) {
+                    if ((q = p.next) == p)
+                        q = head.next;
+                    if (q == null || (item = q.item) != null) {
+                        current = q;
+                        E x = currentElement;
+                        currentElement = item;
+                        return x;
+                    }
+                }
+            } finally {
+                fullyUnlock();
+            }
+        }
+
+        public void remove() {
+            if (lastRet == null)
+                throw new IllegalStateException();
+            fullyLock();
+            try {
+                Node<E> node = lastRet;
+                lastRet = null;
+                for (Node<E> trail = head, p = trail.next;
+                     p != null;
+                     trail = p, p = p.next) {
+                    if (p == node) {
+                        unlink(p, trail);
+                        break;
+                    }
+                }
+            } finally {
+                fullyUnlock();
+            }
+        }
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class LBQSpliterator<E> implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final LinkedBlockingQueue<E> queue;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        long est;           // size estimate
+        LBQSpliterator(LinkedBlockingQueue<E> queue) {
+            this.queue = queue;
+            this.est = queue.size();
+        }
+
+        public long estimateSize() { return est; }
+
+        public Spliterator<E> trySplit() {
+            Node<E> h;
+            final LinkedBlockingQueue<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((h = current) != null || (h = q.head.next) != null) &&
+                h.next != null) {
+                Object[] a = new Object[n];
+                int i = 0;
+                Node<E> p = current;
+                q.fullyLock();
+                try {
+                    if (p != null || (p = q.head.next) != null) {
+                        do {
+                            if ((a[i] = p.item) != null)
+                                ++i;
+                        } while ((p = p.next) != null && i < n);
+                    }
+                } finally {
+                    q.fullyUnlock();
+                }
+                if ((current = p) == null) {
+                    est = 0L;
+                    exhausted = true;
+                }
+                else if ((est -= i) < 0L)
+                    est = 0L;
+                if (i > 0) {
+                    batch = i;
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingQueue<E> q = this.queue;
+            if (!exhausted) {
+                exhausted = true;
+                Node<E> p = current;
+                do {
+                    E e = null;
+                    q.fullyLock();
+                    try {
+                        if (p == null)
+                            p = q.head.next;
+                        while (p != null) {
+                            e = p.item;
+                            p = p.next;
+                            if (e != null)
+                                break;
+                        }
+                    } finally {
+                        q.fullyUnlock();
+                    }
+                    if (e != null)
+                        action.accept(e);
+                } while (p != null);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingQueue<E> q = this.queue;
+            if (!exhausted) {
+                E e = null;
+                q.fullyLock();
+                try {
+                    if (current == null)
+                        current = q.head.next;
+                    while (current != null) {
+                        e = current.item;
+                        current = current.next;
+                        if (e != null)
+                            break;
+                    }
+                } finally {
+                    q.fullyUnlock();
+                }
+                if (current == null)
+                    exhausted = true;
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new LBQSpliterator<E>(this);
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The capacity is emitted (int), followed by all of
+     * its elements (each an {@code Object}) in the proper order,
+     * followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        fullyLock();
+        try {
+            // Write out any hidden stuff, plus capacity
+            s.defaultWriteObject();
+
+            // Write out all elements in the proper order.
+            for (Node<E> p = head.next; p != null; p = p.next)
+                s.writeObject(p.item);
+
+            // Use trailing null as sentinel
+            s.writeObject(null);
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in capacity, and any hidden stuff
+        s.defaultReadObject();
+
+        count.set(0);
+        last = head = new Node<E>(null);
+
+        // Read in all elements and place in queue
+        for (;;) {
+            @SuppressWarnings("unchecked")
+            E item = (E)s.readObject();
+            if (item == null)
+                break;
+            add(item);
+        }
+    }
+}
diff --git a/java/util/concurrent/LinkedTransferQueue.java b/java/util/concurrent/LinkedTransferQueue.java
new file mode 100644
index 0000000..e282b42
--- /dev/null
+++ b/java/util/concurrent/LinkedTransferQueue.java
@@ -0,0 +1,1587 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.LockSupport;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An unbounded {@link TransferQueue} based on linked nodes.
+ * This queue orders elements FIFO (first-in-first-out) with respect
+ * to any given producer.  The <em>head</em> of the queue is that
+ * element that has been on the queue the longest time for some
+ * producer.  The <em>tail</em> of the queue is that element that has
+ * been on the queue the shortest time for some producer.
+ *
+ * <p>Beware that, unlike in most collections, the {@code size} method
+ * is <em>NOT</em> a constant-time operation. Because of the
+ * asynchronous nature of these queues, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code LinkedTransferQueue}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code LinkedTransferQueue} in another thread.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class LinkedTransferQueue<E> extends AbstractQueue<E>
+    implements TransferQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = -3223113410248163686L;
+
+    /*
+     * *** Overview of Dual Queues with Slack ***
+     *
+     * Dual Queues, introduced by Scherer and Scott
+     * (http://www.cs.rice.edu/~wns1/papers/2004-DISC-DDS.pdf) are
+     * (linked) queues in which nodes may represent either data or
+     * requests.  When a thread tries to enqueue a data node, but
+     * encounters a request node, it instead "matches" and removes it;
+     * and vice versa for enqueuing requests. Blocking Dual Queues
+     * arrange that threads enqueuing unmatched requests block until
+     * other threads provide the match. Dual Synchronous Queues (see
+     * Scherer, Lea, & Scott
+     * http://www.cs.rochester.edu/u/scott/papers/2009_Scherer_CACM_SSQ.pdf)
+     * additionally arrange that threads enqueuing unmatched data also
+     * block.  Dual Transfer Queues support all of these modes, as
+     * dictated by callers.
+     *
+     * A FIFO dual queue may be implemented using a variation of the
+     * Michael & Scott (M&S) lock-free queue algorithm
+     * (http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf).
+     * It maintains two pointer fields, "head", pointing to a
+     * (matched) node that in turn points to the first actual
+     * (unmatched) queue node (or null if empty); and "tail" that
+     * points to the last node on the queue (or again null if
+     * empty). For example, here is a possible queue with four data
+     * elements:
+     *
+     *  head                tail
+     *    |                   |
+     *    v                   v
+     *    M -> U -> U -> U -> U
+     *
+     * The M&S queue algorithm is known to be prone to scalability and
+     * overhead limitations when maintaining (via CAS) these head and
+     * tail pointers. This has led to the development of
+     * contention-reducing variants such as elimination arrays (see
+     * Moir et al http://portal.acm.org/citation.cfm?id=1074013) and
+     * optimistic back pointers (see Ladan-Mozes & Shavit
+     * http://people.csail.mit.edu/edya/publications/OptimisticFIFOQueue-journal.pdf).
+     * However, the nature of dual queues enables a simpler tactic for
+     * improving M&S-style implementations when dual-ness is needed.
+     *
+     * In a dual queue, each node must atomically maintain its match
+     * status. While there are other possible variants, we implement
+     * this here as: for a data-mode node, matching entails CASing an
+     * "item" field from a non-null data value to null upon match, and
+     * vice-versa for request nodes, CASing from null to a data
+     * value. (Note that the linearization properties of this style of
+     * queue are easy to verify -- elements are made available by
+     * linking, and unavailable by matching.) Compared to plain M&S
+     * queues, this property of dual queues requires one additional
+     * successful atomic operation per enq/deq pair. But it also
+     * enables lower cost variants of queue maintenance mechanics. (A
+     * variation of this idea applies even for non-dual queues that
+     * support deletion of interior elements, such as
+     * j.u.c.ConcurrentLinkedQueue.)
+     *
+     * Once a node is matched, its match status can never again
+     * change.  We may thus arrange that the linked list of them
+     * contain a prefix of zero or more matched nodes, followed by a
+     * suffix of zero or more unmatched nodes. (Note that we allow
+     * both the prefix and suffix to be zero length, which in turn
+     * means that we do not use a dummy header.)  If we were not
+     * concerned with either time or space efficiency, we could
+     * correctly perform enqueue and dequeue operations by traversing
+     * from a pointer to the initial node; CASing the item of the
+     * first unmatched node on match and CASing the next field of the
+     * trailing node on appends. (Plus some special-casing when
+     * initially empty).  While this would be a terrible idea in
+     * itself, it does have the benefit of not requiring ANY atomic
+     * updates on head/tail fields.
+     *
+     * We introduce here an approach that lies between the extremes of
+     * never versus always updating queue (head and tail) pointers.
+     * This offers a tradeoff between sometimes requiring extra
+     * traversal steps to locate the first and/or last unmatched
+     * nodes, versus the reduced overhead and contention of fewer
+     * updates to queue pointers. For example, a possible snapshot of
+     * a queue is:
+     *
+     *  head           tail
+     *    |              |
+     *    v              v
+     *    M -> M -> U -> U -> U -> U
+     *
+     * The best value for this "slack" (the targeted maximum distance
+     * between the value of "head" and the first unmatched node, and
+     * similarly for "tail") is an empirical matter. We have found
+     * that using very small constants in the range of 1-3 work best
+     * over a range of platforms. Larger values introduce increasing
+     * costs of cache misses and risks of long traversal chains, while
+     * smaller values increase CAS contention and overhead.
+     *
+     * Dual queues with slack differ from plain M&S dual queues by
+     * virtue of only sometimes updating head or tail pointers when
+     * matching, appending, or even traversing nodes; in order to
+     * maintain a targeted slack.  The idea of "sometimes" may be
+     * operationalized in several ways. The simplest is to use a
+     * per-operation counter incremented on each traversal step, and
+     * to try (via CAS) to update the associated queue pointer
+     * whenever the count exceeds a threshold. Another, that requires
+     * more overhead, is to use random number generators to update
+     * with a given probability per traversal step.
+     *
+     * In any strategy along these lines, because CASes updating
+     * fields may fail, the actual slack may exceed targeted
+     * slack. However, they may be retried at any time to maintain
+     * targets.  Even when using very small slack values, this
+     * approach works well for dual queues because it allows all
+     * operations up to the point of matching or appending an item
+     * (hence potentially allowing progress by another thread) to be
+     * read-only, thus not introducing any further contention. As
+     * described below, we implement this by performing slack
+     * maintenance retries only after these points.
+     *
+     * As an accompaniment to such techniques, traversal overhead can
+     * be further reduced without increasing contention of head
+     * pointer updates: Threads may sometimes shortcut the "next" link
+     * path from the current "head" node to be closer to the currently
+     * known first unmatched node, and similarly for tail. Again, this
+     * may be triggered with using thresholds or randomization.
+     *
+     * These ideas must be further extended to avoid unbounded amounts
+     * of costly-to-reclaim garbage caused by the sequential "next"
+     * links of nodes starting at old forgotten head nodes: As first
+     * described in detail by Boehm
+     * (http://portal.acm.org/citation.cfm?doid=503272.503282), if a GC
+     * delays noticing that any arbitrarily old node has become
+     * garbage, all newer dead nodes will also be unreclaimed.
+     * (Similar issues arise in non-GC environments.)  To cope with
+     * this in our implementation, upon CASing to advance the head
+     * pointer, we set the "next" link of the previous head to point
+     * only to itself; thus limiting the length of connected dead lists.
+     * (We also take similar care to wipe out possibly garbage
+     * retaining values held in other Node fields.)  However, doing so
+     * adds some further complexity to traversal: If any "next"
+     * pointer links to itself, it indicates that the current thread
+     * has lagged behind a head-update, and so the traversal must
+     * continue from the "head".  Traversals trying to find the
+     * current tail starting from "tail" may also encounter
+     * self-links, in which case they also continue at "head".
+     *
+     * It is tempting in slack-based scheme to not even use CAS for
+     * updates (similarly to Ladan-Mozes & Shavit). However, this
+     * cannot be done for head updates under the above link-forgetting
+     * mechanics because an update may leave head at a detached node.
+     * And while direct writes are possible for tail updates, they
+     * increase the risk of long retraversals, and hence long garbage
+     * chains, which can be much more costly than is worthwhile
+     * considering that the cost difference of performing a CAS vs
+     * write is smaller when they are not triggered on each operation
+     * (especially considering that writes and CASes equally require
+     * additional GC bookkeeping ("write barriers") that are sometimes
+     * more costly than the writes themselves because of contention).
+     *
+     * *** Overview of implementation ***
+     *
+     * We use a threshold-based approach to updates, with a slack
+     * threshold of two -- that is, we update head/tail when the
+     * current pointer appears to be two or more steps away from the
+     * first/last node. The slack value is hard-wired: a path greater
+     * than one is naturally implemented by checking equality of
+     * traversal pointers except when the list has only one element,
+     * in which case we keep slack threshold at one. Avoiding tracking
+     * explicit counts across method calls slightly simplifies an
+     * already-messy implementation. Using randomization would
+     * probably work better if there were a low-quality dirt-cheap
+     * per-thread one available, but even ThreadLocalRandom is too
+     * heavy for these purposes.
+     *
+     * With such a small slack threshold value, it is not worthwhile
+     * to augment this with path short-circuiting (i.e., unsplicing
+     * interior nodes) except in the case of cancellation/removal (see
+     * below).
+     *
+     * We allow both the head and tail fields to be null before any
+     * nodes are enqueued; initializing upon first append.  This
+     * simplifies some other logic, as well as providing more
+     * efficient explicit control paths instead of letting JVMs insert
+     * implicit NullPointerExceptions when they are null.  While not
+     * currently fully implemented, we also leave open the possibility
+     * of re-nulling these fields when empty (which is complicated to
+     * arrange, for little benefit.)
+     *
+     * All enqueue/dequeue operations are handled by the single method
+     * "xfer" with parameters indicating whether to act as some form
+     * of offer, put, poll, take, or transfer (each possibly with
+     * timeout). The relative complexity of using one monolithic
+     * method outweighs the code bulk and maintenance problems of
+     * using separate methods for each case.
+     *
+     * Operation consists of up to three phases. The first is
+     * implemented within method xfer, the second in tryAppend, and
+     * the third in method awaitMatch.
+     *
+     * 1. Try to match an existing node
+     *
+     *    Starting at head, skip already-matched nodes until finding
+     *    an unmatched node of opposite mode, if one exists, in which
+     *    case matching it and returning, also if necessary updating
+     *    head to one past the matched node (or the node itself if the
+     *    list has no other unmatched nodes). If the CAS misses, then
+     *    a loop retries advancing head by two steps until either
+     *    success or the slack is at most two. By requiring that each
+     *    attempt advances head by two (if applicable), we ensure that
+     *    the slack does not grow without bound. Traversals also check
+     *    if the initial head is now off-list, in which case they
+     *    start at the new head.
+     *
+     *    If no candidates are found and the call was untimed
+     *    poll/offer, (argument "how" is NOW) return.
+     *
+     * 2. Try to append a new node (method tryAppend)
+     *
+     *    Starting at current tail pointer, find the actual last node
+     *    and try to append a new node (or if head was null, establish
+     *    the first node). Nodes can be appended only if their
+     *    predecessors are either already matched or are of the same
+     *    mode. If we detect otherwise, then a new node with opposite
+     *    mode must have been appended during traversal, so we must
+     *    restart at phase 1. The traversal and update steps are
+     *    otherwise similar to phase 1: Retrying upon CAS misses and
+     *    checking for staleness.  In particular, if a self-link is
+     *    encountered, then we can safely jump to a node on the list
+     *    by continuing the traversal at current head.
+     *
+     *    On successful append, if the call was ASYNC, return.
+     *
+     * 3. Await match or cancellation (method awaitMatch)
+     *
+     *    Wait for another thread to match node; instead cancelling if
+     *    the current thread was interrupted or the wait timed out. On
+     *    multiprocessors, we use front-of-queue spinning: If a node
+     *    appears to be the first unmatched node in the queue, it
+     *    spins a bit before blocking. In either case, before blocking
+     *    it tries to unsplice any nodes between the current "head"
+     *    and the first unmatched node.
+     *
+     *    Front-of-queue spinning vastly improves performance of
+     *    heavily contended queues. And so long as it is relatively
+     *    brief and "quiet", spinning does not much impact performance
+     *    of less-contended queues.  During spins threads check their
+     *    interrupt status and generate a thread-local random number
+     *    to decide to occasionally perform a Thread.yield. While
+     *    yield has underdefined specs, we assume that it might help,
+     *    and will not hurt, in limiting impact of spinning on busy
+     *    systems.  We also use smaller (1/2) spins for nodes that are
+     *    not known to be front but whose predecessors have not
+     *    blocked -- these "chained" spins avoid artifacts of
+     *    front-of-queue rules which otherwise lead to alternating
+     *    nodes spinning vs blocking. Further, front threads that
+     *    represent phase changes (from data to request node or vice
+     *    versa) compared to their predecessors receive additional
+     *    chained spins, reflecting longer paths typically required to
+     *    unblock threads during phase changes.
+     *
+     *
+     * ** Unlinking removed interior nodes **
+     *
+     * In addition to minimizing garbage retention via self-linking
+     * described above, we also unlink removed interior nodes. These
+     * may arise due to timed out or interrupted waits, or calls to
+     * remove(x) or Iterator.remove.  Normally, given a node that was
+     * at one time known to be the predecessor of some node s that is
+     * to be removed, we can unsplice s by CASing the next field of
+     * its predecessor if it still points to s (otherwise s must
+     * already have been removed or is now offlist). But there are two
+     * situations in which we cannot guarantee to make node s
+     * unreachable in this way: (1) If s is the trailing node of list
+     * (i.e., with null next), then it is pinned as the target node
+     * for appends, so can only be removed later after other nodes are
+     * appended. (2) We cannot necessarily unlink s given a
+     * predecessor node that is matched (including the case of being
+     * cancelled): the predecessor may already be unspliced, in which
+     * case some previous reachable node may still point to s.
+     * (For further explanation see Herlihy & Shavit "The Art of
+     * Multiprocessor Programming" chapter 9).  Although, in both
+     * cases, we can rule out the need for further action if either s
+     * or its predecessor are (or can be made to be) at, or fall off
+     * from, the head of list.
+     *
+     * Without taking these into account, it would be possible for an
+     * unbounded number of supposedly removed nodes to remain
+     * reachable.  Situations leading to such buildup are uncommon but
+     * can occur in practice; for example when a series of short timed
+     * calls to poll repeatedly time out but never otherwise fall off
+     * the list because of an untimed call to take at the front of the
+     * queue.
+     *
+     * When these cases arise, rather than always retraversing the
+     * entire list to find an actual predecessor to unlink (which
+     * won't help for case (1) anyway), we record a conservative
+     * estimate of possible unsplice failures (in "sweepVotes").
+     * We trigger a full sweep when the estimate exceeds a threshold
+     * ("SWEEP_THRESHOLD") indicating the maximum number of estimated
+     * removal failures to tolerate before sweeping through, unlinking
+     * cancelled nodes that were not unlinked upon initial removal.
+     * We perform sweeps by the thread hitting threshold (rather than
+     * background threads or by spreading work to other threads)
+     * because in the main contexts in which removal occurs, the
+     * caller is already timed-out, cancelled, or performing a
+     * potentially O(n) operation (e.g. remove(x)), none of which are
+     * time-critical enough to warrant the overhead that alternatives
+     * would impose on other threads.
+     *
+     * Because the sweepVotes estimate is conservative, and because
+     * nodes become unlinked "naturally" as they fall off the head of
+     * the queue, and because we allow votes to accumulate even while
+     * sweeps are in progress, there are typically significantly fewer
+     * such nodes than estimated.  Choice of a threshold value
+     * balances the likelihood of wasted effort and contention, versus
+     * providing a worst-case bound on retention of interior nodes in
+     * quiescent queues. The value defined below was chosen
+     * empirically to balance these under various timeout scenarios.
+     *
+     * Note that we cannot self-link unlinked interior nodes during
+     * sweeps. However, the associated garbage chains terminate when
+     * some successor ultimately falls off the head of the list and is
+     * self-linked.
+     */
+
+    /** True if on multiprocessor */
+    private static final boolean MP =
+        Runtime.getRuntime().availableProcessors() > 1;
+
+    /**
+     * The number of times to spin (with randomly interspersed calls
+     * to Thread.yield) on multiprocessor before blocking when a node
+     * is apparently the first waiter in the queue.  See above for
+     * explanation. Must be a power of two. The value is empirically
+     * derived -- it works pretty well across a variety of processors,
+     * numbers of CPUs, and OSes.
+     */
+    private static final int FRONT_SPINS   = 1 << 7;
+
+    /**
+     * The number of times to spin before blocking when a node is
+     * preceded by another node that is apparently spinning.  Also
+     * serves as an increment to FRONT_SPINS on phase changes, and as
+     * base average frequency for yielding during spins. Must be a
+     * power of two.
+     */
+    private static final int CHAINED_SPINS = FRONT_SPINS >>> 1;
+
+    /**
+     * The maximum number of estimated removal failures (sweepVotes)
+     * to tolerate before sweeping through the queue unlinking
+     * cancelled nodes that were not unlinked upon initial
+     * removal. See above for explanation. The value must be at least
+     * two to avoid useless sweeps when removing trailing nodes.
+     */
+    static final int SWEEP_THRESHOLD = 32;
+
+    /**
+     * Queue nodes. Uses Object, not E, for items to allow forgetting
+     * them after use.  Relies heavily on Unsafe mechanics to minimize
+     * unnecessary ordering constraints: Writes that are intrinsically
+     * ordered wrt other accesses or CASes use simple relaxed forms.
+     */
+    static final class Node {
+        final boolean isData;   // false if this is a request node
+        volatile Object item;   // initially non-null if isData; CASed to match
+        volatile Node next;
+        volatile Thread waiter; // null until waiting
+
+        // CAS methods for fields
+        final boolean casNext(Node cmp, Node val) {
+            return U.compareAndSwapObject(this, NEXT, cmp, val);
+        }
+
+        final boolean casItem(Object cmp, Object val) {
+            // assert cmp == null || cmp.getClass() != Node.class;
+            return U.compareAndSwapObject(this, ITEM, cmp, val);
+        }
+
+        /**
+         * Constructs a new node.  Uses relaxed write because item can
+         * only be seen after publication via casNext.
+         */
+        Node(Object item, boolean isData) {
+            U.putObject(this, ITEM, item); // relaxed write
+            this.isData = isData;
+        }
+
+        /**
+         * Links node to itself to avoid garbage retention.  Called
+         * only after CASing head field, so uses relaxed write.
+         */
+        final void forgetNext() {
+            U.putObject(this, NEXT, this);
+        }
+
+        /**
+         * Sets item to self and waiter to null, to avoid garbage
+         * retention after matching or cancelling. Uses relaxed writes
+         * because order is already constrained in the only calling
+         * contexts: item is forgotten only after volatile/atomic
+         * mechanics that extract items.  Similarly, clearing waiter
+         * follows either CAS or return from park (if ever parked;
+         * else we don't care).
+         */
+        final void forgetContents() {
+            U.putObject(this, ITEM, this);
+            U.putObject(this, WAITER, null);
+        }
+
+        /**
+         * Returns true if this node has been matched, including the
+         * case of artificial matches due to cancellation.
+         */
+        final boolean isMatched() {
+            Object x = item;
+            return (x == this) || ((x == null) == isData);
+        }
+
+        /**
+         * Returns true if this is an unmatched request node.
+         */
+        final boolean isUnmatchedRequest() {
+            return !isData && item == null;
+        }
+
+        /**
+         * Returns true if a node with the given mode cannot be
+         * appended to this node because this node is unmatched and
+         * has opposite data mode.
+         */
+        final boolean cannotPrecede(boolean haveData) {
+            boolean d = isData;
+            Object x;
+            return d != haveData && (x = item) != this && (x != null) == d;
+        }
+
+        /**
+         * Tries to artificially match a data node -- used by remove.
+         */
+        final boolean tryMatchData() {
+            // assert isData;
+            Object x = item;
+            if (x != null && x != this && casItem(x, null)) {
+                LockSupport.unpark(waiter);
+                return true;
+            }
+            return false;
+        }
+
+        private static final long serialVersionUID = -3375979862319811754L;
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long ITEM;
+        private static final long NEXT;
+        private static final long WAITER;
+        static {
+            try {
+                ITEM = U.objectFieldOffset
+                    (Node.class.getDeclaredField("item"));
+                NEXT = U.objectFieldOffset
+                    (Node.class.getDeclaredField("next"));
+                WAITER = U.objectFieldOffset
+                    (Node.class.getDeclaredField("waiter"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /** head of the queue; null until first enqueue */
+    transient volatile Node head;
+
+    /** tail of the queue; null until first append */
+    private transient volatile Node tail;
+
+    /** The number of apparent failures to unsplice removed nodes */
+    private transient volatile int sweepVotes;
+
+    // CAS methods for fields
+    private boolean casTail(Node cmp, Node val) {
+        return U.compareAndSwapObject(this, TAIL, cmp, val);
+    }
+
+    private boolean casHead(Node cmp, Node val) {
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
+    }
+
+    private boolean casSweepVotes(int cmp, int val) {
+        return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
+    }
+
+    /*
+     * Possible values for "how" argument in xfer method.
+     */
+    private static final int NOW   = 0; // for untimed poll, tryTransfer
+    private static final int ASYNC = 1; // for offer, put, add
+    private static final int SYNC  = 2; // for transfer, take
+    private static final int TIMED = 3; // for timed poll, tryTransfer
+
+    /**
+     * Implements all queuing methods. See above for explanation.
+     *
+     * @param e the item or null for take
+     * @param haveData true if this is a put, else a take
+     * @param how NOW, ASYNC, SYNC, or TIMED
+     * @param nanos timeout in nanosecs, used only if mode is TIMED
+     * @return an item if matched, else e
+     * @throws NullPointerException if haveData mode but e is null
+     */
+    private E xfer(E e, boolean haveData, int how, long nanos) {
+        if (haveData && (e == null))
+            throw new NullPointerException();
+        Node s = null;                        // the node to append, if needed
+
+        retry:
+        for (;;) {                            // restart on append race
+
+            for (Node h = head, p = h; p != null;) { // find & match first node
+                boolean isData = p.isData;
+                Object item = p.item;
+                if (item != p && (item != null) == isData) { // unmatched
+                    if (isData == haveData)   // can't match
+                        break;
+                    if (p.casItem(item, e)) { // match
+                        for (Node q = p; q != h;) {
+                            Node n = q.next;  // update by 2 unless singleton
+                            if (head == h && casHead(h, n == null ? q : n)) {
+                                h.forgetNext();
+                                break;
+                            }                 // advance and retry
+                            if ((h = head)   == null ||
+                                (q = h.next) == null || !q.isMatched())
+                                break;        // unless slack < 2
+                        }
+                        LockSupport.unpark(p.waiter);
+                        @SuppressWarnings("unchecked") E itemE = (E) item;
+                        return itemE;
+                    }
+                }
+                Node n = p.next;
+                p = (p != n) ? n : (h = head); // Use head if p offlist
+            }
+
+            if (how != NOW) {                 // No matches available
+                if (s == null)
+                    s = new Node(e, haveData);
+                Node pred = tryAppend(s, haveData);
+                if (pred == null)
+                    continue retry;           // lost race vs opposite mode
+                if (how != ASYNC)
+                    return awaitMatch(s, pred, e, (how == TIMED), nanos);
+            }
+            return e; // not waiting
+        }
+    }
+
+    /**
+     * Tries to append node s as tail.
+     *
+     * @param s the node to append
+     * @param haveData true if appending in data mode
+     * @return null on failure due to losing race with append in
+     * different mode, else s's predecessor, or s itself if no
+     * predecessor
+     */
+    private Node tryAppend(Node s, boolean haveData) {
+        for (Node t = tail, p = t;;) {        // move p to last node and append
+            Node n, u;                        // temps for reads of next & tail
+            if (p == null && (p = head) == null) {
+                if (casHead(null, s))
+                    return s;                 // initialize
+            }
+            else if (p.cannotPrecede(haveData))
+                return null;                  // lost race vs opposite mode
+            else if ((n = p.next) != null)    // not last; keep traversing
+                p = p != t && t != (u = tail) ? (t = u) : // stale tail
+                    (p != n) ? n : null;      // restart if off list
+            else if (!p.casNext(null, s))
+                p = p.next;                   // re-read on CAS failure
+            else {
+                if (p != t) {                 // update if slack now >= 2
+                    while ((tail != t || !casTail(t, s)) &&
+                           (t = tail)   != null &&
+                           (s = t.next) != null && // advance and retry
+                           (s = s.next) != null && s != t);
+                }
+                return p;
+            }
+        }
+    }
+
+    /**
+     * Spins/yields/blocks until node s is matched or caller gives up.
+     *
+     * @param s the waiting node
+     * @param pred the predecessor of s, or s itself if it has no
+     * predecessor, or null if unknown (the null case does not occur
+     * in any current calls but may in possible future extensions)
+     * @param e the comparison value for checking match
+     * @param timed if true, wait only until timeout elapses
+     * @param nanos timeout in nanosecs, used only if timed is true
+     * @return matched item, or e if unmatched on interrupt or timeout
+     */
+    private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) {
+        final long deadline = timed ? System.nanoTime() + nanos : 0L;
+        Thread w = Thread.currentThread();
+        int spins = -1; // initialized after first item and cancel checks
+        ThreadLocalRandom randomYields = null; // bound if needed
+
+        for (;;) {
+            Object item = s.item;
+            if (item != e) {                  // matched
+                // assert item != s;
+                s.forgetContents();           // avoid garbage
+                @SuppressWarnings("unchecked") E itemE = (E) item;
+                return itemE;
+            }
+            else if (w.isInterrupted() || (timed && nanos <= 0L)) {
+                unsplice(pred, s);           // try to unlink and cancel
+                if (s.casItem(e, s))         // return normally if lost CAS
+                    return e;
+            }
+            else if (spins < 0) {            // establish spins at/near front
+                if ((spins = spinsFor(pred, s.isData)) > 0)
+                    randomYields = ThreadLocalRandom.current();
+            }
+            else if (spins > 0) {             // spin
+                --spins;
+                if (randomYields.nextInt(CHAINED_SPINS) == 0)
+                    Thread.yield();           // occasionally yield
+            }
+            else if (s.waiter == null) {
+                s.waiter = w;                 // request unpark then recheck
+            }
+            else if (timed) {
+                nanos = deadline - System.nanoTime();
+                if (nanos > 0L)
+                    LockSupport.parkNanos(this, nanos);
+            }
+            else {
+                LockSupport.park(this);
+            }
+        }
+    }
+
+    /**
+     * Returns spin/yield value for a node with given predecessor and
+     * data mode. See above for explanation.
+     */
+    private static int spinsFor(Node pred, boolean haveData) {
+        if (MP && pred != null) {
+            if (pred.isData != haveData)      // phase change
+                return FRONT_SPINS + CHAINED_SPINS;
+            if (pred.isMatched())             // probably at front
+                return FRONT_SPINS;
+            if (pred.waiter == null)          // pred apparently spinning
+                return CHAINED_SPINS;
+        }
+        return 0;
+    }
+
+    /* -------------- Traversal methods -------------- */
+
+    /**
+     * Returns the successor of p, or the head node if p.next has been
+     * linked to self, which will only be true if traversing with a
+     * stale pointer that is now off the list.
+     */
+    final Node succ(Node p) {
+        Node next = p.next;
+        return (p == next) ? head : next;
+    }
+
+    /**
+     * Returns the first unmatched data node, or null if none.
+     * Callers must recheck if the returned node's item field is null
+     * or self-linked before using.
+     */
+    final Node firstDataNode() {
+        restartFromHead: for (;;) {
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p)
+                        return p;
+                }
+                else if (item == null)
+                    break;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Traverses and counts unmatched nodes of the given mode.
+     * Used by methods size and getWaitingConsumerCount.
+     */
+    private int countOfMode(boolean data) {
+        restartFromHead: for (;;) {
+            int count = 0;
+            for (Node p = head; p != null;) {
+                if (!p.isMatched()) {
+                    if (p.isData != data)
+                        return 0;
+                    if (++count == Integer.MAX_VALUE)
+                        break;  // @see Collection.size()
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return count;
+        }
+    }
+
+    public String toString() {
+        String[] a = null;
+        restartFromHead: for (;;) {
+            int charLength = 0;
+            int size = 0;
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p) {
+                        if (a == null)
+                            a = new String[4];
+                        else if (size == a.length)
+                            a = Arrays.copyOf(a, 2 * size);
+                        String s = item.toString();
+                        a[size++] = s;
+                        charLength += s.length();
+                    }
+                } else if (item == null)
+                    break;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+
+            if (size == 0)
+                return "[]";
+
+            return Helpers.toString(a, size, charLength);
+        }
+    }
+
+    private Object[] toArrayInternal(Object[] a) {
+        Object[] x = a;
+        restartFromHead: for (;;) {
+            int size = 0;
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p) {
+                        if (x == null)
+                            x = new Object[4];
+                        else if (size == x.length)
+                            x = Arrays.copyOf(x, 2 * (size + 4));
+                        x[size++] = item;
+                    }
+                } else if (item == null)
+                    break;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            if (x == null)
+                return new Object[0];
+            else if (a != null && size <= a.length) {
+                if (a != x)
+                    System.arraycopy(x, 0, a, 0, size);
+                if (size < a.length)
+                    a[size] = null;
+                return a;
+            }
+            return (size == x.length) ? x : Arrays.copyOf(x, size);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        return toArrayInternal(null);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a == null) throw new NullPointerException();
+        return (T[]) toArrayInternal(a);
+    }
+
+    final class Itr implements Iterator<E> {
+        private Node nextNode;   // next node to return item for
+        private E nextItem;      // the corresponding item
+        private Node lastRet;    // last returned node, to support remove
+        private Node lastPred;   // predecessor to unlink lastRet
+
+        /**
+         * Moves to next node after prev, or first node if prev null.
+         */
+        private void advance(Node prev) {
+            /*
+             * To track and avoid buildup of deleted nodes in the face
+             * of calls to both Queue.remove and Itr.remove, we must
+             * include variants of unsplice and sweep upon each
+             * advance: Upon Itr.remove, we may need to catch up links
+             * from lastPred, and upon other removes, we might need to
+             * skip ahead from stale nodes and unsplice deleted ones
+             * found while advancing.
+             */
+
+            Node r, b; // reset lastPred upon possible deletion of lastRet
+            if ((r = lastRet) != null && !r.isMatched())
+                lastPred = r;    // next lastPred is old lastRet
+            else if ((b = lastPred) == null || b.isMatched())
+                lastPred = null; // at start of list
+            else {
+                Node s, n;       // help with removal of lastPred.next
+                while ((s = b.next) != null &&
+                       s != b && s.isMatched() &&
+                       (n = s.next) != null && n != s)
+                    b.casNext(s, n);
+            }
+
+            this.lastRet = prev;
+
+            for (Node p = prev, s, n;;) {
+                s = (p == null) ? head : p.next;
+                if (s == null)
+                    break;
+                else if (s == p) {
+                    p = null;
+                    continue;
+                }
+                Object item = s.item;
+                if (s.isData) {
+                    if (item != null && item != s) {
+                        @SuppressWarnings("unchecked") E itemE = (E) item;
+                        nextItem = itemE;
+                        nextNode = s;
+                        return;
+                    }
+                }
+                else if (item == null)
+                    break;
+                // assert s.isMatched();
+                if (p == null)
+                    p = s;
+                else if ((n = s.next) == null)
+                    break;
+                else if (s == n)
+                    p = null;
+                else
+                    p.casNext(s, n);
+            }
+            nextNode = null;
+            nextItem = null;
+        }
+
+        Itr() {
+            advance(null);
+        }
+
+        public final boolean hasNext() {
+            return nextNode != null;
+        }
+
+        public final E next() {
+            Node p = nextNode;
+            if (p == null) throw new NoSuchElementException();
+            E e = nextItem;
+            advance(p);
+            return e;
+        }
+
+        public final void remove() {
+            final Node lastRet = this.lastRet;
+            if (lastRet == null)
+                throw new IllegalStateException();
+            this.lastRet = null;
+            if (lastRet.tryMatchData())
+                unsplice(lastPred, lastRet);
+        }
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    final class LTQSpliterator<E> implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        Node current;       // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        LTQSpliterator() {}
+
+        public Spliterator<E> trySplit() {
+            Node p;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((p = current) != null || (p = firstDataNode()) != null) &&
+                p.next != null) {
+                Object[] a = new Object[n];
+                int i = 0;
+                do {
+                    Object e = p.item;
+                    if (e != p && (a[i] = e) != null)
+                        ++i;
+                    if (p == (p = p.next))
+                        p = firstDataNode();
+                } while (p != null && i < n && p.isData);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (i > 0) {
+                    batch = i;
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
+                }
+            }
+            return null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            Node p;
+            if (action == null) throw new NullPointerException();
+            if (!exhausted &&
+                ((p = current) != null || (p = firstDataNode()) != null)) {
+                exhausted = true;
+                do {
+                    Object e = p.item;
+                    if (e != null && e != p)
+                        action.accept((E)e);
+                    if (p == (p = p.next))
+                        p = firstDataNode();
+                } while (p != null && p.isData);
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Node p;
+            if (action == null) throw new NullPointerException();
+            if (!exhausted &&
+                ((p = current) != null || (p = firstDataNode()) != null)) {
+                Object e;
+                do {
+                    if ((e = p.item) == p)
+                        e = null;
+                    if (p == (p = p.next))
+                        p = firstDataNode();
+                } while (e == null && p != null && p.isData);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (e != null) {
+                    action.accept((E)e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public long estimateSize() { return Long.MAX_VALUE; }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new LTQSpliterator<E>();
+    }
+
+    /* -------------- Removal methods -------------- */
+
+    /**
+     * Unsplices (now or later) the given deleted/cancelled node with
+     * the given predecessor.
+     *
+     * @param pred a node that was at one time known to be the
+     * predecessor of s, or null or s itself if s is/was at head
+     * @param s the node to be unspliced
+     */
+    final void unsplice(Node pred, Node s) {
+        s.waiter = null; // disable signals
+        /*
+         * See above for rationale. Briefly: if pred still points to
+         * s, try to unlink s.  If s cannot be unlinked, because it is
+         * trailing node or pred might be unlinked, and neither pred
+         * nor s are head or offlist, add to sweepVotes, and if enough
+         * votes have accumulated, sweep.
+         */
+        if (pred != null && pred != s && pred.next == s) {
+            Node n = s.next;
+            if (n == null ||
+                (n != s && pred.casNext(s, n) && pred.isMatched())) {
+                for (;;) {               // check if at, or could be, head
+                    Node h = head;
+                    if (h == pred || h == s || h == null)
+                        return;          // at head or list empty
+                    if (!h.isMatched())
+                        break;
+                    Node hn = h.next;
+                    if (hn == null)
+                        return;          // now empty
+                    if (hn != h && casHead(h, hn))
+                        h.forgetNext();  // advance head
+                }
+                if (pred.next != pred && s.next != s) { // recheck if offlist
+                    for (;;) {           // sweep now if enough votes
+                        int v = sweepVotes;
+                        if (v < SWEEP_THRESHOLD) {
+                            if (casSweepVotes(v, v + 1))
+                                break;
+                        }
+                        else if (casSweepVotes(v, 0)) {
+                            sweep();
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Unlinks matched (typically cancelled) nodes encountered in a
+     * traversal from head.
+     */
+    private void sweep() {
+        for (Node p = head, s, n; p != null && (s = p.next) != null; ) {
+            if (!s.isMatched())
+                // Unmatched nodes are never self-linked
+                p = s;
+            else if ((n = s.next) == null) // trailing node is pinned
+                break;
+            else if (s == n)    // stale
+                // No need to also check for p == s, since that implies s == n
+                p = head;
+            else
+                p.casNext(s, n);
+        }
+    }
+
+    /**
+     * Main implementation of remove(Object)
+     */
+    private boolean findAndRemove(Object e) {
+        if (e != null) {
+            for (Node pred = null, p = head; p != null; ) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p && e.equals(item) &&
+                        p.tryMatchData()) {
+                        unsplice(pred, p);
+                        return true;
+                    }
+                }
+                else if (item == null)
+                    break;
+                pred = p;
+                if ((p = p.next) == pred) { // stale
+                    pred = null;
+                    p = head;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Creates an initially empty {@code LinkedTransferQueue}.
+     */
+    public LinkedTransferQueue() {
+    }
+
+    /**
+     * Creates a {@code LinkedTransferQueue}
+     * initially containing the elements of the given collection,
+     * added in traversal order of the collection's iterator.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public LinkedTransferQueue(Collection<? extends E> c) {
+        this();
+        addAll(c);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never block.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void put(E e) {
+        xfer(e, true, ASYNC, 0);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never block or
+     * return {@code false}.
+     *
+     * @return {@code true} (as specified by
+     *  {@link java.util.concurrent.BlockingQueue#offer(Object,long,TimeUnit)
+     *  BlockingQueue.offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit) {
+        xfer(e, true, ASYNC, 0);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        xfer(e, true, ASYNC, 0);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never throw
+     * {@link IllegalStateException} or return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        xfer(e, true, ASYNC, 0);
+        return true;
+    }
+
+    /**
+     * Transfers the element to a waiting consumer immediately, if possible.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * otherwise returning {@code false} without enqueuing the element.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean tryTransfer(E e) {
+        return xfer(e, true, NOW, 0) == null;
+    }
+
+    /**
+     * Transfers the element to a consumer, waiting if necessary to do so.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else inserts the specified element at the tail of this queue
+     * and waits until the element is received by a consumer.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void transfer(E e) throws InterruptedException {
+        if (xfer(e, true, SYNC, 0) != null) {
+            Thread.interrupted(); // failure possible only due to interrupt
+            throw new InterruptedException();
+        }
+    }
+
+    /**
+     * Transfers the element to a consumer if it is possible to do so
+     * before the timeout elapses.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else inserts the specified element at the tail of this queue
+     * and waits until the element is received by a consumer,
+     * returning {@code false} if the specified wait time elapses
+     * before the element can be transferred.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean tryTransfer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (xfer(e, true, TIMED, unit.toNanos(timeout)) == null)
+            return true;
+        if (!Thread.interrupted())
+            return false;
+        throw new InterruptedException();
+    }
+
+    public E take() throws InterruptedException {
+        E e = xfer(null, false, SYNC, 0);
+        if (e != null)
+            return e;
+        Thread.interrupted();
+        throw new InterruptedException();
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        E e = xfer(null, false, TIMED, unit.toNanos(timeout));
+        if (e != null || !Thread.interrupted())
+            return e;
+        throw new InterruptedException();
+    }
+
+    public E poll() {
+        return xfer(null, false, NOW, 0);
+    }
+
+    /**
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; (e = poll()) != null;) {
+            c.add(e);
+            ++n;
+        }
+        return n;
+    }
+
+    /**
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; n < maxElements && (e = poll()) != null;) {
+            c.add(e);
+            ++n;
+        }
+        return n;
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    public E peek() {
+        restartFromHead: for (;;) {
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p) {
+                        @SuppressWarnings("unchecked") E e = (E) item;
+                        return e;
+                    }
+                }
+                else if (item == null)
+                    break;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains no elements.
+     *
+     * @return {@code true} if this queue contains no elements
+     */
+    public boolean isEmpty() {
+        return firstDataNode() == null;
+    }
+
+    public boolean hasWaitingConsumer() {
+        restartFromHead: for (;;) {
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p)
+                        break;
+                }
+                else if (item == null)
+                    return true;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Returns the number of elements in this queue.  If this queue
+     * contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these queues, determining the current
+     * number of elements requires an O(n) traversal.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        return countOfMode(true);
+    }
+
+    public int getWaitingConsumerCount() {
+        return countOfMode(false);
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.
+     * Returns {@code true} if this queue contained the specified element
+     * (or equivalently, if this queue changed as a result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        return findAndRemove(o);
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o != null) {
+            for (Node p = head; p != null; p = succ(p)) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p && o.equals(item))
+                        return true;
+                }
+                else if (item == null)
+                    break;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Always returns {@code Integer.MAX_VALUE} because a
+     * {@code LinkedTransferQueue} is not capacity constrained.
+     *
+     * @return {@code Integer.MAX_VALUE} (as specified by
+     *         {@link java.util.concurrent.BlockingQueue#remainingCapacity()
+     *         BlockingQueue.remainingCapacity})
+     */
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData All of the elements (each an {@code E}) in
+     * the proper order, followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        s.defaultWriteObject();
+        for (E e : this)
+            s.writeObject(e);
+        // Use trailing null as sentinel
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        for (;;) {
+            @SuppressWarnings("unchecked")
+            E item = (E) s.readObject();
+            if (item == null)
+                break;
+            else
+                offer(item);
+        }
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
+    private static final long TAIL;
+    private static final long SWEEPVOTES;
+    static {
+        try {
+            HEAD = U.objectFieldOffset
+                (LinkedTransferQueue.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (LinkedTransferQueue.class.getDeclaredField("tail"));
+            SWEEPVOTES = U.objectFieldOffset
+                (LinkedTransferQueue.class.getDeclaredField("sweepVotes"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/java/util/concurrent/Phaser.java b/java/util/concurrent/Phaser.java
new file mode 100644
index 0000000..9ef9936
--- /dev/null
+++ b/java/util/concurrent/Phaser.java
@@ -0,0 +1,1154 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.LockSupport;
+
+/**
+ * A reusable synchronization barrier, similar in functionality to
+ * {@link java.util.concurrent.CyclicBarrier CyclicBarrier} and
+ * {@link java.util.concurrent.CountDownLatch CountDownLatch}
+ * but supporting more flexible usage.
+ *
+ * <p><b>Registration.</b> Unlike the case for other barriers, the
+ * number of parties <em>registered</em> to synchronize on a phaser
+ * may vary over time.  Tasks may be registered at any time (using
+ * methods {@link #register}, {@link #bulkRegister}, or forms of
+ * constructors establishing initial numbers of parties), and
+ * optionally deregistered upon any arrival (using {@link
+ * #arriveAndDeregister}).  As is the case with most basic
+ * synchronization constructs, registration and deregistration affect
+ * only internal counts; they do not establish any further internal
+ * bookkeeping, so tasks cannot query whether they are registered.
+ * (However, you can introduce such bookkeeping by subclassing this
+ * class.)
+ *
+ * <p><b>Synchronization.</b> Like a {@code CyclicBarrier}, a {@code
+ * Phaser} may be repeatedly awaited.  Method {@link
+ * #arriveAndAwaitAdvance} has effect analogous to {@link
+ * java.util.concurrent.CyclicBarrier#await CyclicBarrier.await}. Each
+ * generation of a phaser has an associated phase number. The phase
+ * number starts at zero, and advances when all parties arrive at the
+ * phaser, wrapping around to zero after reaching {@code
+ * Integer.MAX_VALUE}. The use of phase numbers enables independent
+ * control of actions upon arrival at a phaser and upon awaiting
+ * others, via two kinds of methods that may be invoked by any
+ * registered party:
+ *
+ * <ul>
+ *
+ *   <li><b>Arrival.</b> Methods {@link #arrive} and
+ *       {@link #arriveAndDeregister} record arrival.  These methods
+ *       do not block, but return an associated <em>arrival phase
+ *       number</em>; that is, the phase number of the phaser to which
+ *       the arrival applied. When the final party for a given phase
+ *       arrives, an optional action is performed and the phase
+ *       advances.  These actions are performed by the party
+ *       triggering a phase advance, and are arranged by overriding
+ *       method {@link #onAdvance(int, int)}, which also controls
+ *       termination. Overriding this method is similar to, but more
+ *       flexible than, providing a barrier action to a {@code
+ *       CyclicBarrier}.
+ *
+ *   <li><b>Waiting.</b> Method {@link #awaitAdvance} requires an
+ *       argument indicating an arrival phase number, and returns when
+ *       the phaser advances to (or is already at) a different phase.
+ *       Unlike similar constructions using {@code CyclicBarrier},
+ *       method {@code awaitAdvance} continues to wait even if the
+ *       waiting thread is interrupted. Interruptible and timeout
+ *       versions are also available, but exceptions encountered while
+ *       tasks wait interruptibly or with timeout do not change the
+ *       state of the phaser. If necessary, you can perform any
+ *       associated recovery within handlers of those exceptions,
+ *       often after invoking {@code forceTermination}.  Phasers may
+ *       also be used by tasks executing in a {@link ForkJoinPool}.
+ *       Progress is ensured if the pool's parallelismLevel can
+ *       accommodate the maximum number of simultaneously blocked
+ *       parties.
+ *
+ * </ul>
+ *
+ * <p><b>Termination.</b> A phaser may enter a <em>termination</em>
+ * state, that may be checked using method {@link #isTerminated}. Upon
+ * termination, all synchronization methods immediately return without
+ * waiting for advance, as indicated by a negative return value.
+ * Similarly, attempts to register upon termination have no effect.
+ * Termination is triggered when an invocation of {@code onAdvance}
+ * returns {@code true}. The default implementation returns {@code
+ * true} if a deregistration has caused the number of registered
+ * parties to become zero.  As illustrated below, when phasers control
+ * actions with a fixed number of iterations, it is often convenient
+ * to override this method to cause termination when the current phase
+ * number reaches a threshold. Method {@link #forceTermination} is
+ * also available to abruptly release waiting threads and allow them
+ * to terminate.
+ *
+ * <p><b>Tiering.</b> Phasers may be <em>tiered</em> (i.e.,
+ * constructed in tree structures) to reduce contention. Phasers with
+ * large numbers of parties that would otherwise experience heavy
+ * synchronization contention costs may instead be set up so that
+ * groups of sub-phasers share a common parent.  This may greatly
+ * increase throughput even though it incurs greater per-operation
+ * overhead.
+ *
+ * <p>In a tree of tiered phasers, registration and deregistration of
+ * child phasers with their parent are managed automatically.
+ * Whenever the number of registered parties of a child phaser becomes
+ * non-zero (as established in the {@link #Phaser(Phaser,int)}
+ * constructor, {@link #register}, or {@link #bulkRegister}), the
+ * child phaser is registered with its parent.  Whenever the number of
+ * registered parties becomes zero as the result of an invocation of
+ * {@link #arriveAndDeregister}, the child phaser is deregistered
+ * from its parent.
+ *
+ * <p><b>Monitoring.</b> While synchronization methods may be invoked
+ * only by registered parties, the current state of a phaser may be
+ * monitored by any caller.  At any given moment there are {@link
+ * #getRegisteredParties} parties in total, of which {@link
+ * #getArrivedParties} have arrived at the current phase ({@link
+ * #getPhase}).  When the remaining ({@link #getUnarrivedParties})
+ * parties arrive, the phase advances.  The values returned by these
+ * methods may reflect transient states and so are not in general
+ * useful for synchronization control.  Method {@link #toString}
+ * returns snapshots of these state queries in a form convenient for
+ * informal monitoring.
+ *
+ * <p><b>Sample usages:</b>
+ *
+ * <p>A {@code Phaser} may be used instead of a {@code CountDownLatch}
+ * to control a one-shot action serving a variable number of parties.
+ * The typical idiom is for the method setting this up to first
+ * register, then start the actions, then deregister, as in:
+ *
+ * <pre> {@code
+ * void runTasks(List<Runnable> tasks) {
+ *   final Phaser phaser = new Phaser(1); // "1" to register self
+ *   // create and start threads
+ *   for (final Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread() {
+ *       public void run() {
+ *         phaser.arriveAndAwaitAdvance(); // await all creation
+ *         task.run();
+ *       }
+ *     }.start();
+ *   }
+ *
+ *   // allow threads to start and deregister self
+ *   phaser.arriveAndDeregister();
+ * }}</pre>
+ *
+ * <p>One way to cause a set of threads to repeatedly perform actions
+ * for a given number of iterations is to override {@code onAdvance}:
+ *
+ * <pre> {@code
+ * void startTasks(List<Runnable> tasks, final int iterations) {
+ *   final Phaser phaser = new Phaser() {
+ *     protected boolean onAdvance(int phase, int registeredParties) {
+ *       return phase >= iterations || registeredParties == 0;
+ *     }
+ *   };
+ *   phaser.register();
+ *   for (final Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread() {
+ *       public void run() {
+ *         do {
+ *           task.run();
+ *           phaser.arriveAndAwaitAdvance();
+ *         } while (!phaser.isTerminated());
+ *       }
+ *     }.start();
+ *   }
+ *   phaser.arriveAndDeregister(); // deregister self, don't wait
+ * }}</pre>
+ *
+ * If the main task must later await termination, it
+ * may re-register and then execute a similar loop:
+ * <pre> {@code
+ *   // ...
+ *   phaser.register();
+ *   while (!phaser.isTerminated())
+ *     phaser.arriveAndAwaitAdvance();}</pre>
+ *
+ * <p>Related constructions may be used to await particular phase numbers
+ * in contexts where you are sure that the phase will never wrap around
+ * {@code Integer.MAX_VALUE}. For example:
+ *
+ * <pre> {@code
+ * void awaitPhase(Phaser phaser, int phase) {
+ *   int p = phaser.register(); // assumes caller not already registered
+ *   while (p < phase) {
+ *     if (phaser.isTerminated())
+ *       // ... deal with unexpected termination
+ *     else
+ *       p = phaser.arriveAndAwaitAdvance();
+ *   }
+ *   phaser.arriveAndDeregister();
+ * }}</pre>
+ *
+ *
+ * <p>To create a set of {@code n} tasks using a tree of phasers, you
+ * could use code of the following form, assuming a Task class with a
+ * constructor accepting a {@code Phaser} that it registers with upon
+ * construction. After invocation of {@code build(new Task[n], 0, n,
+ * new Phaser())}, these tasks could then be started, for example by
+ * submitting to a pool:
+ *
+ * <pre> {@code
+ * void build(Task[] tasks, int lo, int hi, Phaser ph) {
+ *   if (hi - lo > TASKS_PER_PHASER) {
+ *     for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
+ *       int j = Math.min(i + TASKS_PER_PHASER, hi);
+ *       build(tasks, i, j, new Phaser(ph));
+ *     }
+ *   } else {
+ *     for (int i = lo; i < hi; ++i)
+ *       tasks[i] = new Task(ph);
+ *       // assumes new Task(ph) performs ph.register()
+ *   }
+ * }}</pre>
+ *
+ * The best value of {@code TASKS_PER_PHASER} depends mainly on
+ * expected synchronization rates. A value as low as four may
+ * be appropriate for extremely small per-phase task bodies (thus
+ * high rates), or up to hundreds for extremely large ones.
+ *
+ * <p><b>Implementation notes</b>: This implementation restricts the
+ * maximum number of parties to 65535. Attempts to register additional
+ * parties result in {@code IllegalStateException}. However, you can and
+ * should create tiered phasers to accommodate arbitrarily large sets
+ * of participants.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public class Phaser {
+    /*
+     * This class implements an extension of X10 "clocks".  Thanks to
+     * Vijay Saraswat for the idea, and to Vivek Sarkar for
+     * enhancements to extend functionality.
+     */
+
+    /**
+     * Primary state representation, holding four bit-fields:
+     *
+     * unarrived  -- the number of parties yet to hit barrier (bits  0-15)
+     * parties    -- the number of parties to wait            (bits 16-31)
+     * phase      -- the generation of the barrier            (bits 32-62)
+     * terminated -- set if barrier is terminated             (bit  63 / sign)
+     *
+     * Except that a phaser with no registered parties is
+     * distinguished by the otherwise illegal state of having zero
+     * parties and one unarrived parties (encoded as EMPTY below).
+     *
+     * To efficiently maintain atomicity, these values are packed into
+     * a single (atomic) long. Good performance relies on keeping
+     * state decoding and encoding simple, and keeping race windows
+     * short.
+     *
+     * All state updates are performed via CAS except initial
+     * registration of a sub-phaser (i.e., one with a non-null
+     * parent).  In this (relatively rare) case, we use built-in
+     * synchronization to lock while first registering with its
+     * parent.
+     *
+     * The phase of a subphaser is allowed to lag that of its
+     * ancestors until it is actually accessed -- see method
+     * reconcileState.
+     */
+    private volatile long state;
+
+    private static final int  MAX_PARTIES     = 0xffff;
+    private static final int  MAX_PHASE       = Integer.MAX_VALUE;
+    private static final int  PARTIES_SHIFT   = 16;
+    private static final int  PHASE_SHIFT     = 32;
+    private static final int  UNARRIVED_MASK  = 0xffff;      // to mask ints
+    private static final long PARTIES_MASK    = 0xffff0000L; // to mask longs
+    private static final long COUNTS_MASK     = 0xffffffffL;
+    private static final long TERMINATION_BIT = 1L << 63;
+
+    // some special values
+    private static final int  ONE_ARRIVAL     = 1;
+    private static final int  ONE_PARTY       = 1 << PARTIES_SHIFT;
+    private static final int  ONE_DEREGISTER  = ONE_ARRIVAL|ONE_PARTY;
+    private static final int  EMPTY           = 1;
+
+    // The following unpacking methods are usually manually inlined
+
+    private static int unarrivedOf(long s) {
+        int counts = (int)s;
+        return (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
+    }
+
+    private static int partiesOf(long s) {
+        return (int)s >>> PARTIES_SHIFT;
+    }
+
+    private static int phaseOf(long s) {
+        return (int)(s >>> PHASE_SHIFT);
+    }
+
+    private static int arrivedOf(long s) {
+        int counts = (int)s;
+        return (counts == EMPTY) ? 0 :
+            (counts >>> PARTIES_SHIFT) - (counts & UNARRIVED_MASK);
+    }
+
+    /**
+     * The parent of this phaser, or null if none.
+     */
+    private final Phaser parent;
+
+    /**
+     * The root of phaser tree. Equals this if not in a tree.
+     */
+    private final Phaser root;
+
+    /**
+     * Heads of Treiber stacks for waiting threads. To eliminate
+     * contention when releasing some threads while adding others, we
+     * use two of them, alternating across even and odd phases.
+     * Subphasers share queues with root to speed up releases.
+     */
+    private final AtomicReference<QNode> evenQ;
+    private final AtomicReference<QNode> oddQ;
+
+    private AtomicReference<QNode> queueFor(int phase) {
+        return ((phase & 1) == 0) ? evenQ : oddQ;
+    }
+
+    /**
+     * Returns message string for bounds exceptions on arrival.
+     */
+    private String badArrive(long s) {
+        return "Attempted arrival of unregistered party for " +
+            stateToString(s);
+    }
+
+    /**
+     * Returns message string for bounds exceptions on registration.
+     */
+    private String badRegister(long s) {
+        return "Attempt to register more than " +
+            MAX_PARTIES + " parties for " + stateToString(s);
+    }
+
+    /**
+     * Main implementation for methods arrive and arriveAndDeregister.
+     * Manually tuned to speed up and minimize race windows for the
+     * common case of just decrementing unarrived field.
+     *
+     * @param adjust value to subtract from state;
+     *               ONE_ARRIVAL for arrive,
+     *               ONE_DEREGISTER for arriveAndDeregister
+     */
+    private int doArrive(int adjust) {
+        final Phaser root = this.root;
+        for (;;) {
+            long s = (root == this) ? state : reconcileState();
+            int phase = (int)(s >>> PHASE_SHIFT);
+            if (phase < 0)
+                return phase;
+            int counts = (int)s;
+            int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
+            if (unarrived <= 0)
+                throw new IllegalStateException(badArrive(s));
+            if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
+                if (unarrived == 1) {
+                    long n = s & PARTIES_MASK;  // base of next state
+                    int nextUnarrived = (int)n >>> PARTIES_SHIFT;
+                    if (root == this) {
+                        if (onAdvance(phase, nextUnarrived))
+                            n |= TERMINATION_BIT;
+                        else if (nextUnarrived == 0)
+                            n |= EMPTY;
+                        else
+                            n |= nextUnarrived;
+                        int nextPhase = (phase + 1) & MAX_PHASE;
+                        n |= (long)nextPhase << PHASE_SHIFT;
+                        U.compareAndSwapLong(this, STATE, s, n);
+                        releaseWaiters(phase);
+                    }
+                    else if (nextUnarrived == 0) { // propagate deregistration
+                        phase = parent.doArrive(ONE_DEREGISTER);
+                        U.compareAndSwapLong(this, STATE, s, s | EMPTY);
+                    }
+                    else
+                        phase = parent.doArrive(ONE_ARRIVAL);
+                }
+                return phase;
+            }
+        }
+    }
+
+    /**
+     * Implementation of register, bulkRegister.
+     *
+     * @param registrations number to add to both parties and
+     * unarrived fields. Must be greater than zero.
+     */
+    private int doRegister(int registrations) {
+        // adjustment to state
+        long adjust = ((long)registrations << PARTIES_SHIFT) | registrations;
+        final Phaser parent = this.parent;
+        int phase;
+        for (;;) {
+            long s = (parent == null) ? state : reconcileState();
+            int counts = (int)s;
+            int parties = counts >>> PARTIES_SHIFT;
+            int unarrived = counts & UNARRIVED_MASK;
+            if (registrations > MAX_PARTIES - parties)
+                throw new IllegalStateException(badRegister(s));
+            phase = (int)(s >>> PHASE_SHIFT);
+            if (phase < 0)
+                break;
+            if (counts != EMPTY) {                  // not 1st registration
+                if (parent == null || reconcileState() == s) {
+                    if (unarrived == 0)             // wait out advance
+                        root.internalAwaitAdvance(phase, null);
+                    else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
+                        break;
+                }
+            }
+            else if (parent == null) {              // 1st root registration
+                long next = ((long)phase << PHASE_SHIFT) | adjust;
+                if (U.compareAndSwapLong(this, STATE, s, next))
+                    break;
+            }
+            else {
+                synchronized (this) {               // 1st sub registration
+                    if (state == s) {               // recheck under lock
+                        phase = parent.doRegister(1);
+                        if (phase < 0)
+                            break;
+                        // finish registration whenever parent registration
+                        // succeeded, even when racing with termination,
+                        // since these are part of the same "transaction".
+                        while (!U.compareAndSwapLong
+                               (this, STATE, s,
+                                ((long)phase << PHASE_SHIFT) | adjust)) {
+                            s = state;
+                            phase = (int)(root.state >>> PHASE_SHIFT);
+                            // assert (int)s == EMPTY;
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+        return phase;
+    }
+
+    /**
+     * Resolves lagged phase propagation from root if necessary.
+     * Reconciliation normally occurs when root has advanced but
+     * subphasers have not yet done so, in which case they must finish
+     * their own advance by setting unarrived to parties (or if
+     * parties is zero, resetting to unregistered EMPTY state).
+     *
+     * @return reconciled state
+     */
+    private long reconcileState() {
+        final Phaser root = this.root;
+        long s = state;
+        if (root != this) {
+            int phase, p;
+            // CAS to root phase with current parties, tripping unarrived
+            while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
+                   (int)(s >>> PHASE_SHIFT) &&
+                   !U.compareAndSwapLong
+                   (this, STATE, s,
+                    s = (((long)phase << PHASE_SHIFT) |
+                         ((phase < 0) ? (s & COUNTS_MASK) :
+                          (((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
+                           ((s & PARTIES_MASK) | p))))))
+                s = state;
+        }
+        return s;
+    }
+
+    /**
+     * Creates a new phaser with no initially registered parties, no
+     * parent, and initial phase number 0. Any thread using this
+     * phaser will need to first register for it.
+     */
+    public Phaser() {
+        this(null, 0);
+    }
+
+    /**
+     * Creates a new phaser with the given number of registered
+     * unarrived parties, no parent, and initial phase number 0.
+     *
+     * @param parties the number of parties required to advance to the
+     * next phase
+     * @throws IllegalArgumentException if parties less than zero
+     * or greater than the maximum number of parties supported
+     */
+    public Phaser(int parties) {
+        this(null, parties);
+    }
+
+    /**
+     * Equivalent to {@link #Phaser(Phaser, int) Phaser(parent, 0)}.
+     *
+     * @param parent the parent phaser
+     */
+    public Phaser(Phaser parent) {
+        this(parent, 0);
+    }
+
+    /**
+     * Creates a new phaser with the given parent and number of
+     * registered unarrived parties.  When the given parent is non-null
+     * and the given number of parties is greater than zero, this
+     * child phaser is registered with its parent.
+     *
+     * @param parent the parent phaser
+     * @param parties the number of parties required to advance to the
+     * next phase
+     * @throws IllegalArgumentException if parties less than zero
+     * or greater than the maximum number of parties supported
+     */
+    public Phaser(Phaser parent, int parties) {
+        if (parties >>> PARTIES_SHIFT != 0)
+            throw new IllegalArgumentException("Illegal number of parties");
+        int phase = 0;
+        this.parent = parent;
+        if (parent != null) {
+            final Phaser root = parent.root;
+            this.root = root;
+            this.evenQ = root.evenQ;
+            this.oddQ = root.oddQ;
+            if (parties != 0)
+                phase = parent.doRegister(1);
+        }
+        else {
+            this.root = this;
+            this.evenQ = new AtomicReference<QNode>();
+            this.oddQ = new AtomicReference<QNode>();
+        }
+        this.state = (parties == 0) ? (long)EMPTY :
+            ((long)phase << PHASE_SHIFT) |
+            ((long)parties << PARTIES_SHIFT) |
+            ((long)parties);
+    }
+
+    /**
+     * Adds a new unarrived party to this phaser.  If an ongoing
+     * invocation of {@link #onAdvance} is in progress, this method
+     * may await its completion before returning.  If this phaser has
+     * a parent, and this phaser previously had no registered parties,
+     * this child phaser is also registered with its parent. If
+     * this phaser is terminated, the attempt to register has
+     * no effect, and a negative value is returned.
+     *
+     * @return the arrival phase number to which this registration
+     * applied.  If this value is negative, then this phaser has
+     * terminated, in which case registration has no effect.
+     * @throws IllegalStateException if attempting to register more
+     * than the maximum supported number of parties
+     */
+    public int register() {
+        return doRegister(1);
+    }
+
+    /**
+     * Adds the given number of new unarrived parties to this phaser.
+     * If an ongoing invocation of {@link #onAdvance} is in progress,
+     * this method may await its completion before returning.  If this
+     * phaser has a parent, and the given number of parties is greater
+     * than zero, and this phaser previously had no registered
+     * parties, this child phaser is also registered with its parent.
+     * If this phaser is terminated, the attempt to register has no
+     * effect, and a negative value is returned.
+     *
+     * @param parties the number of additional parties required to
+     * advance to the next phase
+     * @return the arrival phase number to which this registration
+     * applied.  If this value is negative, then this phaser has
+     * terminated, in which case registration has no effect.
+     * @throws IllegalStateException if attempting to register more
+     * than the maximum supported number of parties
+     * @throws IllegalArgumentException if {@code parties < 0}
+     */
+    public int bulkRegister(int parties) {
+        if (parties < 0)
+            throw new IllegalArgumentException();
+        if (parties == 0)
+            return getPhase();
+        return doRegister(parties);
+    }
+
+    /**
+     * Arrives at this phaser, without waiting for others to arrive.
+     *
+     * <p>It is a usage error for an unregistered party to invoke this
+     * method.  However, this error may result in an {@code
+     * IllegalStateException} only upon some subsequent operation on
+     * this phaser, if ever.
+     *
+     * @return the arrival phase number, or a negative value if terminated
+     * @throws IllegalStateException if not terminated and the number
+     * of unarrived parties would become negative
+     */
+    public int arrive() {
+        return doArrive(ONE_ARRIVAL);
+    }
+
+    /**
+     * Arrives at this phaser and deregisters from it without waiting
+     * for others to arrive. Deregistration reduces the number of
+     * parties required to advance in future phases.  If this phaser
+     * has a parent, and deregistration causes this phaser to have
+     * zero parties, this phaser is also deregistered from its parent.
+     *
+     * <p>It is a usage error for an unregistered party to invoke this
+     * method.  However, this error may result in an {@code
+     * IllegalStateException} only upon some subsequent operation on
+     * this phaser, if ever.
+     *
+     * @return the arrival phase number, or a negative value if terminated
+     * @throws IllegalStateException if not terminated and the number
+     * of registered or unarrived parties would become negative
+     */
+    public int arriveAndDeregister() {
+        return doArrive(ONE_DEREGISTER);
+    }
+
+    /**
+     * Arrives at this phaser and awaits others. Equivalent in effect
+     * to {@code awaitAdvance(arrive())}.  If you need to await with
+     * interruption or timeout, you can arrange this with an analogous
+     * construction using one of the other forms of the {@code
+     * awaitAdvance} method.  If instead you need to deregister upon
+     * arrival, use {@code awaitAdvance(arriveAndDeregister())}.
+     *
+     * <p>It is a usage error for an unregistered party to invoke this
+     * method.  However, this error may result in an {@code
+     * IllegalStateException} only upon some subsequent operation on
+     * this phaser, if ever.
+     *
+     * @return the arrival phase number, or the (negative)
+     * {@linkplain #getPhase() current phase} if terminated
+     * @throws IllegalStateException if not terminated and the number
+     * of unarrived parties would become negative
+     */
+    public int arriveAndAwaitAdvance() {
+        // Specialization of doArrive+awaitAdvance eliminating some reads/paths
+        final Phaser root = this.root;
+        for (;;) {
+            long s = (root == this) ? state : reconcileState();
+            int phase = (int)(s >>> PHASE_SHIFT);
+            if (phase < 0)
+                return phase;
+            int counts = (int)s;
+            int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
+            if (unarrived <= 0)
+                throw new IllegalStateException(badArrive(s));
+            if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
+                if (unarrived > 1)
+                    return root.internalAwaitAdvance(phase, null);
+                if (root != this)
+                    return parent.arriveAndAwaitAdvance();
+                long n = s & PARTIES_MASK;  // base of next state
+                int nextUnarrived = (int)n >>> PARTIES_SHIFT;
+                if (onAdvance(phase, nextUnarrived))
+                    n |= TERMINATION_BIT;
+                else if (nextUnarrived == 0)
+                    n |= EMPTY;
+                else
+                    n |= nextUnarrived;
+                int nextPhase = (phase + 1) & MAX_PHASE;
+                n |= (long)nextPhase << PHASE_SHIFT;
+                if (!U.compareAndSwapLong(this, STATE, s, n))
+                    return (int)(state >>> PHASE_SHIFT); // terminated
+                releaseWaiters(phase);
+                return nextPhase;
+            }
+        }
+    }
+
+    /**
+     * Awaits the phase of this phaser to advance from the given phase
+     * value, returning immediately if the current phase is not equal
+     * to the given phase value or this phaser is terminated.
+     *
+     * @param phase an arrival phase number, or negative value if
+     * terminated; this argument is normally the value returned by a
+     * previous call to {@code arrive} or {@code arriveAndDeregister}.
+     * @return the next arrival phase number, or the argument if it is
+     * negative, or the (negative) {@linkplain #getPhase() current phase}
+     * if terminated
+     */
+    public int awaitAdvance(int phase) {
+        final Phaser root = this.root;
+        long s = (root == this) ? state : reconcileState();
+        int p = (int)(s >>> PHASE_SHIFT);
+        if (phase < 0)
+            return phase;
+        if (p == phase)
+            return root.internalAwaitAdvance(phase, null);
+        return p;
+    }
+
+    /**
+     * Awaits the phase of this phaser to advance from the given phase
+     * value, throwing {@code InterruptedException} if interrupted
+     * while waiting, or returning immediately if the current phase is
+     * not equal to the given phase value or this phaser is
+     * terminated.
+     *
+     * @param phase an arrival phase number, or negative value if
+     * terminated; this argument is normally the value returned by a
+     * previous call to {@code arrive} or {@code arriveAndDeregister}.
+     * @return the next arrival phase number, or the argument if it is
+     * negative, or the (negative) {@linkplain #getPhase() current phase}
+     * if terminated
+     * @throws InterruptedException if thread interrupted while waiting
+     */
+    public int awaitAdvanceInterruptibly(int phase)
+        throws InterruptedException {
+        final Phaser root = this.root;
+        long s = (root == this) ? state : reconcileState();
+        int p = (int)(s >>> PHASE_SHIFT);
+        if (phase < 0)
+            return phase;
+        if (p == phase) {
+            QNode node = new QNode(this, phase, true, false, 0L);
+            p = root.internalAwaitAdvance(phase, node);
+            if (node.wasInterrupted)
+                throw new InterruptedException();
+        }
+        return p;
+    }
+
+    /**
+     * Awaits the phase of this phaser to advance from the given phase
+     * value or the given timeout to elapse, throwing {@code
+     * InterruptedException} if interrupted while waiting, or
+     * returning immediately if the current phase is not equal to the
+     * given phase value or this phaser is terminated.
+     *
+     * @param phase an arrival phase number, or negative value if
+     * terminated; this argument is normally the value returned by a
+     * previous call to {@code arrive} or {@code arriveAndDeregister}.
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the next arrival phase number, or the argument if it is
+     * negative, or the (negative) {@linkplain #getPhase() current phase}
+     * if terminated
+     * @throws InterruptedException if thread interrupted while waiting
+     * @throws TimeoutException if timed out while waiting
+     */
+    public int awaitAdvanceInterruptibly(int phase,
+                                         long timeout, TimeUnit unit)
+        throws InterruptedException, TimeoutException {
+        long nanos = unit.toNanos(timeout);
+        final Phaser root = this.root;
+        long s = (root == this) ? state : reconcileState();
+        int p = (int)(s >>> PHASE_SHIFT);
+        if (phase < 0)
+            return phase;
+        if (p == phase) {
+            QNode node = new QNode(this, phase, true, true, nanos);
+            p = root.internalAwaitAdvance(phase, node);
+            if (node.wasInterrupted)
+                throw new InterruptedException();
+            else if (p == phase)
+                throw new TimeoutException();
+        }
+        return p;
+    }
+
+    /**
+     * Forces this phaser to enter termination state.  Counts of
+     * registered parties are unaffected.  If this phaser is a member
+     * of a tiered set of phasers, then all of the phasers in the set
+     * are terminated.  If this phaser is already terminated, this
+     * method has no effect.  This method may be useful for
+     * coordinating recovery after one or more tasks encounter
+     * unexpected exceptions.
+     */
+    public void forceTermination() {
+        // Only need to change root state
+        final Phaser root = this.root;
+        long s;
+        while ((s = root.state) >= 0) {
+            if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
+                // signal all threads
+                releaseWaiters(0); // Waiters on evenQ
+                releaseWaiters(1); // Waiters on oddQ
+                return;
+            }
+        }
+    }
+
+    /**
+     * Returns the current phase number. The maximum phase number is
+     * {@code Integer.MAX_VALUE}, after which it restarts at
+     * zero. Upon termination, the phase number is negative,
+     * in which case the prevailing phase prior to termination
+     * may be obtained via {@code getPhase() + Integer.MIN_VALUE}.
+     *
+     * @return the phase number, or a negative value if terminated
+     */
+    public final int getPhase() {
+        return (int)(root.state >>> PHASE_SHIFT);
+    }
+
+    /**
+     * Returns the number of parties registered at this phaser.
+     *
+     * @return the number of parties
+     */
+    public int getRegisteredParties() {
+        return partiesOf(state);
+    }
+
+    /**
+     * Returns the number of registered parties that have arrived at
+     * the current phase of this phaser. If this phaser has terminated,
+     * the returned value is meaningless and arbitrary.
+     *
+     * @return the number of arrived parties
+     */
+    public int getArrivedParties() {
+        return arrivedOf(reconcileState());
+    }
+
+    /**
+     * Returns the number of registered parties that have not yet
+     * arrived at the current phase of this phaser. If this phaser has
+     * terminated, the returned value is meaningless and arbitrary.
+     *
+     * @return the number of unarrived parties
+     */
+    public int getUnarrivedParties() {
+        return unarrivedOf(reconcileState());
+    }
+
+    /**
+     * Returns the parent of this phaser, or {@code null} if none.
+     *
+     * @return the parent of this phaser, or {@code null} if none
+     */
+    public Phaser getParent() {
+        return parent;
+    }
+
+    /**
+     * Returns the root ancestor of this phaser, which is the same as
+     * this phaser if it has no parent.
+     *
+     * @return the root ancestor of this phaser
+     */
+    public Phaser getRoot() {
+        return root;
+    }
+
+    /**
+     * Returns {@code true} if this phaser has been terminated.
+     *
+     * @return {@code true} if this phaser has been terminated
+     */
+    public boolean isTerminated() {
+        return root.state < 0L;
+    }
+
+    /**
+     * Overridable method to perform an action upon impending phase
+     * advance, and to control termination. This method is invoked
+     * upon arrival of the party advancing this phaser (when all other
+     * waiting parties are dormant).  If this method returns {@code
+     * true}, this phaser will be set to a final termination state
+     * upon advance, and subsequent calls to {@link #isTerminated}
+     * will return true. Any (unchecked) Exception or Error thrown by
+     * an invocation of this method is propagated to the party
+     * attempting to advance this phaser, in which case no advance
+     * occurs.
+     *
+     * <p>The arguments to this method provide the state of the phaser
+     * prevailing for the current transition.  The effects of invoking
+     * arrival, registration, and waiting methods on this phaser from
+     * within {@code onAdvance} are unspecified and should not be
+     * relied on.
+     *
+     * <p>If this phaser is a member of a tiered set of phasers, then
+     * {@code onAdvance} is invoked only for its root phaser on each
+     * advance.
+     *
+     * <p>To support the most common use cases, the default
+     * implementation of this method returns {@code true} when the
+     * number of registered parties has become zero as the result of a
+     * party invoking {@code arriveAndDeregister}.  You can disable
+     * this behavior, thus enabling continuation upon future
+     * registrations, by overriding this method to always return
+     * {@code false}:
+     *
+     * <pre> {@code
+     * Phaser phaser = new Phaser() {
+     *   protected boolean onAdvance(int phase, int parties) { return false; }
+     * }}</pre>
+     *
+     * @param phase the current phase number on entry to this method,
+     * before this phaser is advanced
+     * @param registeredParties the current number of registered parties
+     * @return {@code true} if this phaser should terminate
+     */
+    protected boolean onAdvance(int phase, int registeredParties) {
+        return registeredParties == 0;
+    }
+
+    /**
+     * Returns a string identifying this phaser, as well as its
+     * state.  The state, in brackets, includes the String {@code
+     * "phase = "} followed by the phase number, {@code "parties = "}
+     * followed by the number of registered parties, and {@code
+     * "arrived = "} followed by the number of arrived parties.
+     *
+     * @return a string identifying this phaser, as well as its state
+     */
+    public String toString() {
+        return stateToString(reconcileState());
+    }
+
+    /**
+     * Implementation of toString and string-based error messages.
+     */
+    private String stateToString(long s) {
+        return super.toString() +
+            "[phase = " + phaseOf(s) +
+            " parties = " + partiesOf(s) +
+            " arrived = " + arrivedOf(s) + "]";
+    }
+
+    // Waiting mechanics
+
+    /**
+     * Removes and signals threads from queue for phase.
+     */
+    private void releaseWaiters(int phase) {
+        QNode q;   // first element of queue
+        Thread t;  // its thread
+        AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
+        while ((q = head.get()) != null &&
+               q.phase != (int)(root.state >>> PHASE_SHIFT)) {
+            if (head.compareAndSet(q, q.next) &&
+                (t = q.thread) != null) {
+                q.thread = null;
+                LockSupport.unpark(t);
+            }
+        }
+    }
+
+    /**
+     * Variant of releaseWaiters that additionally tries to remove any
+     * nodes no longer waiting for advance due to timeout or
+     * interrupt. Currently, nodes are removed only if they are at
+     * head of queue, which suffices to reduce memory footprint in
+     * most usages.
+     *
+     * @return current phase on exit
+     */
+    private int abortWait(int phase) {
+        AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
+        for (;;) {
+            Thread t;
+            QNode q = head.get();
+            int p = (int)(root.state >>> PHASE_SHIFT);
+            if (q == null || ((t = q.thread) != null && q.phase == p))
+                return p;
+            if (head.compareAndSet(q, q.next) && t != null) {
+                q.thread = null;
+                LockSupport.unpark(t);
+            }
+        }
+    }
+
+    /** The number of CPUs, for spin control */
+    private static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * The number of times to spin before blocking while waiting for
+     * advance, per arrival while waiting. On multiprocessors, fully
+     * blocking and waking up a large number of threads all at once is
+     * usually a very slow process, so we use rechargeable spins to
+     * avoid it when threads regularly arrive: When a thread in
+     * internalAwaitAdvance notices another arrival before blocking,
+     * and there appear to be enough CPUs available, it spins
+     * SPINS_PER_ARRIVAL more times before blocking. The value trades
+     * off good-citizenship vs big unnecessary slowdowns.
+     */
+    static final int SPINS_PER_ARRIVAL = (NCPU < 2) ? 1 : 1 << 8;
+
+    /**
+     * Possibly blocks and waits for phase to advance unless aborted.
+     * Call only on root phaser.
+     *
+     * @param phase current phase
+     * @param node if non-null, the wait node to track interrupt and timeout;
+     * if null, denotes noninterruptible wait
+     * @return current phase
+     */
+    private int internalAwaitAdvance(int phase, QNode node) {
+        // assert root == this;
+        releaseWaiters(phase-1);          // ensure old queue clean
+        boolean queued = false;           // true when node is enqueued
+        int lastUnarrived = 0;            // to increase spins upon change
+        int spins = SPINS_PER_ARRIVAL;
+        long s;
+        int p;
+        while ((p = (int)((s = state) >>> PHASE_SHIFT)) == phase) {
+            if (node == null) {           // spinning in noninterruptible mode
+                int unarrived = (int)s & UNARRIVED_MASK;
+                if (unarrived != lastUnarrived &&
+                    (lastUnarrived = unarrived) < NCPU)
+                    spins += SPINS_PER_ARRIVAL;
+                boolean interrupted = Thread.interrupted();
+                if (interrupted || --spins < 0) { // need node to record intr
+                    node = new QNode(this, phase, false, false, 0L);
+                    node.wasInterrupted = interrupted;
+                }
+            }
+            else if (node.isReleasable()) // done or aborted
+                break;
+            else if (!queued) {           // push onto queue
+                AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
+                QNode q = node.next = head.get();
+                if ((q == null || q.phase == phase) &&
+                    (int)(state >>> PHASE_SHIFT) == phase) // avoid stale enq
+                    queued = head.compareAndSet(q, node);
+            }
+            else {
+                try {
+                    ForkJoinPool.managedBlock(node);
+                } catch (InterruptedException cantHappen) {
+                    node.wasInterrupted = true;
+                }
+            }
+        }
+
+        if (node != null) {
+            if (node.thread != null)
+                node.thread = null;       // avoid need for unpark()
+            if (node.wasInterrupted && !node.interruptible)
+                Thread.currentThread().interrupt();
+            if (p == phase && (p = (int)(state >>> PHASE_SHIFT)) == phase)
+                return abortWait(phase); // possibly clean up on abort
+        }
+        releaseWaiters(phase);
+        return p;
+    }
+
+    /**
+     * Wait nodes for Treiber stack representing wait queue.
+     */
+    static final class QNode implements ForkJoinPool.ManagedBlocker {
+        final Phaser phaser;
+        final int phase;
+        final boolean interruptible;
+        final boolean timed;
+        boolean wasInterrupted;
+        long nanos;
+        final long deadline;
+        volatile Thread thread; // nulled to cancel wait
+        QNode next;
+
+        QNode(Phaser phaser, int phase, boolean interruptible,
+              boolean timed, long nanos) {
+            this.phaser = phaser;
+            this.phase = phase;
+            this.interruptible = interruptible;
+            this.nanos = nanos;
+            this.timed = timed;
+            this.deadline = timed ? System.nanoTime() + nanos : 0L;
+            thread = Thread.currentThread();
+        }
+
+        public boolean isReleasable() {
+            if (thread == null)
+                return true;
+            if (phaser.getPhase() != phase) {
+                thread = null;
+                return true;
+            }
+            if (Thread.interrupted())
+                wasInterrupted = true;
+            if (wasInterrupted && interruptible) {
+                thread = null;
+                return true;
+            }
+            if (timed &&
+                (nanos <= 0L || (nanos = deadline - System.nanoTime()) <= 0L)) {
+                thread = null;
+                return true;
+            }
+            return false;
+        }
+
+        public boolean block() {
+            while (!isReleasable()) {
+                if (timed)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    LockSupport.park(this);
+            }
+            return true;
+        }
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
+    static {
+        try {
+            STATE = U.objectFieldOffset
+                (Phaser.class.getDeclaredField("state"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/java/util/concurrent/PriorityBlockingQueue.java b/java/util/concurrent/PriorityBlockingQueue.java
new file mode 100644
index 0000000..644de86
--- /dev/null
+++ b/java/util/concurrent/PriorityBlockingQueue.java
@@ -0,0 +1,1023 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.PriorityQueue;
+import java.util.Queue;
+import java.util.SortedSet;
+import java.util.Spliterator;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An unbounded {@linkplain BlockingQueue blocking queue} that uses
+ * the same ordering rules as class {@link PriorityQueue} and supplies
+ * blocking retrieval operations.  While this queue is logically
+ * unbounded, attempted additions may fail due to resource exhaustion
+ * (causing {@code OutOfMemoryError}). This class does not permit
+ * {@code null} elements.  A priority queue relying on {@linkplain
+ * Comparable natural ordering} also does not permit insertion of
+ * non-comparable objects (doing so results in
+ * {@code ClassCastException}).
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.  The Iterator provided in method {@link
+ * #iterator()} is <em>not</em> guaranteed to traverse the elements of
+ * the PriorityBlockingQueue in any particular order. If you need
+ * ordered traversal, consider using
+ * {@code Arrays.sort(pq.toArray())}.  Also, method {@code drainTo}
+ * can be used to <em>remove</em> some or all elements in priority
+ * order and place them in another collection.
+ *
+ * <p>Operations on this class make no guarantees about the ordering
+ * of elements with equal priority. If you need to enforce an
+ * ordering, you can define custom classes or comparators that use a
+ * secondary key to break ties in primary priority values.  For
+ * example, here is a class that applies first-in-first-out
+ * tie-breaking to comparable elements. To use it, you would insert a
+ * {@code new FIFOEntry(anEntry)} instead of a plain entry object.
+ *
+ * <pre> {@code
+ * class FIFOEntry<E extends Comparable<? super E>>
+ *     implements Comparable<FIFOEntry<E>> {
+ *   static final AtomicLong seq = new AtomicLong(0);
+ *   final long seqNum;
+ *   final E entry;
+ *   public FIFOEntry(E entry) {
+ *     seqNum = seq.getAndIncrement();
+ *     this.entry = entry;
+ *   }
+ *   public E getEntry() { return entry; }
+ *   public int compareTo(FIFOEntry<E> other) {
+ *     int res = entry.compareTo(other.entry);
+ *     if (res == 0 && other.entry != this.entry)
+ *       res = (seqNum < other.seqNum ? -1 : 1);
+ *     return res;
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+@SuppressWarnings("unchecked")
+public class PriorityBlockingQueue<E> extends AbstractQueue<E>
+    implements BlockingQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = 5595510919245408276L;
+
+    /*
+     * The implementation uses an array-based binary heap, with public
+     * operations protected with a single lock. However, allocation
+     * during resizing uses a simple spinlock (used only while not
+     * holding main lock) in order to allow takes to operate
+     * concurrently with allocation.  This avoids repeated
+     * postponement of waiting consumers and consequent element
+     * build-up. The need to back away from lock during allocation
+     * makes it impossible to simply wrap delegated
+     * java.util.PriorityQueue operations within a lock, as was done
+     * in a previous version of this class. To maintain
+     * interoperability, a plain PriorityQueue is still used during
+     * serialization, which maintains compatibility at the expense of
+     * transiently doubling overhead.
+     */
+
+    /**
+     * Default array capacity.
+     */
+    private static final int DEFAULT_INITIAL_CAPACITY = 11;
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Priority queue represented as a balanced binary heap: the two
+     * children of queue[n] are queue[2*n+1] and queue[2*(n+1)].  The
+     * priority queue is ordered by comparator, or by the elements'
+     * natural ordering, if comparator is null: For each node n in the
+     * heap and each descendant d of n, n <= d.  The element with the
+     * lowest value is in queue[0], assuming the queue is nonempty.
+     */
+    private transient Object[] queue;
+
+    /**
+     * The number of elements in the priority queue.
+     */
+    private transient int size;
+
+    /**
+     * The comparator, or null if priority queue uses elements'
+     * natural ordering.
+     */
+    private transient Comparator<? super E> comparator;
+
+    /**
+     * Lock used for all public operations.
+     */
+    private final ReentrantLock lock;
+
+    /**
+     * Condition for blocking when empty.
+     */
+    private final Condition notEmpty;
+
+    /**
+     * Spinlock for allocation, acquired via CAS.
+     */
+    private transient volatile int allocationSpinLock;
+
+    /**
+     * A plain PriorityQueue used only for serialization,
+     * to maintain compatibility with previous versions
+     * of this class. Non-null only during serialization/deserialization.
+     */
+    private PriorityQueue<E> q;
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} with the default
+     * initial capacity (11) that orders its elements according to
+     * their {@linkplain Comparable natural ordering}.
+     */
+    public PriorityBlockingQueue() {
+        this(DEFAULT_INITIAL_CAPACITY, null);
+    }
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} with the specified
+     * initial capacity that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     *
+     * @param initialCapacity the initial capacity for this priority queue
+     * @throws IllegalArgumentException if {@code initialCapacity} is less
+     *         than 1
+     */
+    public PriorityBlockingQueue(int initialCapacity) {
+        this(initialCapacity, null);
+    }
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} with the specified initial
+     * capacity that orders its elements according to the specified
+     * comparator.
+     *
+     * @param initialCapacity the initial capacity for this priority queue
+     * @param  comparator the comparator that will be used to order this
+     *         priority queue.  If {@code null}, the {@linkplain Comparable
+     *         natural ordering} of the elements will be used.
+     * @throws IllegalArgumentException if {@code initialCapacity} is less
+     *         than 1
+     */
+    public PriorityBlockingQueue(int initialCapacity,
+                                 Comparator<? super E> comparator) {
+        if (initialCapacity < 1)
+            throw new IllegalArgumentException();
+        this.lock = new ReentrantLock();
+        this.notEmpty = lock.newCondition();
+        this.comparator = comparator;
+        this.queue = new Object[initialCapacity];
+    }
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} containing the elements
+     * in the specified collection.  If the specified collection is a
+     * {@link SortedSet} or a {@link PriorityQueue}, this
+     * priority queue will be ordered according to the same ordering.
+     * Otherwise, this priority queue will be ordered according to the
+     * {@linkplain Comparable natural ordering} of its elements.
+     *
+     * @param  c the collection whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of the specified collection
+     *         cannot be compared to one another according to the priority
+     *         queue's ordering
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public PriorityBlockingQueue(Collection<? extends E> c) {
+        this.lock = new ReentrantLock();
+        this.notEmpty = lock.newCondition();
+        boolean heapify = true; // true if not known to be in heap order
+        boolean screen = true;  // true if must screen for nulls
+        if (c instanceof SortedSet<?>) {
+            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
+            this.comparator = (Comparator<? super E>) ss.comparator();
+            heapify = false;
+        }
+        else if (c instanceof PriorityBlockingQueue<?>) {
+            PriorityBlockingQueue<? extends E> pq =
+                (PriorityBlockingQueue<? extends E>) c;
+            this.comparator = (Comparator<? super E>) pq.comparator();
+            screen = false;
+            if (pq.getClass() == PriorityBlockingQueue.class) // exact match
+                heapify = false;
+        }
+        Object[] a = c.toArray();
+        int n = a.length;
+        // If c.toArray incorrectly doesn't return Object[], copy it.
+        if (a.getClass() != Object[].class)
+            a = Arrays.copyOf(a, n, Object[].class);
+        if (screen && (n == 1 || this.comparator != null)) {
+            for (int i = 0; i < n; ++i)
+                if (a[i] == null)
+                    throw new NullPointerException();
+        }
+        this.queue = a;
+        this.size = n;
+        if (heapify)
+            heapify();
+    }
+
+    /**
+     * Tries to grow array to accommodate at least one more element
+     * (but normally expand by about 50%), giving up (allowing retry)
+     * on contention (which we expect to be rare). Call only while
+     * holding lock.
+     *
+     * @param array the heap array
+     * @param oldCap the length of the array
+     */
+    private void tryGrow(Object[] array, int oldCap) {
+        lock.unlock(); // must release and then re-acquire main lock
+        Object[] newArray = null;
+        if (allocationSpinLock == 0 &&
+            U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
+            try {
+                int newCap = oldCap + ((oldCap < 64) ?
+                                       (oldCap + 2) : // grow faster if small
+                                       (oldCap >> 1));
+                if (newCap - MAX_ARRAY_SIZE > 0) {    // possible overflow
+                    int minCap = oldCap + 1;
+                    if (minCap < 0 || minCap > MAX_ARRAY_SIZE)
+                        throw new OutOfMemoryError();
+                    newCap = MAX_ARRAY_SIZE;
+                }
+                if (newCap > oldCap && queue == array)
+                    newArray = new Object[newCap];
+            } finally {
+                allocationSpinLock = 0;
+            }
+        }
+        if (newArray == null) // back off if another thread is allocating
+            Thread.yield();
+        lock.lock();
+        if (newArray != null && queue == array) {
+            queue = newArray;
+            System.arraycopy(array, 0, newArray, 0, oldCap);
+        }
+    }
+
+    /**
+     * Mechanics for poll().  Call only while holding lock.
+     */
+    private E dequeue() {
+        int n = size - 1;
+        if (n < 0)
+            return null;
+        else {
+            Object[] array = queue;
+            E result = (E) array[0];
+            E x = (E) array[n];
+            array[n] = null;
+            Comparator<? super E> cmp = comparator;
+            if (cmp == null)
+                siftDownComparable(0, x, array, n);
+            else
+                siftDownUsingComparator(0, x, array, n, cmp);
+            size = n;
+            return result;
+        }
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * promoting x up the tree until it is greater than or equal to
+     * its parent, or is the root.
+     *
+     * To simplify and speed up coercions and comparisons. the
+     * Comparable and Comparator versions are separated into different
+     * methods that are otherwise identical. (Similarly for siftDown.)
+     * These methods are static, with heap state as arguments, to
+     * simplify use in light of possible comparator exceptions.
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     * @param array the heap array
+     */
+    private static <T> void siftUpComparable(int k, T x, Object[] array) {
+        Comparable<? super T> key = (Comparable<? super T>) x;
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = array[parent];
+            if (key.compareTo((T) e) >= 0)
+                break;
+            array[k] = e;
+            k = parent;
+        }
+        array[k] = key;
+    }
+
+    private static <T> void siftUpUsingComparator(int k, T x, Object[] array,
+                                       Comparator<? super T> cmp) {
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = array[parent];
+            if (cmp.compare(x, (T) e) >= 0)
+                break;
+            array[k] = e;
+            k = parent;
+        }
+        array[k] = x;
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * demoting x down the tree repeatedly until it is less than or
+     * equal to its children or is a leaf.
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     * @param array the heap array
+     * @param n heap size
+     */
+    private static <T> void siftDownComparable(int k, T x, Object[] array,
+                                               int n) {
+        if (n > 0) {
+            Comparable<? super T> key = (Comparable<? super T>)x;
+            int half = n >>> 1;           // loop while a non-leaf
+            while (k < half) {
+                int child = (k << 1) + 1; // assume left child is least
+                Object c = array[child];
+                int right = child + 1;
+                if (right < n &&
+                    ((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
+                    c = array[child = right];
+                if (key.compareTo((T) c) <= 0)
+                    break;
+                array[k] = c;
+                k = child;
+            }
+            array[k] = key;
+        }
+    }
+
+    private static <T> void siftDownUsingComparator(int k, T x, Object[] array,
+                                                    int n,
+                                                    Comparator<? super T> cmp) {
+        if (n > 0) {
+            int half = n >>> 1;
+            while (k < half) {
+                int child = (k << 1) + 1;
+                Object c = array[child];
+                int right = child + 1;
+                if (right < n && cmp.compare((T) c, (T) array[right]) > 0)
+                    c = array[child = right];
+                if (cmp.compare(x, (T) c) <= 0)
+                    break;
+                array[k] = c;
+                k = child;
+            }
+            array[k] = x;
+        }
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the entire tree,
+     * assuming nothing about the order of the elements prior to the call.
+     */
+    private void heapify() {
+        Object[] array = queue;
+        int n = size;
+        int half = (n >>> 1) - 1;
+        Comparator<? super E> cmp = comparator;
+        if (cmp == null) {
+            for (int i = half; i >= 0; i--)
+                siftDownComparable(i, (E) array[i], array, n);
+        }
+        else {
+            for (int i = half; i >= 0; i--)
+                siftDownUsingComparator(i, (E) array[i], array, n, cmp);
+        }
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws ClassCastException if the specified element cannot be compared
+     *         with elements currently in the priority queue according to the
+     *         priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     * As the queue is unbounded, this method will never return {@code false}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws ClassCastException if the specified element cannot be compared
+     *         with elements currently in the priority queue according to the
+     *         priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        int n, cap;
+        Object[] array;
+        while ((n = size) >= (cap = (array = queue).length))
+            tryGrow(array, cap);
+        try {
+            Comparator<? super E> cmp = comparator;
+            if (cmp == null)
+                siftUpComparable(n, e, array);
+            else
+                siftUpUsingComparator(n, e, array, cmp);
+            size = n + 1;
+            notEmpty.signal();
+        } finally {
+            lock.unlock();
+        }
+        return true;
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     * As the queue is unbounded, this method will never block.
+     *
+     * @param e the element to add
+     * @throws ClassCastException if the specified element cannot be compared
+     *         with elements currently in the priority queue according to the
+     *         priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public void put(E e) {
+        offer(e); // never need to block
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     * As the queue is unbounded, this method will never block or
+     * return {@code false}.
+     *
+     * @param e the element to add
+     * @param timeout This parameter is ignored as the method never blocks
+     * @param unit This parameter is ignored as the method never blocks
+     * @return {@code true} (as specified by
+     *  {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer})
+     * @throws ClassCastException if the specified element cannot be compared
+     *         with elements currently in the priority queue according to the
+     *         priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit) {
+        return offer(e); // never need to block
+    }
+
+    public E poll() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E take() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        E result;
+        try {
+            while ( (result = dequeue()) == null)
+                notEmpty.await();
+        } finally {
+            lock.unlock();
+        }
+        return result;
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        E result;
+        try {
+            while ( (result = dequeue()) == null && nanos > 0)
+                nanos = notEmpty.awaitNanos(nanos);
+        } finally {
+            lock.unlock();
+        }
+        return result;
+    }
+
+    public E peek() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (size == 0) ? null : (E) queue[0];
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns the comparator used to order the elements in this queue,
+     * or {@code null} if this queue uses the {@linkplain Comparable
+     * natural ordering} of its elements.
+     *
+     * @return the comparator used to order the elements in this queue,
+     *         or {@code null} if this queue uses the natural
+     *         ordering of its elements
+     */
+    public Comparator<? super E> comparator() {
+        return comparator;
+    }
+
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return size;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Always returns {@code Integer.MAX_VALUE} because
+     * a {@code PriorityBlockingQueue} is not capacity constrained.
+     * @return {@code Integer.MAX_VALUE} always
+     */
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE;
+    }
+
+    private int indexOf(Object o) {
+        if (o != null) {
+            Object[] array = queue;
+            int n = size;
+            for (int i = 0; i < n; i++)
+                if (o.equals(array[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Removes the ith element from queue.
+     */
+    private void removeAt(int i) {
+        Object[] array = queue;
+        int n = size - 1;
+        if (n == i) // removed last element
+            array[i] = null;
+        else {
+            E moved = (E) array[n];
+            array[n] = null;
+            Comparator<? super E> cmp = comparator;
+            if (cmp == null)
+                siftDownComparable(i, moved, array, n);
+            else
+                siftDownUsingComparator(i, moved, array, n, cmp);
+            if (array[i] == moved) {
+                if (cmp == null)
+                    siftUpComparable(i, moved, array);
+                else
+                    siftUpUsingComparator(i, moved, array, cmp);
+            }
+        }
+        size = n;
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.  Returns {@code true} if and only if this queue contained
+     * the specified element (or equivalently, if this queue changed as a
+     * result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int i = indexOf(o);
+            if (i == -1)
+                return false;
+            removeAt(i);
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Identity-based version for use in Itr.remove.
+     */
+    void removeEQ(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            Object[] array = queue;
+            for (int i = 0, n = size; i < n; i++) {
+                if (o == array[i]) {
+                    removeAt(i);
+                    break;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return indexOf(o) != -1;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = Math.min(size, maxElements);
+            for (int i = 0; i < n; i++) {
+                c.add((E) queue[0]); // In this order, in case add() throws.
+                dequeue();
+            }
+            return n;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Atomically removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            Object[] array = queue;
+            int n = size;
+            size = 0;
+            for (int i = 0; i < n; i++)
+                array[i] = null;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue.
+     * The returned array elements are in no particular order.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return Arrays.copyOf(queue, size);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue; the
+     * runtime type of the returned array is that of the specified array.
+     * The returned array elements are in no particular order.
+     * If the queue fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = size;
+            if (a.length < n)
+                // Make a new array of a's runtime type, but my contents:
+                return (T[]) Arrays.copyOf(queue, size, a.getClass());
+            System.arraycopy(queue, 0, a, 0, n);
+            if (a.length > n)
+                a[n] = null;
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue. The
+     * iterator does not return the elements in any particular order.
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue
+     */
+    public Iterator<E> iterator() {
+        return new Itr(toArray());
+    }
+
+    /**
+     * Snapshot iterator that works off copy of underlying q array.
+     */
+    final class Itr implements Iterator<E> {
+        final Object[] array; // Array of all elements
+        int cursor;           // index of next element to return
+        int lastRet;          // index of last element, or -1 if no such
+
+        Itr(Object[] array) {
+            lastRet = -1;
+            this.array = array;
+        }
+
+        public boolean hasNext() {
+            return cursor < array.length;
+        }
+
+        public E next() {
+            if (cursor >= array.length)
+                throw new NoSuchElementException();
+            lastRet = cursor;
+            return (E)array[cursor++];
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            removeEQ(array[lastRet]);
+            lastRet = -1;
+        }
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * For compatibility with previous version of this class, elements
+     * are first copied to a java.util.PriorityQueue, which is then
+     * serialized.
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        lock.lock();
+        try {
+            // avoid zero capacity argument
+            q = new PriorityQueue<E>(Math.max(size, 1), comparator);
+            q.addAll(this);
+            s.defaultWriteObject();
+        } finally {
+            q = null;
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        try {
+            s.defaultReadObject();
+            this.queue = new Object[q.size()];
+            comparator = q.comparator();
+            addAll(q);
+        } finally {
+            q = null;
+        }
+    }
+
+    // Similar to Collections.ArraySnapshotSpliterator but avoids
+    // commitment to toArray until needed
+    static final class PBQSpliterator<E> implements Spliterator<E> {
+        final PriorityBlockingQueue<E> queue;
+        Object[] array;
+        int index;
+        int fence;
+
+        PBQSpliterator(PriorityBlockingQueue<E> queue, Object[] array,
+                       int index, int fence) {
+            this.queue = queue;
+            this.array = array;
+            this.index = index;
+            this.fence = fence;
+        }
+
+        final int getFence() {
+            int hi;
+            if ((hi = fence) < 0)
+                hi = fence = (array = queue.toArray()).length;
+            return hi;
+        }
+
+        public PBQSpliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new PBQSpliterator<E>(queue, array, lo, index = mid);
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            Object[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array) == null)
+                fence = (a = queue.toArray()).length;
+            if ((hi = fence) <= a.length &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept((E)a[i]); } while (++i < hi);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (getFence() > index && index >= 0) {
+                @SuppressWarnings("unchecked") E e = (E) array[index++];
+                action.accept(e);
+                return true;
+            }
+            return false;
+        }
+
+        public long estimateSize() { return (long)(getFence() - index); }
+
+        public int characteristics() {
+            return Spliterator.NONNULL | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new PBQSpliterator<E>(this, null, 0, -1);
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long ALLOCATIONSPINLOCK;
+    static {
+        try {
+            ALLOCATIONSPINLOCK = U.objectFieldOffset
+                (PriorityBlockingQueue.class.getDeclaredField("allocationSpinLock"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/RecursiveAction.java b/java/util/concurrent/RecursiveAction.java
new file mode 100644
index 0000000..8ac71d2
--- /dev/null
+++ b/java/util/concurrent/RecursiveAction.java
@@ -0,0 +1,193 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A recursive resultless {@link ForkJoinTask}.  This class
+ * establishes conventions to parameterize resultless actions as
+ * {@code Void} {@code ForkJoinTask}s. Because {@code null} is the
+ * only valid value of type {@code Void}, methods such as {@code join}
+ * always return {@code null} upon completion.
+ *
+ * <p><b>Sample Usages.</b> Here is a simple but complete ForkJoin
+ * sort that sorts a given {@code long[]} array:
+ *
+ * <pre> {@code
+ * static class SortTask extends RecursiveAction {
+ *   final long[] array; final int lo, hi;
+ *   SortTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   SortTask(long[] array) { this(array, 0, array.length); }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD)
+ *       sortSequentially(lo, hi);
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new SortTask(array, lo, mid),
+ *                 new SortTask(array, mid, hi));
+ *       merge(lo, mid, hi);
+ *     }
+ *   }
+ *   // implementation details follow:
+ *   static final int THRESHOLD = 1000;
+ *   void sortSequentially(int lo, int hi) {
+ *     Arrays.sort(array, lo, hi);
+ *   }
+ *   void merge(int lo, int mid, int hi) {
+ *     long[] buf = Arrays.copyOfRange(array, lo, mid);
+ *     for (int i = 0, j = lo, k = mid; i < buf.length; j++)
+ *       array[j] = (k == hi || buf[i] < array[k]) ?
+ *         buf[i++] : array[k++];
+ *   }
+ * }}</pre>
+ *
+ * You could then sort {@code anArray} by creating {@code new
+ * SortTask(anArray)} and invoking it in a ForkJoinPool.  As a more
+ * concrete simple example, the following task increments each element
+ * of an array:
+ * <pre> {@code
+ * class IncrementTask extends RecursiveAction {
+ *   final long[] array; final int lo, hi;
+ *   IncrementTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD) {
+ *       for (int i = lo; i < hi; ++i)
+ *         array[i]++;
+ *     }
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new IncrementTask(array, lo, mid),
+ *                 new IncrementTask(array, mid, hi));
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>The following example illustrates some refinements and idioms
+ * that may lead to better performance: RecursiveActions need not be
+ * fully recursive, so long as they maintain the basic
+ * divide-and-conquer approach. Here is a class that sums the squares
+ * of each element of a double array, by subdividing out only the
+ * right-hand-sides of repeated divisions by two, and keeping track of
+ * them with a chain of {@code next} references. It uses a dynamic
+ * threshold based on method {@code getSurplusQueuedTaskCount}, but
+ * counterbalances potential excess partitioning by directly
+ * performing leaf actions on unstolen tasks rather than further
+ * subdividing.
+ *
+ * <pre> {@code
+ * double sumOfSquares(ForkJoinPool pool, double[] array) {
+ *   int n = array.length;
+ *   Applyer a = new Applyer(array, 0, n, null);
+ *   pool.invoke(a);
+ *   return a.result;
+ * }
+ *
+ * class Applyer extends RecursiveAction {
+ *   final double[] array;
+ *   final int lo, hi;
+ *   double result;
+ *   Applyer next; // keeps track of right-hand-side tasks
+ *   Applyer(double[] array, int lo, int hi, Applyer next) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *     this.next = next;
+ *   }
+ *
+ *   double atLeaf(int l, int h) {
+ *     double sum = 0;
+ *     for (int i = l; i < h; ++i) // perform leftmost base step
+ *       sum += array[i] * array[i];
+ *     return sum;
+ *   }
+ *
+ *   protected void compute() {
+ *     int l = lo;
+ *     int h = hi;
+ *     Applyer right = null;
+ *     while (h - l > 1 && getSurplusQueuedTaskCount() <= 3) {
+ *       int mid = (l + h) >>> 1;
+ *       right = new Applyer(array, mid, h, right);
+ *       right.fork();
+ *       h = mid;
+ *     }
+ *     double sum = atLeaf(l, h);
+ *     while (right != null) {
+ *       if (right.tryUnfork()) // directly calculate if not stolen
+ *         sum += right.atLeaf(right.lo, right.hi);
+ *       else {
+ *         right.join();
+ *         sum += right.result;
+ *       }
+ *       right = right.next;
+ *     }
+ *     result = sum;
+ *   }
+ * }}</pre>
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public abstract class RecursiveAction extends ForkJoinTask<Void> {
+    private static final long serialVersionUID = 5232453952276485070L;
+
+    /**
+     * The main computation performed by this task.
+     */
+    protected abstract void compute();
+
+    /**
+     * Always returns {@code null}.
+     *
+     * @return {@code null} always
+     */
+    public final Void getRawResult() { return null; }
+
+    /**
+     * Requires null completion value.
+     */
+    protected final void setRawResult(Void mustBeNull) { }
+
+    /**
+     * Implements execution conventions for RecursiveActions.
+     */
+    protected final boolean exec() {
+        compute();
+        return true;
+    }
+
+}
diff --git a/java/util/concurrent/RecursiveTask.java b/java/util/concurrent/RecursiveTask.java
new file mode 100644
index 0000000..9c5ad91
--- /dev/null
+++ b/java/util/concurrent/RecursiveTask.java
@@ -0,0 +1,98 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A recursive result-bearing {@link ForkJoinTask}.
+ *
+ * <p>For a classic example, here is a task computing Fibonacci numbers:
+ *
+ * <pre> {@code
+ * class Fibonacci extends RecursiveTask<Integer> {
+ *   final int n;
+ *   Fibonacci(int n) { this.n = n; }
+ *   protected Integer compute() {
+ *     if (n <= 1)
+ *       return n;
+ *     Fibonacci f1 = new Fibonacci(n - 1);
+ *     f1.fork();
+ *     Fibonacci f2 = new Fibonacci(n - 2);
+ *     return f2.compute() + f1.join();
+ *   }
+ * }}</pre>
+ *
+ * However, besides being a dumb way to compute Fibonacci functions
+ * (there is a simple fast linear algorithm that you'd use in
+ * practice), this is likely to perform poorly because the smallest
+ * subtasks are too small to be worthwhile splitting up. Instead, as
+ * is the case for nearly all fork/join applications, you'd pick some
+ * minimum granularity size (for example 10 here) for which you always
+ * sequentially solve rather than subdividing.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
+    private static final long serialVersionUID = 5232453952276485270L;
+
+    /**
+     * The result of the computation.
+     */
+    V result;
+
+    /**
+     * The main computation performed by this task.
+     * @return the result of the computation
+     */
+    protected abstract V compute();
+
+    public final V getRawResult() {
+        return result;
+    }
+
+    protected final void setRawResult(V value) {
+        result = value;
+    }
+
+    /**
+     * Implements execution conventions for RecursiveTask.
+     */
+    protected final boolean exec() {
+        result = compute();
+        return true;
+    }
+
+}
diff --git a/java/util/concurrent/RejectedExecutionException.java b/java/util/concurrent/RejectedExecutionException.java
new file mode 100644
index 0000000..87feef4
--- /dev/null
+++ b/java/util/concurrent/RejectedExecutionException.java
@@ -0,0 +1,91 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown by an {@link Executor} when a task cannot be
+ * accepted for execution.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class RejectedExecutionException extends RuntimeException {
+    private static final long serialVersionUID = -375805702767069545L;
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with no detail message.
+     * The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     */
+    public RejectedExecutionException() { }
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with the
+     * specified detail message. The cause is not initialized, and may
+     * subsequently be initialized by a call to {@link
+     * #initCause(Throwable) initCause}.
+     *
+     * @param message the detail message
+     */
+    public RejectedExecutionException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with the
+     * specified detail message and cause.
+     *
+     * @param  message the detail message
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public RejectedExecutionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with the
+     * specified cause.  The detail message is set to {@code (cause ==
+     * null ? null : cause.toString())} (which typically contains
+     * the class and detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public RejectedExecutionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/util/concurrent/RejectedExecutionHandler.java b/java/util/concurrent/RejectedExecutionHandler.java
new file mode 100644
index 0000000..c1e314c
--- /dev/null
+++ b/java/util/concurrent/RejectedExecutionHandler.java
@@ -0,0 +1,62 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A handler for tasks that cannot be executed by a {@link ThreadPoolExecutor}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface RejectedExecutionHandler {
+
+    /**
+     * Method that may be invoked by a {@link ThreadPoolExecutor} when
+     * {@link ThreadPoolExecutor#execute execute} cannot accept a
+     * task.  This may occur when no more threads or queue slots are
+     * available because their bounds would be exceeded, or upon
+     * shutdown of the Executor.
+     *
+     * <p>In the absence of other alternatives, the method may throw
+     * an unchecked {@link RejectedExecutionException}, which will be
+     * propagated to the caller of {@code execute}.
+     *
+     * @param r the runnable task requested to be executed
+     * @param executor the executor attempting to execute this task
+     * @throws RejectedExecutionException if there is no remedy
+     */
+    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
+}
diff --git a/java/util/concurrent/RunnableFuture.java b/java/util/concurrent/RunnableFuture.java
new file mode 100644
index 0000000..b6b088a
--- /dev/null
+++ b/java/util/concurrent/RunnableFuture.java
@@ -0,0 +1,54 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link Future} that is {@link Runnable}. Successful execution of
+ * the {@code run} method causes completion of the {@code Future}
+ * and allows access to its results.
+ * @see FutureTask
+ * @see Executor
+ * @since 1.6
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future's {@code get} method
+ */
+public interface RunnableFuture<V> extends Runnable, Future<V> {
+    /**
+     * Sets this Future to the result of its computation
+     * unless it has been cancelled.
+     */
+    void run();
+}
diff --git a/java/util/concurrent/RunnableScheduledFuture.java b/java/util/concurrent/RunnableScheduledFuture.java
new file mode 100644
index 0000000..4f5ce1b
--- /dev/null
+++ b/java/util/concurrent/RunnableScheduledFuture.java
@@ -0,0 +1,58 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link ScheduledFuture} that is {@link Runnable}. Successful
+ * execution of the {@code run} method causes completion of the
+ * {@code Future} and allows access to its results.
+ * @see FutureTask
+ * @see Executor
+ * @since 1.6
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future's {@code get} method
+ */
+public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, ScheduledFuture<V> {
+
+    /**
+     * Returns {@code true} if this task is periodic. A periodic task may
+     * re-run according to some schedule. A non-periodic task can be
+     * run only once.
+     *
+     * @return {@code true} if this task is periodic
+     */
+    boolean isPeriodic();
+}
diff --git a/java/util/concurrent/ScheduledExecutorService.java b/java/util/concurrent/ScheduledExecutorService.java
new file mode 100644
index 0000000..c32e2d1
--- /dev/null
+++ b/java/util/concurrent/ScheduledExecutorService.java
@@ -0,0 +1,213 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * An {@link ExecutorService} that can schedule commands to run after a given
+ * delay, or to execute periodically.
+ *
+ * <p>The {@code schedule} methods create tasks with various delays
+ * and return a task object that can be used to cancel or check
+ * execution. The {@code scheduleAtFixedRate} and
+ * {@code scheduleWithFixedDelay} methods create and execute tasks
+ * that run periodically until cancelled.
+ *
+ * <p>Commands submitted using the {@link Executor#execute(Runnable)}
+ * and {@link ExecutorService} {@code submit} methods are scheduled
+ * with a requested delay of zero. Zero and negative delays (but not
+ * periods) are also allowed in {@code schedule} methods, and are
+ * treated as requests for immediate execution.
+ *
+ * <p>All {@code schedule} methods accept <em>relative</em> delays and
+ * periods as arguments, not absolute times or dates. It is a simple
+ * matter to transform an absolute time represented as a {@link
+ * java.util.Date} to the required form. For example, to schedule at
+ * a certain future {@code date}, you can use: {@code schedule(task,
+ * date.getTime() - System.currentTimeMillis(),
+ * TimeUnit.MILLISECONDS)}. Beware however that expiration of a
+ * relative delay need not coincide with the current {@code Date} at
+ * which the task is enabled due to network time synchronization
+ * protocols, clock drift, or other factors.
+ *
+ * <p>The {@link Executors} class provides convenient factory methods for
+ * the ScheduledExecutorService implementations provided in this package.
+ *
+ * <h3>Usage Example</h3>
+ *
+ * Here is a class with a method that sets up a ScheduledExecutorService
+ * to beep every ten seconds for an hour:
+ *
+ * <pre> {@code
+ * import static java.util.concurrent.TimeUnit.*;
+ * class BeeperControl {
+ *   private final ScheduledExecutorService scheduler =
+ *     Executors.newScheduledThreadPool(1);
+ *
+ *   public void beepForAnHour() {
+ *     final Runnable beeper = new Runnable() {
+ *       public void run() { System.out.println("beep"); }
+ *     };
+ *     final ScheduledFuture<?> beeperHandle =
+ *       scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
+ *     scheduler.schedule(new Runnable() {
+ *       public void run() { beeperHandle.cancel(true); }
+ *     }, 60 * 60, SECONDS);
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ScheduledExecutorService extends ExecutorService {
+
+    /**
+     * Creates and executes a one-shot action that becomes enabled
+     * after the given delay.
+     *
+     * @param command the task to execute
+     * @param delay the time from now to delay execution
+     * @param unit the time unit of the delay parameter
+     * @return a ScheduledFuture representing pending completion of
+     *         the task and whose {@code get()} method will return
+     *         {@code null} upon completion
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command is null
+     */
+    public ScheduledFuture<?> schedule(Runnable command,
+                                       long delay, TimeUnit unit);
+
+    /**
+     * Creates and executes a ScheduledFuture that becomes enabled after the
+     * given delay.
+     *
+     * @param callable the function to execute
+     * @param delay the time from now to delay execution
+     * @param unit the time unit of the delay parameter
+     * @param <V> the type of the callable's result
+     * @return a ScheduledFuture that can be used to extract result or cancel
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if callable is null
+     */
+    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
+                                           long delay, TimeUnit unit);
+
+    /**
+     * Creates and executes a periodic action that becomes enabled first
+     * after the given initial delay, and subsequently with the given
+     * period; that is, executions will commence after
+     * {@code initialDelay}, then {@code initialDelay + period}, then
+     * {@code initialDelay + 2 * period}, and so on.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>The executor terminates, also resulting in task cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will
+     * throw {@link ExecutionException}.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
+     * <p>If any execution of this task takes longer than its period, then
+     * subsequent executions may start late, but will not concurrently
+     * execute.
+     *
+     * @param command the task to execute
+     * @param initialDelay the time to delay first execution
+     * @param period the period between successive executions
+     * @param unit the time unit of the initialDelay and period parameters
+     * @return a ScheduledFuture representing pending completion of
+     *         the series of repeated tasks.  The future's {@link
+     *         Future#get() get()} method will never return normally,
+     *         and will throw an exception upon task cancellation or
+     *         abnormal termination of a task execution.
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command is null
+     * @throws IllegalArgumentException if period less than or equal to zero
+     */
+    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
+                                                  long initialDelay,
+                                                  long period,
+                                                  TimeUnit unit);
+
+    /**
+     * Creates and executes a periodic action that becomes enabled first
+     * after the given initial delay, and subsequently with the
+     * given delay between the termination of one execution and the
+     * commencement of the next.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>The executor terminates, also resulting in task cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will
+     * throw {@link ExecutionException}.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
+     * @param command the task to execute
+     * @param initialDelay the time to delay first execution
+     * @param delay the delay between the termination of one
+     * execution and the commencement of the next
+     * @param unit the time unit of the initialDelay and delay parameters
+     * @return a ScheduledFuture representing pending completion of
+     *         the series of repeated tasks.  The future's {@link
+     *         Future#get() get()} method will never return normally,
+     *         and will throw an exception upon task cancellation or
+     *         abnormal termination of a task execution.
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command is null
+     * @throws IllegalArgumentException if delay less than or equal to zero
+     */
+    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
+                                                     long initialDelay,
+                                                     long delay,
+                                                     TimeUnit unit);
+
+}
diff --git a/java/util/concurrent/ScheduledFuture.java b/java/util/concurrent/ScheduledFuture.java
new file mode 100644
index 0000000..1c1efa4
--- /dev/null
+++ b/java/util/concurrent/ScheduledFuture.java
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A delayed result-bearing action that can be cancelled.
+ * Usually a scheduled future is the result of scheduling
+ * a task with a {@link ScheduledExecutorService}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future
+ */
+public interface ScheduledFuture<V> extends Delayed, Future<V> {
+}
diff --git a/java/util/concurrent/ScheduledThreadPoolExecutor.java b/java/util/concurrent/ScheduledThreadPoolExecutor.java
new file mode 100644
index 0000000..4249872
--- /dev/null
+++ b/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -0,0 +1,1322 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// omit class-level docs on setRemoveOnCancelPolicy()
+// END android-note
+
+/**
+ * A {@link ThreadPoolExecutor} that can additionally schedule
+ * commands to run after a given delay, or to execute periodically.
+ * This class is preferable to {@link java.util.Timer} when multiple
+ * worker threads are needed, or when the additional flexibility or
+ * capabilities of {@link ThreadPoolExecutor} (which this class
+ * extends) are required.
+ *
+ * <p>Delayed tasks execute no sooner than they are enabled, but
+ * without any real-time guarantees about when, after they are
+ * enabled, they will commence. Tasks scheduled for exactly the same
+ * execution time are enabled in first-in-first-out (FIFO) order of
+ * submission.
+ *
+ * <p>When a submitted task is cancelled before it is run, execution
+ * is suppressed.  By default, such a cancelled task is not
+ * automatically removed from the work queue until its delay elapses.
+ * While this enables further inspection and monitoring, it may also
+ * cause unbounded retention of cancelled tasks.
+ *
+ * <p>Successive executions of a periodic task scheduled via
+ * {@link #scheduleAtFixedRate scheduleAtFixedRate} or
+ * {@link #scheduleWithFixedDelay scheduleWithFixedDelay}
+ * do not overlap. While different executions may be performed by
+ * different threads, the effects of prior executions
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * those of subsequent ones.
+ *
+ * <p>While this class inherits from {@link ThreadPoolExecutor}, a few
+ * of the inherited tuning methods are not useful for it. In
+ * particular, because it acts as a fixed-sized pool using
+ * {@code corePoolSize} threads and an unbounded queue, adjustments
+ * to {@code maximumPoolSize} have no useful effect. Additionally, it
+ * is almost never a good idea to set {@code corePoolSize} to zero or
+ * use {@code allowCoreThreadTimeOut} because this may leave the pool
+ * without threads to handle tasks once they become eligible to run.
+ *
+ * <p><b>Extension notes:</b> This class overrides the
+ * {@link ThreadPoolExecutor#execute(Runnable) execute} and
+ * {@link AbstractExecutorService#submit(Runnable) submit}
+ * methods to generate internal {@link ScheduledFuture} objects to
+ * control per-task delays and scheduling.  To preserve
+ * functionality, any further overrides of these methods in
+ * subclasses must invoke superclass versions, which effectively
+ * disables additional task customization.  However, this class
+ * provides alternative protected extension method
+ * {@code decorateTask} (one version each for {@code Runnable} and
+ * {@code Callable}) that can be used to customize the concrete task
+ * types used to execute commands entered via {@code execute},
+ * {@code submit}, {@code schedule}, {@code scheduleAtFixedRate},
+ * and {@code scheduleWithFixedDelay}.  By default, a
+ * {@code ScheduledThreadPoolExecutor} uses a task type extending
+ * {@link FutureTask}. However, this may be modified or replaced using
+ * subclasses of the form:
+ *
+ * <pre> {@code
+ * public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
+ *
+ *   static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
+ *
+ *   protected <V> RunnableScheduledFuture<V> decorateTask(
+ *                Runnable r, RunnableScheduledFuture<V> task) {
+ *       return new CustomTask<V>(r, task);
+ *   }
+ *
+ *   protected <V> RunnableScheduledFuture<V> decorateTask(
+ *                Callable<V> c, RunnableScheduledFuture<V> task) {
+ *       return new CustomTask<V>(c, task);
+ *   }
+ *   // ... add constructors, etc.
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ScheduledThreadPoolExecutor
+        extends ThreadPoolExecutor
+        implements ScheduledExecutorService {
+
+    /*
+     * This class specializes ThreadPoolExecutor implementation by
+     *
+     * 1. Using a custom task type ScheduledFutureTask, even for tasks
+     *    that don't require scheduling because they are submitted
+     *    using ExecutorService rather than ScheduledExecutorService
+     *    methods, which are treated as tasks with a delay of zero.
+     *
+     * 2. Using a custom queue (DelayedWorkQueue), a variant of
+     *    unbounded DelayQueue. The lack of capacity constraint and
+     *    the fact that corePoolSize and maximumPoolSize are
+     *    effectively identical simplifies some execution mechanics
+     *    (see delayedExecute) compared to ThreadPoolExecutor.
+     *
+     * 3. Supporting optional run-after-shutdown parameters, which
+     *    leads to overrides of shutdown methods to remove and cancel
+     *    tasks that should NOT be run after shutdown, as well as
+     *    different recheck logic when task (re)submission overlaps
+     *    with a shutdown.
+     *
+     * 4. Task decoration methods to allow interception and
+     *    instrumentation, which are needed because subclasses cannot
+     *    otherwise override submit methods to get this effect. These
+     *    don't have any impact on pool control logic though.
+     */
+
+    /**
+     * False if should cancel/suppress periodic tasks on shutdown.
+     */
+    private volatile boolean continueExistingPeriodicTasksAfterShutdown;
+
+    /**
+     * False if should cancel non-periodic tasks on shutdown.
+     */
+    private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
+
+    /**
+     * True if ScheduledFutureTask.cancel should remove from queue.
+     */
+    volatile boolean removeOnCancel;
+
+    /**
+     * Sequence number to break scheduling ties, and in turn to
+     * guarantee FIFO order among tied entries.
+     */
+    private static final AtomicLong sequencer = new AtomicLong();
+
+    private class ScheduledFutureTask<V>
+            extends FutureTask<V> implements RunnableScheduledFuture<V> {
+
+        /** Sequence number to break ties FIFO */
+        private final long sequenceNumber;
+
+        /** The nanoTime-based time when the task is enabled to execute. */
+        private volatile long time;
+
+        /**
+         * Period for repeating tasks, in nanoseconds.
+         * A positive value indicates fixed-rate execution.
+         * A negative value indicates fixed-delay execution.
+         * A value of 0 indicates a non-repeating (one-shot) task.
+         */
+        private final long period;
+
+        /** The actual task to be re-enqueued by reExecutePeriodic */
+        RunnableScheduledFuture<V> outerTask = this;
+
+        /**
+         * Index into delay queue, to support faster cancellation.
+         */
+        int heapIndex;
+
+        /**
+         * Creates a one-shot action with given nanoTime-based trigger time.
+         */
+        ScheduledFutureTask(Runnable r, V result, long triggerTime,
+                            long sequenceNumber) {
+            super(r, result);
+            this.time = triggerTime;
+            this.period = 0;
+            this.sequenceNumber = sequenceNumber;
+        }
+
+        /**
+         * Creates a periodic action with given nanoTime-based initial
+         * trigger time and period.
+         */
+        ScheduledFutureTask(Runnable r, V result, long triggerTime,
+                            long period, long sequenceNumber) {
+            super(r, result);
+            this.time = triggerTime;
+            this.period = period;
+            this.sequenceNumber = sequenceNumber;
+        }
+
+        /**
+         * Creates a one-shot action with given nanoTime-based trigger time.
+         */
+        ScheduledFutureTask(Callable<V> callable, long triggerTime,
+                            long sequenceNumber) {
+            super(callable);
+            this.time = triggerTime;
+            this.period = 0;
+            this.sequenceNumber = sequenceNumber;
+        }
+
+        public long getDelay(TimeUnit unit) {
+            return unit.convert(time - System.nanoTime(), NANOSECONDS);
+        }
+
+        public int compareTo(Delayed other) {
+            if (other == this) // compare zero if same object
+                return 0;
+            if (other instanceof ScheduledFutureTask) {
+                ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
+                long diff = time - x.time;
+                if (diff < 0)
+                    return -1;
+                else if (diff > 0)
+                    return 1;
+                else if (sequenceNumber < x.sequenceNumber)
+                    return -1;
+                else
+                    return 1;
+            }
+            long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
+            return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
+        }
+
+        /**
+         * Returns {@code true} if this is a periodic (not a one-shot) action.
+         *
+         * @return {@code true} if periodic
+         */
+        public boolean isPeriodic() {
+            return period != 0;
+        }
+
+        /**
+         * Sets the next time to run for a periodic task.
+         */
+        private void setNextRunTime() {
+            long p = period;
+            if (p > 0)
+                time += p;
+            else
+                time = triggerTime(-p);
+        }
+
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            // The racy read of heapIndex below is benign:
+            // if heapIndex < 0, then OOTA guarantees that we have surely
+            // been removed; else we recheck under lock in remove()
+            boolean cancelled = super.cancel(mayInterruptIfRunning);
+            if (cancelled && removeOnCancel && heapIndex >= 0)
+                remove(this);
+            return cancelled;
+        }
+
+        /**
+         * Overrides FutureTask version so as to reset/requeue if periodic.
+         */
+        public void run() {
+            boolean periodic = isPeriodic();
+            if (!canRunInCurrentRunState(periodic))
+                cancel(false);
+            else if (!periodic)
+                super.run();
+            else if (super.runAndReset()) {
+                setNextRunTime();
+                reExecutePeriodic(outerTask);
+            }
+        }
+    }
+
+    /**
+     * Returns true if can run a task given current run state
+     * and run-after-shutdown parameters.
+     *
+     * @param periodic true if this task periodic, false if delayed
+     */
+    boolean canRunInCurrentRunState(boolean periodic) {
+        return isRunningOrShutdown(periodic ?
+                                   continueExistingPeriodicTasksAfterShutdown :
+                                   executeExistingDelayedTasksAfterShutdown);
+    }
+
+    /**
+     * Main execution method for delayed or periodic tasks.  If pool
+     * is shut down, rejects the task. Otherwise adds task to queue
+     * and starts a thread, if necessary, to run it.  (We cannot
+     * prestart the thread to run the task because the task (probably)
+     * shouldn't be run yet.)  If the pool is shut down while the task
+     * is being added, cancel and remove it if required by state and
+     * run-after-shutdown parameters.
+     *
+     * @param task the task
+     */
+    private void delayedExecute(RunnableScheduledFuture<?> task) {
+        if (isShutdown())
+            reject(task);
+        else {
+            super.getQueue().add(task);
+            if (isShutdown() &&
+                !canRunInCurrentRunState(task.isPeriodic()) &&
+                remove(task))
+                task.cancel(false);
+            else
+                ensurePrestart();
+        }
+    }
+
+    /**
+     * Requeues a periodic task unless current run state precludes it.
+     * Same idea as delayedExecute except drops task rather than rejecting.
+     *
+     * @param task the task
+     */
+    void reExecutePeriodic(RunnableScheduledFuture<?> task) {
+        if (canRunInCurrentRunState(true)) {
+            super.getQueue().add(task);
+            if (!canRunInCurrentRunState(true) && remove(task))
+                task.cancel(false);
+            else
+                ensurePrestart();
+        }
+    }
+
+    /**
+     * Cancels and clears the queue of all tasks that should not be run
+     * due to shutdown policy.  Invoked within super.shutdown.
+     */
+    @Override void onShutdown() {
+        BlockingQueue<Runnable> q = super.getQueue();
+        boolean keepDelayed =
+            getExecuteExistingDelayedTasksAfterShutdownPolicy();
+        boolean keepPeriodic =
+            getContinueExistingPeriodicTasksAfterShutdownPolicy();
+        if (!keepDelayed && !keepPeriodic) {
+            for (Object e : q.toArray())
+                if (e instanceof RunnableScheduledFuture<?>)
+                    ((RunnableScheduledFuture<?>) e).cancel(false);
+            q.clear();
+        }
+        else {
+            // Traverse snapshot to avoid iterator exceptions
+            for (Object e : q.toArray()) {
+                if (e instanceof RunnableScheduledFuture) {
+                    RunnableScheduledFuture<?> t =
+                        (RunnableScheduledFuture<?>)e;
+                    if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) ||
+                        t.isCancelled()) { // also remove if already cancelled
+                        if (q.remove(t))
+                            t.cancel(false);
+                    }
+                }
+            }
+        }
+        tryTerminate();
+    }
+
+    /**
+     * Modifies or replaces the task used to execute a runnable.
+     * This method can be used to override the concrete
+     * class used for managing internal tasks.
+     * The default implementation simply returns the given task.
+     *
+     * @param runnable the submitted Runnable
+     * @param task the task created to execute the runnable
+     * @param <V> the type of the task's result
+     * @return a task that can execute the runnable
+     * @since 1.6
+     */
+    protected <V> RunnableScheduledFuture<V> decorateTask(
+        Runnable runnable, RunnableScheduledFuture<V> task) {
+        return task;
+    }
+
+    /**
+     * Modifies or replaces the task used to execute a callable.
+     * This method can be used to override the concrete
+     * class used for managing internal tasks.
+     * The default implementation simply returns the given task.
+     *
+     * @param callable the submitted Callable
+     * @param task the task created to execute the callable
+     * @param <V> the type of the task's result
+     * @return a task that can execute the callable
+     * @since 1.6
+     */
+    protected <V> RunnableScheduledFuture<V> decorateTask(
+        Callable<V> callable, RunnableScheduledFuture<V> task) {
+        return task;
+    }
+
+    /**
+     * The default keep-alive time for pool threads.
+     *
+     * Normally, this value is unused because all pool threads will be
+     * core threads, but if a user creates a pool with a corePoolSize
+     * of zero (against our advice), we keep a thread alive as long as
+     * there are queued tasks.  If the keep alive time is zero (the
+     * historic value), we end up hot-spinning in getTask, wasting a
+     * CPU.  But on the other hand, if we set the value too high, and
+     * users create a one-shot pool which they don't cleanly shutdown,
+     * the pool's non-daemon threads will prevent JVM termination.  A
+     * small but non-zero value (relative to a JVM's lifetime) seems
+     * best.
+     */
+    private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given core pool size.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue());
+    }
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given initial parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if {@code threadFactory} is null
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize,
+                                       ThreadFactory threadFactory) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue(), threadFactory);
+    }
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given initial parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if {@code handler} is null
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize,
+                                       RejectedExecutionHandler handler) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue(), handler);
+    }
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given initial parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if {@code threadFactory} or
+     *         {@code handler} is null
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize,
+                                       ThreadFactory threadFactory,
+                                       RejectedExecutionHandler handler) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue(), threadFactory, handler);
+    }
+
+    /**
+     * Returns the nanoTime-based trigger time of a delayed action.
+     */
+    private long triggerTime(long delay, TimeUnit unit) {
+        return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
+    }
+
+    /**
+     * Returns the nanoTime-based trigger time of a delayed action.
+     */
+    long triggerTime(long delay) {
+        return System.nanoTime() +
+            ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
+    }
+
+    /**
+     * Constrains the values of all delays in the queue to be within
+     * Long.MAX_VALUE of each other, to avoid overflow in compareTo.
+     * This may occur if a task is eligible to be dequeued, but has
+     * not yet been, while some other task is added with a delay of
+     * Long.MAX_VALUE.
+     */
+    private long overflowFree(long delay) {
+        Delayed head = (Delayed) super.getQueue().peek();
+        if (head != null) {
+            long headDelay = head.getDelay(NANOSECONDS);
+            if (headDelay < 0 && (delay - headDelay < 0))
+                delay = Long.MAX_VALUE + headDelay;
+        }
+        return delay;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public ScheduledFuture<?> schedule(Runnable command,
+                                       long delay,
+                                       TimeUnit unit) {
+        if (command == null || unit == null)
+            throw new NullPointerException();
+        RunnableScheduledFuture<Void> t = decorateTask(command,
+            new ScheduledFutureTask<Void>(command, null,
+                                          triggerTime(delay, unit),
+                                          sequencer.getAndIncrement()));
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
+                                           long delay,
+                                           TimeUnit unit) {
+        if (callable == null || unit == null)
+            throw new NullPointerException();
+        RunnableScheduledFuture<V> t = decorateTask(callable,
+            new ScheduledFutureTask<V>(callable,
+                                       triggerTime(delay, unit),
+                                       sequencer.getAndIncrement()));
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     * @throws IllegalArgumentException   {@inheritDoc}
+     */
+    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
+                                                  long initialDelay,
+                                                  long period,
+                                                  TimeUnit unit) {
+        if (command == null || unit == null)
+            throw new NullPointerException();
+        if (period <= 0L)
+            throw new IllegalArgumentException();
+        ScheduledFutureTask<Void> sft =
+            new ScheduledFutureTask<Void>(command,
+                                          null,
+                                          triggerTime(initialDelay, unit),
+                                          unit.toNanos(period),
+                                          sequencer.getAndIncrement());
+        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
+        sft.outerTask = t;
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     * @throws IllegalArgumentException   {@inheritDoc}
+     */
+    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
+                                                     long initialDelay,
+                                                     long delay,
+                                                     TimeUnit unit) {
+        if (command == null || unit == null)
+            throw new NullPointerException();
+        if (delay <= 0L)
+            throw new IllegalArgumentException();
+        ScheduledFutureTask<Void> sft =
+            new ScheduledFutureTask<Void>(command,
+                                          null,
+                                          triggerTime(initialDelay, unit),
+                                          -unit.toNanos(delay),
+                                          sequencer.getAndIncrement());
+        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
+        sft.outerTask = t;
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * Executes {@code command} with zero required delay.
+     * This has effect equivalent to
+     * {@link #schedule(Runnable,long,TimeUnit) schedule(command, 0, anyUnit)}.
+     * Note that inspections of the queue and of the list returned by
+     * {@code shutdownNow} will access the zero-delayed
+     * {@link ScheduledFuture}, not the {@code command} itself.
+     *
+     * <p>A consequence of the use of {@code ScheduledFuture} objects is
+     * that {@link ThreadPoolExecutor#afterExecute afterExecute} is always
+     * called with a null second {@code Throwable} argument, even if the
+     * {@code command} terminated abruptly.  Instead, the {@code Throwable}
+     * thrown by such a task can be obtained via {@link Future#get}.
+     *
+     * @throws RejectedExecutionException at discretion of
+     *         {@code RejectedExecutionHandler}, if the task
+     *         cannot be accepted for execution because the
+     *         executor has been shut down
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void execute(Runnable command) {
+        schedule(command, 0, NANOSECONDS);
+    }
+
+    // Override AbstractExecutorService methods
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public Future<?> submit(Runnable task) {
+        return schedule(task, 0, NANOSECONDS);
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Runnable task, T result) {
+        return schedule(Executors.callable(task, result), 0, NANOSECONDS);
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Callable<T> task) {
+        return schedule(task, 0, NANOSECONDS);
+    }
+
+    /**
+     * Sets the policy on whether to continue executing existing
+     * periodic tasks even when this executor has been {@code shutdown}.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow} or after setting the policy to
+     * {@code false} when already shutdown.
+     * This value is by default {@code false}.
+     *
+     * @param value if {@code true}, continue after shutdown, else don't
+     * @see #getContinueExistingPeriodicTasksAfterShutdownPolicy
+     */
+    public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) {
+        continueExistingPeriodicTasksAfterShutdown = value;
+        if (!value && isShutdown())
+            onShutdown();
+    }
+
+    /**
+     * Gets the policy on whether to continue executing existing
+     * periodic tasks even when this executor has been {@code shutdown}.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow} or after setting the policy to
+     * {@code false} when already shutdown.
+     * This value is by default {@code false}.
+     *
+     * @return {@code true} if will continue after shutdown
+     * @see #setContinueExistingPeriodicTasksAfterShutdownPolicy
+     */
+    public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy() {
+        return continueExistingPeriodicTasksAfterShutdown;
+    }
+
+    /**
+     * Sets the policy on whether to execute existing delayed
+     * tasks even when this executor has been {@code shutdown}.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow}, or after setting the policy to
+     * {@code false} when already shutdown.
+     * This value is by default {@code true}.
+     *
+     * @param value if {@code true}, execute after shutdown, else don't
+     * @see #getExecuteExistingDelayedTasksAfterShutdownPolicy
+     */
+    public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value) {
+        executeExistingDelayedTasksAfterShutdown = value;
+        if (!value && isShutdown())
+            onShutdown();
+    }
+
+    /**
+     * Gets the policy on whether to execute existing delayed
+     * tasks even when this executor has been {@code shutdown}.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow}, or after setting the policy to
+     * {@code false} when already shutdown.
+     * This value is by default {@code true}.
+     *
+     * @return {@code true} if will execute after shutdown
+     * @see #setExecuteExistingDelayedTasksAfterShutdownPolicy
+     */
+    public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() {
+        return executeExistingDelayedTasksAfterShutdown;
+    }
+
+    /**
+     * Sets the policy on whether cancelled tasks should be immediately
+     * removed from the work queue at time of cancellation.  This value is
+     * by default {@code false}.
+     *
+     * @param value if {@code true}, remove on cancellation, else don't
+     * @see #getRemoveOnCancelPolicy
+     * @since 1.7
+     */
+    public void setRemoveOnCancelPolicy(boolean value) {
+        removeOnCancel = value;
+    }
+
+    /**
+     * Gets the policy on whether cancelled tasks should be immediately
+     * removed from the work queue at time of cancellation.  This value is
+     * by default {@code false}.
+     *
+     * @return {@code true} if cancelled tasks are immediately removed
+     *         from the queue
+     * @see #setRemoveOnCancelPolicy
+     * @since 1.7
+     */
+    public boolean getRemoveOnCancelPolicy() {
+        return removeOnCancel;
+    }
+
+    /**
+     * Initiates an orderly shutdown in which previously submitted
+     * tasks are executed, but no new tasks will be accepted.
+     * Invocation has no additional effect if already shut down.
+     *
+     * <p>This method does not wait for previously submitted tasks to
+     * complete execution.  Use {@link #awaitTermination awaitTermination}
+     * to do that.
+     *
+     * <p>If the {@code ExecuteExistingDelayedTasksAfterShutdownPolicy}
+     * has been set {@code false}, existing delayed tasks whose delays
+     * have not yet elapsed are cancelled.  And unless the {@code
+     * ContinueExistingPeriodicTasksAfterShutdownPolicy} has been set
+     * {@code true}, future executions of existing periodic tasks will
+     * be cancelled.
+     */
+    // android-note: Removed "throws SecurityException" doc.
+    public void shutdown() {
+        super.shutdown();
+    }
+
+    /**
+     * Attempts to stop all actively executing tasks, halts the
+     * processing of waiting tasks, and returns a list of the tasks
+     * that were awaiting execution. These tasks are drained (removed)
+     * from the task queue upon return from this method.
+     *
+     * <p>This method does not wait for actively executing tasks to
+     * terminate.  Use {@link #awaitTermination awaitTermination} to
+     * do that.
+     *
+     * <p>There are no guarantees beyond best-effort attempts to stop
+     * processing actively executing tasks.  This implementation
+     * interrupts tasks via {@link Thread#interrupt}; any task that
+     * fails to respond to interrupts may never terminate.
+     *
+     * @return list of tasks that never commenced execution.
+     *         Each element of this list is a {@link ScheduledFuture}.
+     *         For tasks submitted via one of the {@code schedule}
+     *         methods, the element will be identical to the returned
+     *         {@code ScheduledFuture}.  For tasks submitted using
+     *         {@link #execute execute}, the element will be a
+     *         zero-delay {@code ScheduledFuture}.
+     */
+    // android-note: Removed "throws SecurityException" doc.
+    public List<Runnable> shutdownNow() {
+        return super.shutdownNow();
+    }
+
+    /**
+     * Returns the task queue used by this executor.  Access to the
+     * task queue is intended primarily for debugging and monitoring.
+     * This queue may be in active use.  Retrieving the task queue
+     * does not prevent queued tasks from executing.
+     *
+     * <p>Each element of this queue is a {@link ScheduledFuture}.
+     * For tasks submitted via one of the {@code schedule} methods, the
+     * element will be identical to the returned {@code ScheduledFuture}.
+     * For tasks submitted using {@link #execute execute}, the element
+     * will be a zero-delay {@code ScheduledFuture}.
+     *
+     * <p>Iteration over this queue is <em>not</em> guaranteed to traverse
+     * tasks in the order in which they will execute.
+     *
+     * @return the task queue
+     */
+    public BlockingQueue<Runnable> getQueue() {
+        return super.getQueue();
+    }
+
+    /**
+     * Specialized delay queue. To mesh with TPE declarations, this
+     * class must be declared as a BlockingQueue<Runnable> even though
+     * it can only hold RunnableScheduledFutures.
+     */
+    static class DelayedWorkQueue extends AbstractQueue<Runnable>
+        implements BlockingQueue<Runnable> {
+
+        /*
+         * A DelayedWorkQueue is based on a heap-based data structure
+         * like those in DelayQueue and PriorityQueue, except that
+         * every ScheduledFutureTask also records its index into the
+         * heap array. This eliminates the need to find a task upon
+         * cancellation, greatly speeding up removal (down from O(n)
+         * to O(log n)), and reducing garbage retention that would
+         * otherwise occur by waiting for the element to rise to top
+         * before clearing. But because the queue may also hold
+         * RunnableScheduledFutures that are not ScheduledFutureTasks,
+         * we are not guaranteed to have such indices available, in
+         * which case we fall back to linear search. (We expect that
+         * most tasks will not be decorated, and that the faster cases
+         * will be much more common.)
+         *
+         * All heap operations must record index changes -- mainly
+         * within siftUp and siftDown. Upon removal, a task's
+         * heapIndex is set to -1. Note that ScheduledFutureTasks can
+         * appear at most once in the queue (this need not be true for
+         * other kinds of tasks or work queues), so are uniquely
+         * identified by heapIndex.
+         */
+
+        private static final int INITIAL_CAPACITY = 16;
+        private RunnableScheduledFuture<?>[] queue =
+            new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
+        private final ReentrantLock lock = new ReentrantLock();
+        private int size;
+
+        /**
+         * Thread designated to wait for the task at the head of the
+         * queue.  This variant of the Leader-Follower pattern
+         * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to
+         * minimize unnecessary timed waiting.  When a thread becomes
+         * the leader, it waits only for the next delay to elapse, but
+         * other threads await indefinitely.  The leader thread must
+         * signal some other thread before returning from take() or
+         * poll(...), unless some other thread becomes leader in the
+         * interim.  Whenever the head of the queue is replaced with a
+         * task with an earlier expiration time, the leader field is
+         * invalidated by being reset to null, and some waiting
+         * thread, but not necessarily the current leader, is
+         * signalled.  So waiting threads must be prepared to acquire
+         * and lose leadership while waiting.
+         */
+        private Thread leader;
+
+        /**
+         * Condition signalled when a newer task becomes available at the
+         * head of the queue or a new thread may need to become leader.
+         */
+        private final Condition available = lock.newCondition();
+
+        /**
+         * Sets f's heapIndex if it is a ScheduledFutureTask.
+         */
+        private void setIndex(RunnableScheduledFuture<?> f, int idx) {
+            if (f instanceof ScheduledFutureTask)
+                ((ScheduledFutureTask)f).heapIndex = idx;
+        }
+
+        /**
+         * Sifts element added at bottom up to its heap-ordered spot.
+         * Call only when holding lock.
+         */
+        private void siftUp(int k, RunnableScheduledFuture<?> key) {
+            while (k > 0) {
+                int parent = (k - 1) >>> 1;
+                RunnableScheduledFuture<?> e = queue[parent];
+                if (key.compareTo(e) >= 0)
+                    break;
+                queue[k] = e;
+                setIndex(e, k);
+                k = parent;
+            }
+            queue[k] = key;
+            setIndex(key, k);
+        }
+
+        /**
+         * Sifts element added at top down to its heap-ordered spot.
+         * Call only when holding lock.
+         */
+        private void siftDown(int k, RunnableScheduledFuture<?> key) {
+            int half = size >>> 1;
+            while (k < half) {
+                int child = (k << 1) + 1;
+                RunnableScheduledFuture<?> c = queue[child];
+                int right = child + 1;
+                if (right < size && c.compareTo(queue[right]) > 0)
+                    c = queue[child = right];
+                if (key.compareTo(c) <= 0)
+                    break;
+                queue[k] = c;
+                setIndex(c, k);
+                k = child;
+            }
+            queue[k] = key;
+            setIndex(key, k);
+        }
+
+        /**
+         * Resizes the heap array.  Call only when holding lock.
+         */
+        private void grow() {
+            int oldCapacity = queue.length;
+            int newCapacity = oldCapacity + (oldCapacity >> 1); // grow 50%
+            if (newCapacity < 0) // overflow
+                newCapacity = Integer.MAX_VALUE;
+            queue = Arrays.copyOf(queue, newCapacity);
+        }
+
+        /**
+         * Finds index of given object, or -1 if absent.
+         */
+        private int indexOf(Object x) {
+            if (x != null) {
+                if (x instanceof ScheduledFutureTask) {
+                    int i = ((ScheduledFutureTask) x).heapIndex;
+                    // Sanity check; x could conceivably be a
+                    // ScheduledFutureTask from some other pool.
+                    if (i >= 0 && i < size && queue[i] == x)
+                        return i;
+                } else {
+                    for (int i = 0; i < size; i++)
+                        if (x.equals(queue[i]))
+                            return i;
+                }
+            }
+            return -1;
+        }
+
+        public boolean contains(Object x) {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return indexOf(x) != -1;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean remove(Object x) {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                int i = indexOf(x);
+                if (i < 0)
+                    return false;
+
+                setIndex(queue[i], -1);
+                int s = --size;
+                RunnableScheduledFuture<?> replacement = queue[s];
+                queue[s] = null;
+                if (s != i) {
+                    siftDown(i, replacement);
+                    if (queue[i] == replacement)
+                        siftUp(i, replacement);
+                }
+                return true;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public int size() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return size;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean isEmpty() {
+            return size() == 0;
+        }
+
+        public int remainingCapacity() {
+            return Integer.MAX_VALUE;
+        }
+
+        public RunnableScheduledFuture<?> peek() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return queue[0];
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean offer(Runnable x) {
+            if (x == null)
+                throw new NullPointerException();
+            RunnableScheduledFuture<?> e = (RunnableScheduledFuture<?>)x;
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                int i = size;
+                if (i >= queue.length)
+                    grow();
+                size = i + 1;
+                if (i == 0) {
+                    queue[0] = e;
+                    setIndex(e, 0);
+                } else {
+                    siftUp(i, e);
+                }
+                if (queue[0] == e) {
+                    leader = null;
+                    available.signal();
+                }
+            } finally {
+                lock.unlock();
+            }
+            return true;
+        }
+
+        public void put(Runnable e) {
+            offer(e);
+        }
+
+        public boolean add(Runnable e) {
+            return offer(e);
+        }
+
+        public boolean offer(Runnable e, long timeout, TimeUnit unit) {
+            return offer(e);
+        }
+
+        /**
+         * Performs common bookkeeping for poll and take: Replaces
+         * first element with last and sifts it down.  Call only when
+         * holding lock.
+         * @param f the task to remove and return
+         */
+        private RunnableScheduledFuture<?> finishPoll(RunnableScheduledFuture<?> f) {
+            int s = --size;
+            RunnableScheduledFuture<?> x = queue[s];
+            queue[s] = null;
+            if (s != 0)
+                siftDown(0, x);
+            setIndex(f, -1);
+            return f;
+        }
+
+        public RunnableScheduledFuture<?> poll() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                RunnableScheduledFuture<?> first = queue[0];
+                return (first == null || first.getDelay(NANOSECONDS) > 0)
+                    ? null
+                    : finishPoll(first);
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public RunnableScheduledFuture<?> take() throws InterruptedException {
+            final ReentrantLock lock = this.lock;
+            lock.lockInterruptibly();
+            try {
+                for (;;) {
+                    RunnableScheduledFuture<?> first = queue[0];
+                    if (first == null)
+                        available.await();
+                    else {
+                        long delay = first.getDelay(NANOSECONDS);
+                        if (delay <= 0L)
+                            return finishPoll(first);
+                        first = null; // don't retain ref while waiting
+                        if (leader != null)
+                            available.await();
+                        else {
+                            Thread thisThread = Thread.currentThread();
+                            leader = thisThread;
+                            try {
+                                available.awaitNanos(delay);
+                            } finally {
+                                if (leader == thisThread)
+                                    leader = null;
+                            }
+                        }
+                    }
+                }
+            } finally {
+                if (leader == null && queue[0] != null)
+                    available.signal();
+                lock.unlock();
+            }
+        }
+
+        public RunnableScheduledFuture<?> poll(long timeout, TimeUnit unit)
+            throws InterruptedException {
+            long nanos = unit.toNanos(timeout);
+            final ReentrantLock lock = this.lock;
+            lock.lockInterruptibly();
+            try {
+                for (;;) {
+                    RunnableScheduledFuture<?> first = queue[0];
+                    if (first == null) {
+                        if (nanos <= 0L)
+                            return null;
+                        else
+                            nanos = available.awaitNanos(nanos);
+                    } else {
+                        long delay = first.getDelay(NANOSECONDS);
+                        if (delay <= 0L)
+                            return finishPoll(first);
+                        if (nanos <= 0L)
+                            return null;
+                        first = null; // don't retain ref while waiting
+                        if (nanos < delay || leader != null)
+                            nanos = available.awaitNanos(nanos);
+                        else {
+                            Thread thisThread = Thread.currentThread();
+                            leader = thisThread;
+                            try {
+                                long timeLeft = available.awaitNanos(delay);
+                                nanos -= delay - timeLeft;
+                            } finally {
+                                if (leader == thisThread)
+                                    leader = null;
+                            }
+                        }
+                    }
+                }
+            } finally {
+                if (leader == null && queue[0] != null)
+                    available.signal();
+                lock.unlock();
+            }
+        }
+
+        public void clear() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                for (int i = 0; i < size; i++) {
+                    RunnableScheduledFuture<?> t = queue[i];
+                    if (t != null) {
+                        queue[i] = null;
+                        setIndex(t, -1);
+                    }
+                }
+                size = 0;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        /**
+         * Returns first element only if it is expired.
+         * Used only by drainTo.  Call only when holding lock.
+         */
+        private RunnableScheduledFuture<?> peekExpired() {
+            // assert lock.isHeldByCurrentThread();
+            RunnableScheduledFuture<?> first = queue[0];
+            return (first == null || first.getDelay(NANOSECONDS) > 0) ?
+                null : first;
+        }
+
+        public int drainTo(Collection<? super Runnable> c) {
+            if (c == null)
+                throw new NullPointerException();
+            if (c == this)
+                throw new IllegalArgumentException();
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                RunnableScheduledFuture<?> first;
+                int n = 0;
+                while ((first = peekExpired()) != null) {
+                    c.add(first);   // In this order, in case add() throws.
+                    finishPoll(first);
+                    ++n;
+                }
+                return n;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public int drainTo(Collection<? super Runnable> c, int maxElements) {
+            if (c == null)
+                throw new NullPointerException();
+            if (c == this)
+                throw new IllegalArgumentException();
+            if (maxElements <= 0)
+                return 0;
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                RunnableScheduledFuture<?> first;
+                int n = 0;
+                while (n < maxElements && (first = peekExpired()) != null) {
+                    c.add(first);   // In this order, in case add() throws.
+                    finishPoll(first);
+                    ++n;
+                }
+                return n;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public Object[] toArray() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return Arrays.copyOf(queue, size, Object[].class);
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                if (a.length < size)
+                    return (T[]) Arrays.copyOf(queue, size, a.getClass());
+                System.arraycopy(queue, 0, a, 0, size);
+                if (a.length > size)
+                    a[size] = null;
+                return a;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public Iterator<Runnable> iterator() {
+            return new Itr(Arrays.copyOf(queue, size));
+        }
+
+        /**
+         * Snapshot iterator that works off copy of underlying q array.
+         */
+        private class Itr implements Iterator<Runnable> {
+            final RunnableScheduledFuture<?>[] array;
+            int cursor;        // index of next element to return; initially 0
+            int lastRet = -1;  // index of last element returned; -1 if no such
+
+            Itr(RunnableScheduledFuture<?>[] array) {
+                this.array = array;
+            }
+
+            public boolean hasNext() {
+                return cursor < array.length;
+            }
+
+            public Runnable next() {
+                if (cursor >= array.length)
+                    throw new NoSuchElementException();
+                lastRet = cursor;
+                return array[cursor++];
+            }
+
+            public void remove() {
+                if (lastRet < 0)
+                    throw new IllegalStateException();
+                DelayedWorkQueue.this.remove(array[lastRet]);
+                lastRet = -1;
+            }
+        }
+    }
+}
diff --git a/java/util/concurrent/Semaphore.java b/java/util/concurrent/Semaphore.java
new file mode 100644
index 0000000..1298a6e
--- /dev/null
+++ b/java/util/concurrent/Semaphore.java
@@ -0,0 +1,717 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+/**
+ * A counting semaphore.  Conceptually, a semaphore maintains a set of
+ * permits.  Each {@link #acquire} blocks if necessary until a permit is
+ * available, and then takes it.  Each {@link #release} adds a permit,
+ * potentially releasing a blocking acquirer.
+ * However, no actual permit objects are used; the {@code Semaphore} just
+ * keeps a count of the number available and acts accordingly.
+ *
+ * <p>Semaphores are often used to restrict the number of threads than can
+ * access some (physical or logical) resource. For example, here is
+ * a class that uses a semaphore to control access to a pool of items:
+ * <pre> {@code
+ * class Pool {
+ *   private static final int MAX_AVAILABLE = 100;
+ *   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
+ *
+ *   public Object getItem() throws InterruptedException {
+ *     available.acquire();
+ *     return getNextAvailableItem();
+ *   }
+ *
+ *   public void putItem(Object x) {
+ *     if (markAsUnused(x))
+ *       available.release();
+ *   }
+ *
+ *   // Not a particularly efficient data structure; just for demo
+ *
+ *   protected Object[] items = ... whatever kinds of items being managed
+ *   protected boolean[] used = new boolean[MAX_AVAILABLE];
+ *
+ *   protected synchronized Object getNextAvailableItem() {
+ *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
+ *       if (!used[i]) {
+ *          used[i] = true;
+ *          return items[i];
+ *       }
+ *     }
+ *     return null; // not reached
+ *   }
+ *
+ *   protected synchronized boolean markAsUnused(Object item) {
+ *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
+ *       if (item == items[i]) {
+ *          if (used[i]) {
+ *            used[i] = false;
+ *            return true;
+ *          } else
+ *            return false;
+ *       }
+ *     }
+ *     return false;
+ *   }
+ * }}</pre>
+ *
+ * <p>Before obtaining an item each thread must acquire a permit from
+ * the semaphore, guaranteeing that an item is available for use. When
+ * the thread has finished with the item it is returned back to the
+ * pool and a permit is returned to the semaphore, allowing another
+ * thread to acquire that item.  Note that no synchronization lock is
+ * held when {@link #acquire} is called as that would prevent an item
+ * from being returned to the pool.  The semaphore encapsulates the
+ * synchronization needed to restrict access to the pool, separately
+ * from any synchronization needed to maintain the consistency of the
+ * pool itself.
+ *
+ * <p>A semaphore initialized to one, and which is used such that it
+ * only has at most one permit available, can serve as a mutual
+ * exclusion lock.  This is more commonly known as a <em>binary
+ * semaphore</em>, because it only has two states: one permit
+ * available, or zero permits available.  When used in this way, the
+ * binary semaphore has the property (unlike many {@link java.util.concurrent.locks.Lock}
+ * implementations), that the &quot;lock&quot; can be released by a
+ * thread other than the owner (as semaphores have no notion of
+ * ownership).  This can be useful in some specialized contexts, such
+ * as deadlock recovery.
+ *
+ * <p>The constructor for this class optionally accepts a
+ * <em>fairness</em> parameter. When set false, this class makes no
+ * guarantees about the order in which threads acquire permits. In
+ * particular, <em>barging</em> is permitted, that is, a thread
+ * invoking {@link #acquire} can be allocated a permit ahead of a
+ * thread that has been waiting - logically the new thread places itself at
+ * the head of the queue of waiting threads. When fairness is set true, the
+ * semaphore guarantees that threads invoking any of the {@link
+ * #acquire() acquire} methods are selected to obtain permits in the order in
+ * which their invocation of those methods was processed
+ * (first-in-first-out; FIFO). Note that FIFO ordering necessarily
+ * applies to specific internal points of execution within these
+ * methods.  So, it is possible for one thread to invoke
+ * {@code acquire} before another, but reach the ordering point after
+ * the other, and similarly upon return from the method.
+ * Also note that the untimed {@link #tryAcquire() tryAcquire} methods do not
+ * honor the fairness setting, but will take any permits that are
+ * available.
+ *
+ * <p>Generally, semaphores used to control resource access should be
+ * initialized as fair, to ensure that no thread is starved out from
+ * accessing a resource. When using semaphores for other kinds of
+ * synchronization control, the throughput advantages of non-fair
+ * ordering often outweigh fairness considerations.
+ *
+ * <p>This class also provides convenience methods to {@link
+ * #acquire(int) acquire} and {@link #release(int) release} multiple
+ * permits at a time. These methods are generally more efficient and
+ * effective than loops. However, they do not establish any preference
+ * order. For example, if thread A invokes {@code s.acquire(3}) and
+ * thread B invokes {@code s.acquire(2)}, and two permits become
+ * available, then there is no guarantee that thread B will obtain
+ * them unless its acquire came first and Semaphore {@code s} is in
+ * fair mode.
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to calling
+ * a "release" method such as {@code release()}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions following a successful "acquire" method such as {@code acquire()}
+ * in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class Semaphore implements java.io.Serializable {
+    private static final long serialVersionUID = -3222578661600680210L;
+    /** All mechanics via AbstractQueuedSynchronizer subclass */
+    private final Sync sync;
+
+    /**
+     * Synchronization implementation for semaphore.  Uses AQS state
+     * to represent permits. Subclassed into fair and nonfair
+     * versions.
+     */
+    abstract static class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = 1192457210091910933L;
+
+        Sync(int permits) {
+            setState(permits);
+        }
+
+        final int getPermits() {
+            return getState();
+        }
+
+        final int nonfairTryAcquireShared(int acquires) {
+            for (;;) {
+                int available = getState();
+                int remaining = available - acquires;
+                if (remaining < 0 ||
+                    compareAndSetState(available, remaining))
+                    return remaining;
+            }
+        }
+
+        protected final boolean tryReleaseShared(int releases) {
+            for (;;) {
+                int current = getState();
+                int next = current + releases;
+                if (next < current) // overflow
+                    throw new Error("Maximum permit count exceeded");
+                if (compareAndSetState(current, next))
+                    return true;
+            }
+        }
+
+        final void reducePermits(int reductions) {
+            for (;;) {
+                int current = getState();
+                int next = current - reductions;
+                if (next > current) // underflow
+                    throw new Error("Permit count underflow");
+                if (compareAndSetState(current, next))
+                    return;
+            }
+        }
+
+        final int drainPermits() {
+            for (;;) {
+                int current = getState();
+                if (current == 0 || compareAndSetState(current, 0))
+                    return current;
+            }
+        }
+    }
+
+    /**
+     * NonFair version
+     */
+    static final class NonfairSync extends Sync {
+        private static final long serialVersionUID = -2694183684443567898L;
+
+        NonfairSync(int permits) {
+            super(permits);
+        }
+
+        protected int tryAcquireShared(int acquires) {
+            return nonfairTryAcquireShared(acquires);
+        }
+    }
+
+    /**
+     * Fair version
+     */
+    static final class FairSync extends Sync {
+        private static final long serialVersionUID = 2014338818796000944L;
+
+        FairSync(int permits) {
+            super(permits);
+        }
+
+        protected int tryAcquireShared(int acquires) {
+            for (;;) {
+                if (hasQueuedPredecessors())
+                    return -1;
+                int available = getState();
+                int remaining = available - acquires;
+                if (remaining < 0 ||
+                    compareAndSetState(available, remaining))
+                    return remaining;
+            }
+        }
+    }
+
+    /**
+     * Creates a {@code Semaphore} with the given number of
+     * permits and nonfair fairness setting.
+     *
+     * @param permits the initial number of permits available.
+     *        This value may be negative, in which case releases
+     *        must occur before any acquires will be granted.
+     */
+    public Semaphore(int permits) {
+        sync = new NonfairSync(permits);
+    }
+
+    /**
+     * Creates a {@code Semaphore} with the given number of
+     * permits and the given fairness setting.
+     *
+     * @param permits the initial number of permits available.
+     *        This value may be negative, in which case releases
+     *        must occur before any acquires will be granted.
+     * @param fair {@code true} if this semaphore will guarantee
+     *        first-in first-out granting of permits under contention,
+     *        else {@code false}
+     */
+    public Semaphore(int permits, boolean fair) {
+        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
+    }
+
+    /**
+     * Acquires a permit from this semaphore, blocking until one is
+     * available, or the thread is {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of two things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #release} method for this
+     * semaphore and the current thread is next to be assigned a permit; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for a permit,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public void acquire() throws InterruptedException {
+        sync.acquireSharedInterruptibly(1);
+    }
+
+    /**
+     * Acquires a permit from this semaphore, blocking until one is
+     * available.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * some other thread invokes the {@link #release} method for this
+     * semaphore and the current thread is next to be assigned a permit.
+     *
+     * <p>If the current thread is {@linkplain Thread#interrupt interrupted}
+     * while waiting for a permit then it will continue to wait, but the
+     * time at which the thread is assigned a permit may change compared to
+     * the time it would have received the permit had no interruption
+     * occurred.  When the thread does return from this method its interrupt
+     * status will be set.
+     */
+    public void acquireUninterruptibly() {
+        sync.acquireShared(1);
+    }
+
+    /**
+     * Acquires a permit from this semaphore, only if one is available at the
+     * time of invocation.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * with the value {@code true},
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then this method will return
+     * immediately with the value {@code false}.
+     *
+     * <p>Even when this semaphore has been set to use a
+     * fair ordering policy, a call to {@code tryAcquire()} <em>will</em>
+     * immediately acquire a permit if one is available, whether or not
+     * other threads are currently waiting.
+     * This &quot;barging&quot; behavior can be useful in certain
+     * circumstances, even though it breaks fairness. If you want to honor
+     * the fairness setting, then use
+     * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS) }
+     * which is almost equivalent (it also detects interruption).
+     *
+     * @return {@code true} if a permit was acquired and {@code false}
+     *         otherwise
+     */
+    public boolean tryAcquire() {
+        return sync.nonfairTryAcquireShared(1) >= 0;
+    }
+
+    /**
+     * Acquires a permit from this semaphore, if one becomes available
+     * within the given waiting time and the current thread has not
+     * been {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * with the value {@code true},
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of three things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #release} method for this
+     * semaphore and the current thread is next to be assigned a permit; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     *
+     * <p>If a permit is acquired then the value {@code true} is returned.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * to acquire a permit,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.
+     *
+     * @param timeout the maximum time to wait for a permit
+     * @param unit the time unit of the {@code timeout} argument
+     * @return {@code true} if a permit was acquired and {@code false}
+     *         if the waiting time elapsed before a permit was acquired
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public boolean tryAcquire(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
+    }
+
+    /**
+     * Releases a permit, returning it to the semaphore.
+     *
+     * <p>Releases a permit, increasing the number of available permits by
+     * one.  If any threads are trying to acquire a permit, then one is
+     * selected and given the permit that was just released.  That thread
+     * is (re)enabled for thread scheduling purposes.
+     *
+     * <p>There is no requirement that a thread that releases a permit must
+     * have acquired that permit by calling {@link #acquire}.
+     * Correct usage of a semaphore is established by programming convention
+     * in the application.
+     */
+    public void release() {
+        sync.releaseShared(1);
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore,
+     * blocking until all are available,
+     * or the thread is {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the given number of permits, if they are available,
+     * and returns immediately, reducing the number of available permits
+     * by the given amount. This method has the same effect as the
+     * loop {@code for (int i = 0; i < permits; ++i) acquire();} except
+     * that it atomically acquires the permits all at once:
+     *
+     * <p>If insufficient permits are available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of two things happens:
+     * <ul>
+     * <li>Some other thread invokes one of the {@link #release() release}
+     * methods for this semaphore and the current thread is next to be assigned
+     * permits and the number of available permits satisfies this request; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for a permit,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     * Any permits that were to be assigned to this thread are instead
+     * assigned to other threads trying to acquire permits, as if
+     * permits had been made available by a call to {@link #release()}.
+     *
+     * @param permits the number of permits to acquire
+     * @throws InterruptedException if the current thread is interrupted
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public void acquire(int permits) throws InterruptedException {
+        if (permits < 0) throw new IllegalArgumentException();
+        sync.acquireSharedInterruptibly(permits);
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore,
+     * blocking until all are available.
+     *
+     * <p>Acquires the given number of permits, if they are available,
+     * and returns immediately, reducing the number of available permits
+     * by the given amount. This method has the same effect as the
+     * loop {@code for (int i = 0; i < permits; ++i) acquireUninterruptibly();}
+     * except that it atomically acquires the permits all at once:
+     *
+     * <p>If insufficient permits are available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * some other thread invokes one of the {@link #release() release}
+     * methods for this semaphore and the current thread is next to be assigned
+     * permits and the number of available permits satisfies this request.
+     *
+     * <p>If the current thread is {@linkplain Thread#interrupt interrupted}
+     * while waiting for permits then it will continue to wait and its
+     * position in the queue is not affected.  When the thread does return
+     * from this method its interrupt status will be set.
+     *
+     * @param permits the number of permits to acquire
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public void acquireUninterruptibly(int permits) {
+        if (permits < 0) throw new IllegalArgumentException();
+        sync.acquireShared(permits);
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore, only
+     * if all are available at the time of invocation.
+     *
+     * <p>Acquires the given number of permits, if they are available, and
+     * returns immediately, with the value {@code true},
+     * reducing the number of available permits by the given amount.
+     *
+     * <p>If insufficient permits are available then this method will return
+     * immediately with the value {@code false} and the number of available
+     * permits is unchanged.
+     *
+     * <p>Even when this semaphore has been set to use a fair ordering
+     * policy, a call to {@code tryAcquire} <em>will</em>
+     * immediately acquire a permit if one is available, whether or
+     * not other threads are currently waiting.  This
+     * &quot;barging&quot; behavior can be useful in certain
+     * circumstances, even though it breaks fairness. If you want to
+     * honor the fairness setting, then use {@link #tryAcquire(int,
+     * long, TimeUnit) tryAcquire(permits, 0, TimeUnit.SECONDS) }
+     * which is almost equivalent (it also detects interruption).
+     *
+     * @param permits the number of permits to acquire
+     * @return {@code true} if the permits were acquired and
+     *         {@code false} otherwise
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public boolean tryAcquire(int permits) {
+        if (permits < 0) throw new IllegalArgumentException();
+        return sync.nonfairTryAcquireShared(permits) >= 0;
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore, if all
+     * become available within the given waiting time and the current
+     * thread has not been {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the given number of permits, if they are available and
+     * returns immediately, with the value {@code true},
+     * reducing the number of available permits by the given amount.
+     *
+     * <p>If insufficient permits are available then
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     * <ul>
+     * <li>Some other thread invokes one of the {@link #release() release}
+     * methods for this semaphore and the current thread is next to be assigned
+     * permits and the number of available permits satisfies this request; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     *
+     * <p>If the permits are acquired then the value {@code true} is returned.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * to acquire the permits,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     * Any permits that were to be assigned to this thread, are instead
+     * assigned to other threads trying to acquire permits, as if
+     * the permits had been made available by a call to {@link #release()}.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.  Any permits that were to be assigned to this
+     * thread, are instead assigned to other threads trying to acquire
+     * permits, as if the permits had been made available by a call to
+     * {@link #release()}.
+     *
+     * @param permits the number of permits to acquire
+     * @param timeout the maximum time to wait for the permits
+     * @param unit the time unit of the {@code timeout} argument
+     * @return {@code true} if all permits were acquired and {@code false}
+     *         if the waiting time elapsed before all permits were acquired
+     * @throws InterruptedException if the current thread is interrupted
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (permits < 0) throw new IllegalArgumentException();
+        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
+    }
+
+    /**
+     * Releases the given number of permits, returning them to the semaphore.
+     *
+     * <p>Releases the given number of permits, increasing the number of
+     * available permits by that amount.
+     * If any threads are trying to acquire permits, then one thread
+     * is selected and given the permits that were just released.
+     * If the number of available permits satisfies that thread's request
+     * then that thread is (re)enabled for thread scheduling purposes;
+     * otherwise the thread will wait until sufficient permits are available.
+     * If there are still permits available
+     * after this thread's request has been satisfied, then those permits
+     * are assigned in turn to other threads trying to acquire permits.
+     *
+     * <p>There is no requirement that a thread that releases a permit must
+     * have acquired that permit by calling {@link Semaphore#acquire acquire}.
+     * Correct usage of a semaphore is established by programming convention
+     * in the application.
+     *
+     * @param permits the number of permits to release
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public void release(int permits) {
+        if (permits < 0) throw new IllegalArgumentException();
+        sync.releaseShared(permits);
+    }
+
+    /**
+     * Returns the current number of permits available in this semaphore.
+     *
+     * <p>This method is typically used for debugging and testing purposes.
+     *
+     * @return the number of permits available in this semaphore
+     */
+    public int availablePermits() {
+        return sync.getPermits();
+    }
+
+    /**
+     * Acquires and returns all permits that are immediately available.
+     *
+     * @return the number of permits acquired
+     */
+    public int drainPermits() {
+        return sync.drainPermits();
+    }
+
+    /**
+     * Shrinks the number of available permits by the indicated
+     * reduction. This method can be useful in subclasses that use
+     * semaphores to track resources that become unavailable. This
+     * method differs from {@code acquire} in that it does not block
+     * waiting for permits to become available.
+     *
+     * @param reduction the number of permits to remove
+     * @throws IllegalArgumentException if {@code reduction} is negative
+     */
+    protected void reducePermits(int reduction) {
+        if (reduction < 0) throw new IllegalArgumentException();
+        sync.reducePermits(reduction);
+    }
+
+    /**
+     * Returns {@code true} if this semaphore has fairness set true.
+     *
+     * @return {@code true} if this semaphore has fairness set true
+     */
+    public boolean isFair() {
+        return sync instanceof FairSync;
+    }
+
+    /**
+     * Queries whether any threads are waiting to acquire. Note that
+     * because cancellations may occur at any time, a {@code true}
+     * return does not guarantee that any other thread will ever
+     * acquire.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @return {@code true} if there may be other threads waiting to
+     *         acquire the lock
+     */
+    public final boolean hasQueuedThreads() {
+        return sync.hasQueuedThreads();
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting to acquire.
+     * The value is only an estimate because the number of threads may
+     * change dynamically while this method traverses internal data
+     * structures.  This method is designed for use in monitoring
+     * system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting for this lock
+     */
+    public final int getQueueLength() {
+        return sync.getQueueLength();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to acquire.
+     * Because the actual set of threads may change dynamically while
+     * constructing this result, the returned collection is only a best-effort
+     * estimate.  The elements of the returned collection are in no particular
+     * order.  This method is designed to facilitate construction of
+     * subclasses that provide more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedThreads() {
+        return sync.getQueuedThreads();
+    }
+
+    /**
+     * Returns a string identifying this semaphore, as well as its state.
+     * The state, in brackets, includes the String {@code "Permits ="}
+     * followed by the number of permits.
+     *
+     * @return a string identifying this semaphore, as well as its state
+     */
+    public String toString() {
+        return super.toString() + "[Permits = " + sync.getPermits() + "]";
+    }
+}
diff --git a/java/util/concurrent/SynchronousQueue.java b/java/util/concurrent/SynchronousQueue.java
new file mode 100644
index 0000000..9655205
--- /dev/null
+++ b/java/util/concurrent/SynchronousQueue.java
@@ -0,0 +1,1208 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea, Bill Scherer, and Michael Scott with
+ * assistance from members of JCP JSR-166 Expert Group and released to
+ * the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A {@linkplain BlockingQueue blocking queue} in which each insert
+ * operation must wait for a corresponding remove operation by another
+ * thread, and vice versa.  A synchronous queue does not have any
+ * internal capacity, not even a capacity of one.  You cannot
+ * {@code peek} at a synchronous queue because an element is only
+ * present when you try to remove it; you cannot insert an element
+ * (using any method) unless another thread is trying to remove it;
+ * you cannot iterate as there is nothing to iterate.  The
+ * <em>head</em> of the queue is the element that the first queued
+ * inserting thread is trying to add to the queue; if there is no such
+ * queued thread then no element is available for removal and
+ * {@code poll()} will return {@code null}.  For purposes of other
+ * {@code Collection} methods (for example {@code contains}), a
+ * {@code SynchronousQueue} acts as an empty collection.  This queue
+ * does not permit {@code null} elements.
+ *
+ * <p>Synchronous queues are similar to rendezvous channels used in
+ * CSP and Ada. They are well suited for handoff designs, in which an
+ * object running in one thread must sync up with an object running
+ * in another thread in order to hand it some information, event, or
+ * task.
+ *
+ * <p>This class supports an optional fairness policy for ordering
+ * waiting producer and consumer threads.  By default, this ordering
+ * is not guaranteed. However, a queue constructed with fairness set
+ * to {@code true} grants threads access in FIFO order.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * @since 1.5
+ * @author Doug Lea and Bill Scherer and Michael Scott
+ * @param <E> the type of elements held in this queue
+ */
+public class SynchronousQueue<E> extends AbstractQueue<E>
+    implements BlockingQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = -3223113410248163686L;
+
+    /*
+     * This class implements extensions of the dual stack and dual
+     * queue algorithms described in "Nonblocking Concurrent Objects
+     * with Condition Synchronization", by W. N. Scherer III and
+     * M. L. Scott.  18th Annual Conf. on Distributed Computing,
+     * Oct. 2004 (see also
+     * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/duals.html).
+     * The (Lifo) stack is used for non-fair mode, and the (Fifo)
+     * queue for fair mode. The performance of the two is generally
+     * similar. Fifo usually supports higher throughput under
+     * contention but Lifo maintains higher thread locality in common
+     * applications.
+     *
+     * A dual queue (and similarly stack) is one that at any given
+     * time either holds "data" -- items provided by put operations,
+     * or "requests" -- slots representing take operations, or is
+     * empty. A call to "fulfill" (i.e., a call requesting an item
+     * from a queue holding data or vice versa) dequeues a
+     * complementary node.  The most interesting feature of these
+     * queues is that any operation can figure out which mode the
+     * queue is in, and act accordingly without needing locks.
+     *
+     * Both the queue and stack extend abstract class Transferer
+     * defining the single method transfer that does a put or a
+     * take. These are unified into a single method because in dual
+     * data structures, the put and take operations are symmetrical,
+     * so nearly all code can be combined. The resulting transfer
+     * methods are on the long side, but are easier to follow than
+     * they would be if broken up into nearly-duplicated parts.
+     *
+     * The queue and stack data structures share many conceptual
+     * similarities but very few concrete details. For simplicity,
+     * they are kept distinct so that they can later evolve
+     * separately.
+     *
+     * The algorithms here differ from the versions in the above paper
+     * in extending them for use in synchronous queues, as well as
+     * dealing with cancellation. The main differences include:
+     *
+     *  1. The original algorithms used bit-marked pointers, but
+     *     the ones here use mode bits in nodes, leading to a number
+     *     of further adaptations.
+     *  2. SynchronousQueues must block threads waiting to become
+     *     fulfilled.
+     *  3. Support for cancellation via timeout and interrupts,
+     *     including cleaning out cancelled nodes/threads
+     *     from lists to avoid garbage retention and memory depletion.
+     *
+     * Blocking is mainly accomplished using LockSupport park/unpark,
+     * except that nodes that appear to be the next ones to become
+     * fulfilled first spin a bit (on multiprocessors only). On very
+     * busy synchronous queues, spinning can dramatically improve
+     * throughput. And on less busy ones, the amount of spinning is
+     * small enough not to be noticeable.
+     *
+     * Cleaning is done in different ways in queues vs stacks.  For
+     * queues, we can almost always remove a node immediately in O(1)
+     * time (modulo retries for consistency checks) when it is
+     * cancelled. But if it may be pinned as the current tail, it must
+     * wait until some subsequent cancellation. For stacks, we need a
+     * potentially O(n) traversal to be sure that we can remove the
+     * node, but this can run concurrently with other threads
+     * accessing the stack.
+     *
+     * While garbage collection takes care of most node reclamation
+     * issues that otherwise complicate nonblocking algorithms, care
+     * is taken to "forget" references to data, other nodes, and
+     * threads that might be held on to long-term by blocked
+     * threads. In cases where setting to null would otherwise
+     * conflict with main algorithms, this is done by changing a
+     * node's link to now point to the node itself. This doesn't arise
+     * much for Stack nodes (because blocked threads do not hang on to
+     * old head pointers), but references in Queue nodes must be
+     * aggressively forgotten to avoid reachability of everything any
+     * node has ever referred to since arrival.
+     */
+
+    /**
+     * Shared internal API for dual stacks and queues.
+     */
+    abstract static class Transferer<E> {
+        /**
+         * Performs a put or take.
+         *
+         * @param e if non-null, the item to be handed to a consumer;
+         *          if null, requests that transfer return an item
+         *          offered by producer.
+         * @param timed if this operation should timeout
+         * @param nanos the timeout, in nanoseconds
+         * @return if non-null, the item provided or received; if null,
+         *         the operation failed due to timeout or interrupt --
+         *         the caller can distinguish which of these occurred
+         *         by checking Thread.interrupted.
+         */
+        abstract E transfer(E e, boolean timed, long nanos);
+    }
+
+    /**
+     * The number of times to spin before blocking in timed waits.
+     * The value is empirically derived -- it works well across a
+     * variety of processors and OSes. Empirically, the best value
+     * seems not to vary with number of CPUs (beyond 2) so is just
+     * a constant.
+     */
+    static final int MAX_TIMED_SPINS =
+        (Runtime.getRuntime().availableProcessors() < 2) ? 0 : 32;
+
+    /**
+     * The number of times to spin before blocking in untimed waits.
+     * This is greater than timed value because untimed waits spin
+     * faster since they don't need to check times on each spin.
+     */
+    static final int MAX_UNTIMED_SPINS = MAX_TIMED_SPINS * 16;
+
+    /**
+     * The number of nanoseconds for which it is faster to spin
+     * rather than to use timed park. A rough estimate suffices.
+     */
+    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+
+    /** Dual stack */
+    static final class TransferStack<E> extends Transferer<E> {
+        /*
+         * This extends Scherer-Scott dual stack algorithm, differing,
+         * among other ways, by using "covering" nodes rather than
+         * bit-marked pointers: Fulfilling operations push on marker
+         * nodes (with FULFILLING bit set in mode) to reserve a spot
+         * to match a waiting node.
+         */
+
+        /* Modes for SNodes, ORed together in node fields */
+        /** Node represents an unfulfilled consumer */
+        static final int REQUEST    = 0;
+        /** Node represents an unfulfilled producer */
+        static final int DATA       = 1;
+        /** Node is fulfilling another unfulfilled DATA or REQUEST */
+        static final int FULFILLING = 2;
+
+        /** Returns true if m has fulfilling bit set. */
+        static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; }
+
+        /** Node class for TransferStacks. */
+        static final class SNode {
+            volatile SNode next;        // next node in stack
+            volatile SNode match;       // the node matched to this
+            volatile Thread waiter;     // to control park/unpark
+            Object item;                // data; or null for REQUESTs
+            int mode;
+            // Note: item and mode fields don't need to be volatile
+            // since they are always written before, and read after,
+            // other volatile/atomic operations.
+
+            SNode(Object item) {
+                this.item = item;
+            }
+
+            boolean casNext(SNode cmp, SNode val) {
+                return cmp == next &&
+                    U.compareAndSwapObject(this, NEXT, cmp, val);
+            }
+
+            /**
+             * Tries to match node s to this node, if so, waking up thread.
+             * Fulfillers call tryMatch to identify their waiters.
+             * Waiters block until they have been matched.
+             *
+             * @param s the node to match
+             * @return true if successfully matched to s
+             */
+            boolean tryMatch(SNode s) {
+                if (match == null &&
+                    U.compareAndSwapObject(this, MATCH, null, s)) {
+                    Thread w = waiter;
+                    if (w != null) {    // waiters need at most one unpark
+                        waiter = null;
+                        LockSupport.unpark(w);
+                    }
+                    return true;
+                }
+                return match == s;
+            }
+
+            /**
+             * Tries to cancel a wait by matching node to itself.
+             */
+            void tryCancel() {
+                U.compareAndSwapObject(this, MATCH, null, this);
+            }
+
+            boolean isCancelled() {
+                return match == this;
+            }
+
+            // Unsafe mechanics
+            private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+            private static final long MATCH;
+            private static final long NEXT;
+
+            static {
+                try {
+                    MATCH = U.objectFieldOffset
+                        (SNode.class.getDeclaredField("match"));
+                    NEXT = U.objectFieldOffset
+                        (SNode.class.getDeclaredField("next"));
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }
+            }
+        }
+
+        /** The head (top) of the stack */
+        volatile SNode head;
+
+        boolean casHead(SNode h, SNode nh) {
+            return h == head &&
+                U.compareAndSwapObject(this, HEAD, h, nh);
+        }
+
+        /**
+         * Creates or resets fields of a node. Called only from transfer
+         * where the node to push on stack is lazily created and
+         * reused when possible to help reduce intervals between reads
+         * and CASes of head and to avoid surges of garbage when CASes
+         * to push nodes fail due to contention.
+         */
+        static SNode snode(SNode s, Object e, SNode next, int mode) {
+            if (s == null) s = new SNode(e);
+            s.mode = mode;
+            s.next = next;
+            return s;
+        }
+
+        /**
+         * Puts or takes an item.
+         */
+        @SuppressWarnings("unchecked")
+        E transfer(E e, boolean timed, long nanos) {
+            /*
+             * Basic algorithm is to loop trying one of three actions:
+             *
+             * 1. If apparently empty or already containing nodes of same
+             *    mode, try to push node on stack and wait for a match,
+             *    returning it, or null if cancelled.
+             *
+             * 2. If apparently containing node of complementary mode,
+             *    try to push a fulfilling node on to stack, match
+             *    with corresponding waiting node, pop both from
+             *    stack, and return matched item. The matching or
+             *    unlinking might not actually be necessary because of
+             *    other threads performing action 3:
+             *
+             * 3. If top of stack already holds another fulfilling node,
+             *    help it out by doing its match and/or pop
+             *    operations, and then continue. The code for helping
+             *    is essentially the same as for fulfilling, except
+             *    that it doesn't return the item.
+             */
+
+            SNode s = null; // constructed/reused as needed
+            int mode = (e == null) ? REQUEST : DATA;
+
+            for (;;) {
+                SNode h = head;
+                if (h == null || h.mode == mode) {  // empty or same-mode
+                    if (timed && nanos <= 0L) {     // can't wait
+                        if (h != null && h.isCancelled())
+                            casHead(h, h.next);     // pop cancelled node
+                        else
+                            return null;
+                    } else if (casHead(h, s = snode(s, e, h, mode))) {
+                        SNode m = awaitFulfill(s, timed, nanos);
+                        if (m == s) {               // wait was cancelled
+                            clean(s);
+                            return null;
+                        }
+                        if ((h = head) != null && h.next == s)
+                            casHead(h, s.next);     // help s's fulfiller
+                        return (E) ((mode == REQUEST) ? m.item : s.item);
+                    }
+                } else if (!isFulfilling(h.mode)) { // try to fulfill
+                    if (h.isCancelled())            // already cancelled
+                        casHead(h, h.next);         // pop and retry
+                    else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
+                        for (;;) { // loop until matched or waiters disappear
+                            SNode m = s.next;       // m is s's match
+                            if (m == null) {        // all waiters are gone
+                                casHead(s, null);   // pop fulfill node
+                                s = null;           // use new node next time
+                                break;              // restart main loop
+                            }
+                            SNode mn = m.next;
+                            if (m.tryMatch(s)) {
+                                casHead(s, mn);     // pop both s and m
+                                return (E) ((mode == REQUEST) ? m.item : s.item);
+                            } else                  // lost match
+                                s.casNext(m, mn);   // help unlink
+                        }
+                    }
+                } else {                            // help a fulfiller
+                    SNode m = h.next;               // m is h's match
+                    if (m == null)                  // waiter is gone
+                        casHead(h, null);           // pop fulfilling node
+                    else {
+                        SNode mn = m.next;
+                        if (m.tryMatch(h))          // help match
+                            casHead(h, mn);         // pop both h and m
+                        else                        // lost match
+                            h.casNext(m, mn);       // help unlink
+                    }
+                }
+            }
+        }
+
+        /**
+         * Spins/blocks until node s is matched by a fulfill operation.
+         *
+         * @param s the waiting node
+         * @param timed true if timed wait
+         * @param nanos timeout value
+         * @return matched node, or s if cancelled
+         */
+        SNode awaitFulfill(SNode s, boolean timed, long nanos) {
+            /*
+             * When a node/thread is about to block, it sets its waiter
+             * field and then rechecks state at least one more time
+             * before actually parking, thus covering race vs
+             * fulfiller noticing that waiter is non-null so should be
+             * woken.
+             *
+             * When invoked by nodes that appear at the point of call
+             * to be at the head of the stack, calls to park are
+             * preceded by spins to avoid blocking when producers and
+             * consumers are arriving very close in time.  This can
+             * happen enough to bother only on multiprocessors.
+             *
+             * The order of checks for returning out of main loop
+             * reflects fact that interrupts have precedence over
+             * normal returns, which have precedence over
+             * timeouts. (So, on timeout, one last check for match is
+             * done before giving up.) Except that calls from untimed
+             * SynchronousQueue.{poll/offer} don't check interrupts
+             * and don't wait at all, so are trapped in transfer
+             * method rather than calling awaitFulfill.
+             */
+            final long deadline = timed ? System.nanoTime() + nanos : 0L;
+            Thread w = Thread.currentThread();
+            int spins = shouldSpin(s)
+                ? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
+                : 0;
+            for (;;) {
+                if (w.isInterrupted())
+                    s.tryCancel();
+                SNode m = s.match;
+                if (m != null)
+                    return m;
+                if (timed) {
+                    nanos = deadline - System.nanoTime();
+                    if (nanos <= 0L) {
+                        s.tryCancel();
+                        continue;
+                    }
+                }
+                if (spins > 0)
+                    spins = shouldSpin(s) ? (spins - 1) : 0;
+                else if (s.waiter == null)
+                    s.waiter = w; // establish waiter so can park next iter
+                else if (!timed)
+                    LockSupport.park(this);
+                else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanos);
+            }
+        }
+
+        /**
+         * Returns true if node s is at head or there is an active
+         * fulfiller.
+         */
+        boolean shouldSpin(SNode s) {
+            SNode h = head;
+            return (h == s || h == null || isFulfilling(h.mode));
+        }
+
+        /**
+         * Unlinks s from the stack.
+         */
+        void clean(SNode s) {
+            s.item = null;   // forget item
+            s.waiter = null; // forget thread
+
+            /*
+             * At worst we may need to traverse entire stack to unlink
+             * s. If there are multiple concurrent calls to clean, we
+             * might not see s if another thread has already removed
+             * it. But we can stop when we see any node known to
+             * follow s. We use s.next unless it too is cancelled, in
+             * which case we try the node one past. We don't check any
+             * further because we don't want to doubly traverse just to
+             * find sentinel.
+             */
+
+            SNode past = s.next;
+            if (past != null && past.isCancelled())
+                past = past.next;
+
+            // Absorb cancelled nodes at head
+            SNode p;
+            while ((p = head) != null && p != past && p.isCancelled())
+                casHead(p, p.next);
+
+            // Unsplice embedded nodes
+            while (p != null && p != past) {
+                SNode n = p.next;
+                if (n != null && n.isCancelled())
+                    p.casNext(n, n.next);
+                else
+                    p = n;
+            }
+        }
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long HEAD;
+        static {
+            try {
+                HEAD = U.objectFieldOffset
+                    (TransferStack.class.getDeclaredField("head"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /** Dual Queue */
+    static final class TransferQueue<E> extends Transferer<E> {
+        /*
+         * This extends Scherer-Scott dual queue algorithm, differing,
+         * among other ways, by using modes within nodes rather than
+         * marked pointers. The algorithm is a little simpler than
+         * that for stacks because fulfillers do not need explicit
+         * nodes, and matching is done by CAS'ing QNode.item field
+         * from non-null to null (for put) or vice versa (for take).
+         */
+
+        /** Node class for TransferQueue. */
+        static final class QNode {
+            volatile QNode next;          // next node in queue
+            volatile Object item;         // CAS'ed to or from null
+            volatile Thread waiter;       // to control park/unpark
+            final boolean isData;
+
+            QNode(Object item, boolean isData) {
+                this.item = item;
+                this.isData = isData;
+            }
+
+            boolean casNext(QNode cmp, QNode val) {
+                return next == cmp &&
+                    U.compareAndSwapObject(this, NEXT, cmp, val);
+            }
+
+            boolean casItem(Object cmp, Object val) {
+                return item == cmp &&
+                    U.compareAndSwapObject(this, ITEM, cmp, val);
+            }
+
+            /**
+             * Tries to cancel by CAS'ing ref to this as item.
+             */
+            void tryCancel(Object cmp) {
+                U.compareAndSwapObject(this, ITEM, cmp, this);
+            }
+
+            boolean isCancelled() {
+                return item == this;
+            }
+
+            /**
+             * Returns true if this node is known to be off the queue
+             * because its next pointer has been forgotten due to
+             * an advanceHead operation.
+             */
+            boolean isOffList() {
+                return next == this;
+            }
+
+            // Unsafe mechanics
+            private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+            private static final long ITEM;
+            private static final long NEXT;
+
+            static {
+                try {
+                    ITEM = U.objectFieldOffset
+                        (QNode.class.getDeclaredField("item"));
+                    NEXT = U.objectFieldOffset
+                        (QNode.class.getDeclaredField("next"));
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }
+            }
+        }
+
+        /** Head of queue */
+        transient volatile QNode head;
+        /** Tail of queue */
+        transient volatile QNode tail;
+        /**
+         * Reference to a cancelled node that might not yet have been
+         * unlinked from queue because it was the last inserted node
+         * when it was cancelled.
+         */
+        transient volatile QNode cleanMe;
+
+        TransferQueue() {
+            QNode h = new QNode(null, false); // initialize to dummy node.
+            head = h;
+            tail = h;
+        }
+
+        /**
+         * Tries to cas nh as new head; if successful, unlink
+         * old head's next node to avoid garbage retention.
+         */
+        void advanceHead(QNode h, QNode nh) {
+            if (h == head &&
+                U.compareAndSwapObject(this, HEAD, h, nh))
+                h.next = h; // forget old next
+        }
+
+        /**
+         * Tries to cas nt as new tail.
+         */
+        void advanceTail(QNode t, QNode nt) {
+            if (tail == t)
+                U.compareAndSwapObject(this, TAIL, t, nt);
+        }
+
+        /**
+         * Tries to CAS cleanMe slot.
+         */
+        boolean casCleanMe(QNode cmp, QNode val) {
+            return cleanMe == cmp &&
+                U.compareAndSwapObject(this, CLEANME, cmp, val);
+        }
+
+        /**
+         * Puts or takes an item.
+         */
+        @SuppressWarnings("unchecked")
+        E transfer(E e, boolean timed, long nanos) {
+            /* Basic algorithm is to loop trying to take either of
+             * two actions:
+             *
+             * 1. If queue apparently empty or holding same-mode nodes,
+             *    try to add node to queue of waiters, wait to be
+             *    fulfilled (or cancelled) and return matching item.
+             *
+             * 2. If queue apparently contains waiting items, and this
+             *    call is of complementary mode, try to fulfill by CAS'ing
+             *    item field of waiting node and dequeuing it, and then
+             *    returning matching item.
+             *
+             * In each case, along the way, check for and try to help
+             * advance head and tail on behalf of other stalled/slow
+             * threads.
+             *
+             * The loop starts off with a null check guarding against
+             * seeing uninitialized head or tail values. This never
+             * happens in current SynchronousQueue, but could if
+             * callers held non-volatile/final ref to the
+             * transferer. The check is here anyway because it places
+             * null checks at top of loop, which is usually faster
+             * than having them implicitly interspersed.
+             */
+
+            QNode s = null; // constructed/reused as needed
+            boolean isData = (e != null);
+
+            for (;;) {
+                QNode t = tail;
+                QNode h = head;
+                if (t == null || h == null)         // saw uninitialized value
+                    continue;                       // spin
+
+                if (h == t || t.isData == isData) { // empty or same-mode
+                    QNode tn = t.next;
+                    if (t != tail)                  // inconsistent read
+                        continue;
+                    if (tn != null) {               // lagging tail
+                        advanceTail(t, tn);
+                        continue;
+                    }
+                    if (timed && nanos <= 0L)       // can't wait
+                        return null;
+                    if (s == null)
+                        s = new QNode(e, isData);
+                    if (!t.casNext(null, s))        // failed to link in
+                        continue;
+
+                    advanceTail(t, s);              // swing tail and wait
+                    Object x = awaitFulfill(s, e, timed, nanos);
+                    if (x == s) {                   // wait was cancelled
+                        clean(t, s);
+                        return null;
+                    }
+
+                    if (!s.isOffList()) {           // not already unlinked
+                        advanceHead(t, s);          // unlink if head
+                        if (x != null)              // and forget fields
+                            s.item = s;
+                        s.waiter = null;
+                    }
+                    return (x != null) ? (E)x : e;
+
+                } else {                            // complementary-mode
+                    QNode m = h.next;               // node to fulfill
+                    if (t != tail || m == null || h != head)
+                        continue;                   // inconsistent read
+
+                    Object x = m.item;
+                    if (isData == (x != null) ||    // m already fulfilled
+                        x == m ||                   // m cancelled
+                        !m.casItem(x, e)) {         // lost CAS
+                        advanceHead(h, m);          // dequeue and retry
+                        continue;
+                    }
+
+                    advanceHead(h, m);              // successfully fulfilled
+                    LockSupport.unpark(m.waiter);
+                    return (x != null) ? (E)x : e;
+                }
+            }
+        }
+
+        /**
+         * Spins/blocks until node s is fulfilled.
+         *
+         * @param s the waiting node
+         * @param e the comparison value for checking match
+         * @param timed true if timed wait
+         * @param nanos timeout value
+         * @return matched item, or s if cancelled
+         */
+        Object awaitFulfill(QNode s, E e, boolean timed, long nanos) {
+            /* Same idea as TransferStack.awaitFulfill */
+            final long deadline = timed ? System.nanoTime() + nanos : 0L;
+            Thread w = Thread.currentThread();
+            int spins = (head.next == s)
+                ? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
+                : 0;
+            for (;;) {
+                if (w.isInterrupted())
+                    s.tryCancel(e);
+                Object x = s.item;
+                if (x != e)
+                    return x;
+                if (timed) {
+                    nanos = deadline - System.nanoTime();
+                    if (nanos <= 0L) {
+                        s.tryCancel(e);
+                        continue;
+                    }
+                }
+                if (spins > 0)
+                    --spins;
+                else if (s.waiter == null)
+                    s.waiter = w;
+                else if (!timed)
+                    LockSupport.park(this);
+                else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanos);
+            }
+        }
+
+        /**
+         * Gets rid of cancelled node s with original predecessor pred.
+         */
+        void clean(QNode pred, QNode s) {
+            s.waiter = null; // forget thread
+            /*
+             * At any given time, exactly one node on list cannot be
+             * deleted -- the last inserted node. To accommodate this,
+             * if we cannot delete s, we save its predecessor as
+             * "cleanMe", deleting the previously saved version
+             * first. At least one of node s or the node previously
+             * saved can always be deleted, so this always terminates.
+             */
+            while (pred.next == s) { // Return early if already unlinked
+                QNode h = head;
+                QNode hn = h.next;   // Absorb cancelled first node as head
+                if (hn != null && hn.isCancelled()) {
+                    advanceHead(h, hn);
+                    continue;
+                }
+                QNode t = tail;      // Ensure consistent read for tail
+                if (t == h)
+                    return;
+                QNode tn = t.next;
+                if (t != tail)
+                    continue;
+                if (tn != null) {
+                    advanceTail(t, tn);
+                    continue;
+                }
+                if (s != t) {        // If not tail, try to unsplice
+                    QNode sn = s.next;
+                    if (sn == s || pred.casNext(s, sn))
+                        return;
+                }
+                QNode dp = cleanMe;
+                if (dp != null) {    // Try unlinking previous cancelled node
+                    QNode d = dp.next;
+                    QNode dn;
+                    if (d == null ||               // d is gone or
+                        d == dp ||                 // d is off list or
+                        !d.isCancelled() ||        // d not cancelled or
+                        (d != t &&                 // d not tail and
+                         (dn = d.next) != null &&  //   has successor
+                         dn != d &&                //   that is on list
+                         dp.casNext(d, dn)))       // d unspliced
+                        casCleanMe(dp, null);
+                    if (dp == pred)
+                        return;      // s is already saved node
+                } else if (casCleanMe(null, pred))
+                    return;          // Postpone cleaning s
+            }
+        }
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long HEAD;
+        private static final long TAIL;
+        private static final long CLEANME;
+        static {
+            try {
+                HEAD = U.objectFieldOffset
+                    (TransferQueue.class.getDeclaredField("head"));
+                TAIL = U.objectFieldOffset
+                    (TransferQueue.class.getDeclaredField("tail"));
+                CLEANME = U.objectFieldOffset
+                    (TransferQueue.class.getDeclaredField("cleanMe"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /**
+     * The transferer. Set only in constructor, but cannot be declared
+     * as final without further complicating serialization.  Since
+     * this is accessed only at most once per public method, there
+     * isn't a noticeable performance penalty for using volatile
+     * instead of final here.
+     */
+    private transient volatile Transferer<E> transferer;
+
+    /**
+     * Creates a {@code SynchronousQueue} with nonfair access policy.
+     */
+    public SynchronousQueue() {
+        this(false);
+    }
+
+    /**
+     * Creates a {@code SynchronousQueue} with the specified fairness policy.
+     *
+     * @param fair if true, waiting threads contend in FIFO order for
+     *        access; otherwise the order is unspecified.
+     */
+    public SynchronousQueue(boolean fair) {
+        transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
+    }
+
+    /**
+     * Adds the specified element to this queue, waiting if necessary for
+     * another thread to receive it.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        if (transferer.transfer(e, false, 0) == null) {
+            Thread.interrupted();
+            throw new InterruptedException();
+        }
+    }
+
+    /**
+     * Inserts the specified element into this queue, waiting if necessary
+     * up to the specified wait time for another thread to receive it.
+     *
+     * @return {@code true} if successful, or {@code false} if the
+     *         specified waiting time elapses before a consumer appears
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        if (transferer.transfer(e, true, unit.toNanos(timeout)) != null)
+            return true;
+        if (!Thread.interrupted())
+            return false;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Inserts the specified element into this queue, if another thread is
+     * waiting to receive it.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this queue, else
+     *         {@code false}
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null) throw new NullPointerException();
+        return transferer.transfer(e, true, 0) != null;
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * for another thread to insert it.
+     *
+     * @return the head of this queue
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E take() throws InterruptedException {
+        E e = transferer.transfer(null, false, 0);
+        if (e != null)
+            return e;
+        Thread.interrupted();
+        throw new InterruptedException();
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting
+     * if necessary up to the specified wait time, for another thread
+     * to insert it.
+     *
+     * @return the head of this queue, or {@code null} if the
+     *         specified waiting time elapses before an element is present
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        E e = transferer.transfer(null, true, unit.toNanos(timeout));
+        if (e != null || !Thread.interrupted())
+            return e;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, if another thread
+     * is currently making an element available.
+     *
+     * @return the head of this queue, or {@code null} if no
+     *         element is available
+     */
+    public E poll() {
+        return transferer.transfer(null, true, 0);
+    }
+
+    /**
+     * Always returns {@code true}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @return {@code true}
+     */
+    public boolean isEmpty() {
+        return true;
+    }
+
+    /**
+     * Always returns zero.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @return zero
+     */
+    public int size() {
+        return 0;
+    }
+
+    /**
+     * Always returns zero.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @return zero
+     */
+    public int remainingCapacity() {
+        return 0;
+    }
+
+    /**
+     * Does nothing.
+     * A {@code SynchronousQueue} has no internal capacity.
+     */
+    public void clear() {
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param o the element
+     * @return {@code false}
+     */
+    public boolean contains(Object o) {
+        return false;
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param o the element to remove
+     * @return {@code false}
+     */
+    public boolean remove(Object o) {
+        return false;
+    }
+
+    /**
+     * Returns {@code false} unless the given collection is empty.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param c the collection
+     * @return {@code false} unless given collection is empty
+     */
+    public boolean containsAll(Collection<?> c) {
+        return c.isEmpty();
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param c the collection
+     * @return {@code false}
+     */
+    public boolean removeAll(Collection<?> c) {
+        return false;
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param c the collection
+     * @return {@code false}
+     */
+    public boolean retainAll(Collection<?> c) {
+        return false;
+    }
+
+    /**
+     * Always returns {@code null}.
+     * A {@code SynchronousQueue} does not return elements
+     * unless actively waited on.
+     *
+     * @return {@code null}
+     */
+    public E peek() {
+        return null;
+    }
+
+    /**
+     * Returns an empty iterator in which {@code hasNext} always returns
+     * {@code false}.
+     *
+     * @return an empty iterator
+     */
+    public Iterator<E> iterator() {
+        return Collections.emptyIterator();
+    }
+
+    /**
+     * Returns an empty spliterator in which calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return an empty spliterator
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.emptySpliterator();
+    }
+
+    /**
+     * Returns a zero-length array.
+     * @return a zero-length array
+     */
+    public Object[] toArray() {
+        return new Object[0];
+    }
+
+    /**
+     * Sets the zeroth element of the specified array to {@code null}
+     * (if the array has non-zero length) and returns it.
+     *
+     * @param a the array
+     * @return the specified array
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        if (a.length > 0)
+            a[0] = null;
+        return a;
+    }
+
+    /**
+     * Always returns {@code "[]"}.
+     * @return {@code "[]"}
+     */
+    public String toString() {
+        return "[]";
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; (e = poll()) != null;) {
+            c.add(e);
+            ++n;
+        }
+        return n;
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; n < maxElements && (e = poll()) != null;) {
+            c.add(e);
+            ++n;
+        }
+        return n;
+    }
+
+    /*
+     * To cope with serialization strategy in the 1.5 version of
+     * SynchronousQueue, we declare some unused classes and fields
+     * that exist solely to enable serializability across versions.
+     * These fields are never used, so are initialized only if this
+     * object is ever serialized or deserialized.
+     */
+
+    @SuppressWarnings("serial")
+    static class WaitQueue implements java.io.Serializable { }
+    static class LifoWaitQueue extends WaitQueue {
+        private static final long serialVersionUID = -3633113410248163686L;
+    }
+    static class FifoWaitQueue extends WaitQueue {
+        private static final long serialVersionUID = -3623113410248163686L;
+    }
+    private ReentrantLock qlock;
+    private WaitQueue waitingProducers;
+    private WaitQueue waitingConsumers;
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        boolean fair = transferer instanceof TransferQueue;
+        if (fair) {
+            qlock = new ReentrantLock(true);
+            waitingProducers = new FifoWaitQueue();
+            waitingConsumers = new FifoWaitQueue();
+        }
+        else {
+            qlock = new ReentrantLock();
+            waitingProducers = new LifoWaitQueue();
+            waitingConsumers = new LifoWaitQueue();
+        }
+        s.defaultWriteObject();
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        if (waitingProducers instanceof FifoWaitQueue)
+            transferer = new TransferQueue<E>();
+        else
+            transferer = new TransferStack<E>();
+    }
+
+    static {
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/java/util/concurrent/ThreadFactory.java b/java/util/concurrent/ThreadFactory.java
new file mode 100644
index 0000000..ac7afa0
--- /dev/null
+++ b/java/util/concurrent/ThreadFactory.java
@@ -0,0 +1,69 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * An object that creates new threads on demand.  Using thread factories
+ * removes hardwiring of calls to {@link Thread#Thread(Runnable) new Thread},
+ * enabling applications to use special thread subclasses, priorities, etc.
+ *
+ * <p>
+ * The simplest implementation of this interface is just:
+ * <pre> {@code
+ * class SimpleThreadFactory implements ThreadFactory {
+ *   public Thread newThread(Runnable r) {
+ *     return new Thread(r);
+ *   }
+ * }}</pre>
+ *
+ * The {@link Executors#defaultThreadFactory} method provides a more
+ * useful simple implementation, that sets the created thread context
+ * to known values before returning it.
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ThreadFactory {
+
+    /**
+     * Constructs a new {@code Thread}.  Implementations may also initialize
+     * priority, name, daemon status, {@code ThreadGroup}, etc.
+     *
+     * @param r a runnable to be executed by new thread instance
+     * @return constructed thread, or {@code null} if the request to
+     *         create a thread is rejected
+     */
+    Thread newThread(Runnable r);
+}
diff --git a/java/util/concurrent/ThreadLocalRandom.java b/java/util/concurrent/ThreadLocalRandom.java
new file mode 100644
index 0000000..195f8ac
--- /dev/null
+++ b/java/util/concurrent/ThreadLocalRandom.java
@@ -0,0 +1,1073 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.io.ObjectStreamField;
+import java.util.Random;
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.StreamSupport;
+
+/**
+ * A random number generator isolated to the current thread.  Like the
+ * global {@link java.util.Random} generator used by the {@link
+ * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized
+ * with an internally generated seed that may not otherwise be
+ * modified. When applicable, use of {@code ThreadLocalRandom} rather
+ * than shared {@code Random} objects in concurrent programs will
+ * typically encounter much less overhead and contention.  Use of
+ * {@code ThreadLocalRandom} is particularly appropriate when multiple
+ * tasks (for example, each a {@link ForkJoinTask}) use random numbers
+ * in parallel in thread pools.
+ *
+ * <p>Usages of this class should typically be of the form:
+ * {@code ThreadLocalRandom.current().nextX(...)} (where
+ * {@code X} is {@code Int}, {@code Long}, etc).
+ * When all usages are of this form, it is never possible to
+ * accidently share a {@code ThreadLocalRandom} across multiple threads.
+ *
+ * <p>This class also provides additional commonly used bounded random
+ * generation methods.
+ *
+ * <p>Instances of {@code ThreadLocalRandom} are not cryptographically
+ * secure.  Consider instead using {@link java.security.SecureRandom}
+ * in security-sensitive applications. Additionally,
+ * default-constructed instances do not use a cryptographically random
+ * seed unless the {@linkplain System#getProperty system property}
+ * {@code java.util.secureRandomSeed} is set to {@code true}.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public class ThreadLocalRandom extends Random {
+    /*
+     * This class implements the java.util.Random API (and subclasses
+     * Random) using a single static instance that accesses random
+     * number state held in class Thread (primarily, field
+     * threadLocalRandomSeed). In doing so, it also provides a home
+     * for managing package-private utilities that rely on exactly the
+     * same state as needed to maintain the ThreadLocalRandom
+     * instances. We leverage the need for an initialization flag
+     * field to also use it as a "probe" -- a self-adjusting thread
+     * hash used for contention avoidance, as well as a secondary
+     * simpler (xorShift) random seed that is conservatively used to
+     * avoid otherwise surprising users by hijacking the
+     * ThreadLocalRandom sequence.  The dual use is a marriage of
+     * convenience, but is a simple and efficient way of reducing
+     * application-level overhead and footprint of most concurrent
+     * programs.
+     *
+     * Even though this class subclasses java.util.Random, it uses the
+     * same basic algorithm as java.util.SplittableRandom.  (See its
+     * internal documentation for explanations, which are not repeated
+     * here.)  Because ThreadLocalRandoms are not splittable
+     * though, we use only a single 64bit gamma.
+     *
+     * Because this class is in a different package than class Thread,
+     * field access methods use Unsafe to bypass access control rules.
+     * To conform to the requirements of the Random superclass
+     * constructor, the common static ThreadLocalRandom maintains an
+     * "initialized" field for the sake of rejecting user calls to
+     * setSeed while still allowing a call from constructor.  Note
+     * that serialization is completely unnecessary because there is
+     * only a static singleton.  But we generate a serial form
+     * containing "rnd" and "initialized" fields to ensure
+     * compatibility across versions.
+     *
+     * Implementations of non-core methods are mostly the same as in
+     * SplittableRandom, that were in part derived from a previous
+     * version of this class.
+     *
+     * The nextLocalGaussian ThreadLocal supports the very rarely used
+     * nextGaussian method by providing a holder for the second of a
+     * pair of them. As is true for the base class version of this
+     * method, this time/space tradeoff is probably never worthwhile,
+     * but we provide identical statistical properties.
+     */
+
+    private static long mix64(long z) {
+        z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
+        z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
+        return z ^ (z >>> 33);
+    }
+
+    private static int mix32(long z) {
+        z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
+        return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32);
+    }
+
+    /**
+     * Field used only during singleton initialization.
+     * True when constructor completes.
+     */
+    boolean initialized;
+
+    /** Constructor used only for static singleton */
+    private ThreadLocalRandom() {
+        initialized = true; // false during super() call
+    }
+
+    /**
+     * Initialize Thread fields for the current thread.  Called only
+     * when Thread.threadLocalRandomProbe is zero, indicating that a
+     * thread local seed value needs to be generated. Note that even
+     * though the initialization is purely thread-local, we need to
+     * rely on (static) atomic generators to initialize the values.
+     */
+    static final void localInit() {
+        int p = probeGenerator.addAndGet(PROBE_INCREMENT);
+        int probe = (p == 0) ? 1 : p; // skip 0
+        long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
+        Thread t = Thread.currentThread();
+        U.putLong(t, SEED, seed);
+        U.putInt(t, PROBE, probe);
+    }
+
+    /**
+     * Returns the current thread's {@code ThreadLocalRandom}.
+     *
+     * @return the current thread's {@code ThreadLocalRandom}
+     */
+    public static ThreadLocalRandom current() {
+        if (U.getInt(Thread.currentThread(), PROBE) == 0)
+            localInit();
+        return instance;
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}.  Setting seeds in
+     * this generator is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     */
+    public void setSeed(long seed) {
+        // only allow call from super() constructor
+        if (initialized)
+            throw new UnsupportedOperationException();
+    }
+
+    final long nextSeed() {
+        Thread t; long r; // read and update per-thread seed
+        U.putLong(t = Thread.currentThread(), SEED,
+                  r = U.getLong(t, SEED) + GAMMA);
+        return r;
+    }
+
+    // We must define this, but never use it.
+    protected int next(int bits) {
+        return (int)(mix64(nextSeed()) >>> (64 - bits));
+    }
+
+    /**
+     * The form of nextLong used by LongStream Spliterators.  If
+     * origin is greater than bound, acts as unbounded form of
+     * nextLong, else as bounded form.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final long internalNextLong(long origin, long bound) {
+        long r = mix64(nextSeed());
+        if (origin < bound) {
+            long n = bound - origin, m = n - 1;
+            if ((n & m) == 0L)  // power of two
+                r = (r & m) + origin;
+            else if (n > 0L) {  // reject over-represented candidates
+                for (long u = r >>> 1;            // ensure nonnegative
+                     u + m - (r = u % n) < 0L;    // rejection check
+                     u = mix64(nextSeed()) >>> 1) // retry
+                    ;
+                r += origin;
+            }
+            else {              // range not representable as long
+                while (r < origin || r >= bound)
+                    r = mix64(nextSeed());
+            }
+        }
+        return r;
+    }
+
+    /**
+     * The form of nextInt used by IntStream Spliterators.
+     * Exactly the same as long version, except for types.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final int internalNextInt(int origin, int bound) {
+        int r = mix32(nextSeed());
+        if (origin < bound) {
+            int n = bound - origin, m = n - 1;
+            if ((n & m) == 0)
+                r = (r & m) + origin;
+            else if (n > 0) {
+                for (int u = r >>> 1;
+                     u + m - (r = u % n) < 0;
+                     u = mix32(nextSeed()) >>> 1)
+                    ;
+                r += origin;
+            }
+            else {
+                while (r < origin || r >= bound)
+                    r = mix32(nextSeed());
+            }
+        }
+        return r;
+    }
+
+    /**
+     * The form of nextDouble used by DoubleStream Spliterators.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final double internalNextDouble(double origin, double bound) {
+        double r = (nextLong() >>> 11) * DOUBLE_UNIT;
+        if (origin < bound) {
+            r = r * (bound - origin) + origin;
+            if (r >= bound) // correct for rounding
+                r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+        }
+        return r;
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value.
+     *
+     * @return a pseudorandom {@code int} value
+     */
+    public int nextInt() {
+        return mix32(nextSeed());
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value between zero (inclusive)
+     * and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code int} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public int nextInt(int bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BAD_BOUND);
+        int r = mix32(nextSeed());
+        int m = bound - 1;
+        if ((bound & m) == 0) // power of two
+            r &= m;
+        else { // reject over-represented candidates
+            for (int u = r >>> 1;
+                 u + m - (r = u % bound) < 0;
+                 u = mix32(nextSeed()) >>> 1)
+                ;
+        }
+        return r;
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code int} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public int nextInt(int origin, int bound) {
+        if (origin >= bound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextInt(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value.
+     *
+     * @return a pseudorandom {@code long} value
+     */
+    public long nextLong() {
+        return mix64(nextSeed());
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value between zero (inclusive)
+     * and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code long} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public long nextLong(long bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BAD_BOUND);
+        long r = mix64(nextSeed());
+        long m = bound - 1;
+        if ((bound & m) == 0L) // power of two
+            r &= m;
+        else { // reject over-represented candidates
+            for (long u = r >>> 1;
+                 u + m - (r = u % bound) < 0L;
+                 u = mix64(nextSeed()) >>> 1)
+                ;
+        }
+        return r;
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code long} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public long nextLong(long origin, long bound) {
+        if (origin >= bound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextLong(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @return a pseudorandom {@code double} value between zero
+     *         (inclusive) and one (exclusive)
+     */
+    public double nextDouble() {
+        return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT;
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between 0.0
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code double} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public double nextDouble(double bound) {
+        if (!(bound > 0.0))
+            throw new IllegalArgumentException(BAD_BOUND);
+        double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
+        return (result < bound) ? result : // correct for rounding
+            Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between the specified
+     * origin (inclusive) and bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code double} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public double nextDouble(double origin, double bound) {
+        if (!(origin < bound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextDouble(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code boolean} value.
+     *
+     * @return a pseudorandom {@code boolean} value
+     */
+    public boolean nextBoolean() {
+        return mix32(nextSeed()) < 0;
+    }
+
+    /**
+     * Returns a pseudorandom {@code float} value between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @return a pseudorandom {@code float} value between zero
+     *         (inclusive) and one (exclusive)
+     */
+    public float nextFloat() {
+        return (mix32(nextSeed()) >>> 8) * FLOAT_UNIT;
+    }
+
+    public double nextGaussian() {
+        // Use nextLocalGaussian instead of nextGaussian field
+        Double d = nextLocalGaussian.get();
+        if (d != null) {
+            nextLocalGaussian.set(null);
+            return d.doubleValue();
+        }
+        double v1, v2, s;
+        do {
+            v1 = 2 * nextDouble() - 1; // between -1 and 1
+            v2 = 2 * nextDouble() - 1; // between -1 and 1
+            s = v1 * v1 + v2 * v2;
+        } while (s >= 1 || s == 0);
+        double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
+        nextLocalGaussian.set(new Double(v2 * multiplier));
+        return v1 * multiplier;
+    }
+
+    // stream methods, coded in a way intended to better isolate for
+    // maintenance purposes the small differences across forms.
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code int} values.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code int} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public IntStream ints(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, streamSize, Integer.MAX_VALUE, 0),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code int}
+     * values.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code int} values
+     * @since 1.8
+     */
+    public IntStream ints() {
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values, each conforming to the given
+     * origin (inclusive) and bound (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public IntStream ints(long streamSize, int randomNumberOrigin,
+                          int randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * int} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long} values.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code long} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public LongStream longs(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, streamSize, Long.MAX_VALUE, 0L),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code long}
+     * values.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code long} values
+     * @since 1.8
+     */
+    public LongStream longs() {
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long}, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public LongStream longs(long streamSize, long randomNumberOrigin,
+                            long randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of {@code double} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public DoubleStream doubles(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, streamSize, Double.MAX_VALUE, 0.0),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each between zero (inclusive) and one
+     * (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code double} values
+     * @since 1.8
+     */
+    public DoubleStream doubles() {
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public DoubleStream doubles(long streamSize, double randomNumberOrigin,
+                                double randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Spliterator for int streams.  We multiplex the four int
+     * versions into one class by treating a bound less than origin as
+     * unbounded, and also by treating "infinite" as equivalent to
+     * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
+     * approach. The long and double versions of this class are
+     * identical except for types.
+     */
+    private static final class RandomIntsSpliterator
+            implements Spliterator.OfInt {
+        long index;
+        final long fence;
+        final int origin;
+        final int bound;
+        RandomIntsSpliterator(long index, long fence,
+                              int origin, int bound) {
+            this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomIntsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomIntsSpliterator(i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(ThreadLocalRandom.current().internalNextInt(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                int o = origin, b = bound;
+                ThreadLocalRandom rng = ThreadLocalRandom.current();
+                do {
+                    consumer.accept(rng.internalNextInt(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+    /**
+     * Spliterator for long streams.
+     */
+    private static final class RandomLongsSpliterator
+            implements Spliterator.OfLong {
+        long index;
+        final long fence;
+        final long origin;
+        final long bound;
+        RandomLongsSpliterator(long index, long fence,
+                               long origin, long bound) {
+            this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomLongsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomLongsSpliterator(i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(ThreadLocalRandom.current().internalNextLong(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                long o = origin, b = bound;
+                ThreadLocalRandom rng = ThreadLocalRandom.current();
+                do {
+                    consumer.accept(rng.internalNextLong(o, b));
+                } while (++i < f);
+            }
+        }
+
+    }
+
+    /**
+     * Spliterator for double streams.
+     */
+    private static final class RandomDoublesSpliterator
+            implements Spliterator.OfDouble {
+        long index;
+        final long fence;
+        final double origin;
+        final double bound;
+        RandomDoublesSpliterator(long index, long fence,
+                                 double origin, double bound) {
+            this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomDoublesSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomDoublesSpliterator(i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(ThreadLocalRandom.current().internalNextDouble(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                double o = origin, b = bound;
+                ThreadLocalRandom rng = ThreadLocalRandom.current();
+                do {
+                    consumer.accept(rng.internalNextDouble(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+
+    // Within-package utilities
+
+    /*
+     * Descriptions of the usages of the methods below can be found in
+     * the classes that use them. Briefly, a thread's "probe" value is
+     * a non-zero hash code that (probably) does not collide with
+     * other existing threads with respect to any power of two
+     * collision space. When it does collide, it is pseudo-randomly
+     * adjusted (using a Marsaglia XorShift). The nextSecondarySeed
+     * method is used in the same contexts as ThreadLocalRandom, but
+     * only for transient usages such as random adaptive spin/block
+     * sequences for which a cheap RNG suffices and for which it could
+     * in principle disrupt user-visible statistical properties of the
+     * main ThreadLocalRandom if we were to use it.
+     *
+     * Note: Because of package-protection issues, versions of some
+     * these methods also appear in some subpackage classes.
+     */
+
+    /**
+     * Returns the probe value for the current thread without forcing
+     * initialization. Note that invoking ThreadLocalRandom.current()
+     * can be used to force initialization on zero return.
+     */
+    static final int getProbe() {
+        return U.getInt(Thread.currentThread(), PROBE);
+    }
+
+    /**
+     * Pseudo-randomly advances and records the given probe value for the
+     * given thread.
+     */
+    static final int advanceProbe(int probe) {
+        probe ^= probe << 13;   // xorshift
+        probe ^= probe >>> 17;
+        probe ^= probe << 5;
+        U.putInt(Thread.currentThread(), PROBE, probe);
+        return probe;
+    }
+
+    /**
+     * Returns the pseudo-randomly initialized or updated secondary seed.
+     */
+    static final int nextSecondarySeed() {
+        int r;
+        Thread t = Thread.currentThread();
+        if ((r = U.getInt(t, SECONDARY)) != 0) {
+            r ^= r << 13;   // xorshift
+            r ^= r >>> 17;
+            r ^= r << 5;
+        }
+        else if ((r = mix32(seeder.getAndAdd(SEEDER_INCREMENT))) == 0)
+            r = 1; // avoid zero
+        U.putInt(t, SECONDARY, r);
+        return r;
+    }
+
+    // Serialization support
+
+    private static final long serialVersionUID = -5851777807851030925L;
+
+    /**
+     * @serialField rnd long
+     *              seed for random computations
+     * @serialField initialized boolean
+     *              always true
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("rnd", long.class),
+        new ObjectStreamField("initialized", boolean.class),
+    };
+
+    /**
+     * Saves the {@code ThreadLocalRandom} to a stream (that is, serializes it).
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        java.io.ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("rnd", U.getLong(Thread.currentThread(), SEED));
+        fields.put("initialized", true);
+        s.writeFields();
+    }
+
+    /**
+     * Returns the {@link #current() current} thread's {@code ThreadLocalRandom}.
+     * @return the {@link #current() current} thread's {@code ThreadLocalRandom}
+     */
+    private Object readResolve() {
+        return current();
+    }
+
+    // Static initialization
+
+    /**
+     * The seed increment.
+     */
+    private static final long GAMMA = 0x9e3779b97f4a7c15L;
+
+    /**
+     * The increment for generating probe values.
+     */
+    private static final int PROBE_INCREMENT = 0x9e3779b9;
+
+    /**
+     * The increment of seeder per new instance.
+     */
+    private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
+
+    // Constants from SplittableRandom
+    private static final double DOUBLE_UNIT = 0x1.0p-53;  // 1.0  / (1L << 53)
+    private static final float  FLOAT_UNIT  = 0x1.0p-24f; // 1.0f / (1 << 24)
+
+    // IllegalArgumentException messages
+    static final String BAD_BOUND = "bound must be positive";
+    static final String BAD_RANGE = "bound must be greater than origin";
+    static final String BAD_SIZE  = "size must be non-negative";
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long SEED;
+    private static final long PROBE;
+    private static final long SECONDARY;
+    static {
+        try {
+            SEED = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomSeed"));
+            PROBE = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomProbe"));
+            SECONDARY = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    /** Rarely-used holder for the second of a pair of Gaussians */
+    private static final ThreadLocal<Double> nextLocalGaussian =
+        new ThreadLocal<>();
+
+    /** Generates per-thread initialization/probe field */
+    private static final AtomicInteger probeGenerator = new AtomicInteger();
+
+    /** The common ThreadLocalRandom */
+    static final ThreadLocalRandom instance = new ThreadLocalRandom();
+
+    /**
+     * The next seed for default constructors.
+     */
+    private static final AtomicLong seeder
+        = new AtomicLong(mix64(System.currentTimeMillis()) ^
+                         mix64(System.nanoTime()));
+
+    // at end of <clinit> to survive static initialization circularity
+    static {
+        if (java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return Boolean.getBoolean("java.util.secureRandomSeed");
+                }})) {
+            byte[] seedBytes = java.security.SecureRandom.getSeed(8);
+            long s = (long)seedBytes[0] & 0xffL;
+            for (int i = 1; i < 8; ++i)
+                s = (s << 8) | ((long)seedBytes[i] & 0xffL);
+            seeder.set(s);
+        }
+    }
+}
diff --git a/java/util/concurrent/ThreadPoolExecutor.java b/java/util/concurrent/ThreadPoolExecutor.java
new file mode 100644
index 0000000..b0096a4
--- /dev/null
+++ b/java/util/concurrent/ThreadPoolExecutor.java
@@ -0,0 +1,2137 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// removed security manager docs
+// END android-note
+
+/**
+ * An {@link ExecutorService} that executes each submitted task using
+ * one of possibly several pooled threads, normally configured
+ * using {@link Executors} factory methods.
+ *
+ * <p>Thread pools address two different problems: they usually
+ * provide improved performance when executing large numbers of
+ * asynchronous tasks, due to reduced per-task invocation overhead,
+ * and they provide a means of bounding and managing the resources,
+ * including threads, consumed when executing a collection of tasks.
+ * Each {@code ThreadPoolExecutor} also maintains some basic
+ * statistics, such as the number of completed tasks.
+ *
+ * <p>To be useful across a wide range of contexts, this class
+ * provides many adjustable parameters and extensibility
+ * hooks. However, programmers are urged to use the more convenient
+ * {@link Executors} factory methods {@link
+ * Executors#newCachedThreadPool} (unbounded thread pool, with
+ * automatic thread reclamation), {@link Executors#newFixedThreadPool}
+ * (fixed size thread pool) and {@link
+ * Executors#newSingleThreadExecutor} (single background thread), that
+ * preconfigure settings for the most common usage
+ * scenarios. Otherwise, use the following guide when manually
+ * configuring and tuning this class:
+ *
+ * <dl>
+ *
+ * <dt>Core and maximum pool sizes</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * A {@code ThreadPoolExecutor} will automatically adjust the
+ * pool size (see {@link #getPoolSize})
+ * according to the bounds set by
+ * corePoolSize (see {@link #getCorePoolSize}) and
+ * maximumPoolSize (see {@link #getMaximumPoolSize}).
+ *
+ * When a new task is submitted in method {@link #execute(Runnable)},
+ * and fewer than corePoolSize threads are running, a new thread is
+ * created to handle the request, even if other worker threads are
+ * idle.  If there are more than corePoolSize but less than
+ * maximumPoolSize threads running, a new thread will be created only
+ * if the queue is full.  By setting corePoolSize and maximumPoolSize
+ * the same, you create a fixed-size thread pool. By setting
+ * maximumPoolSize to an essentially unbounded value such as {@code
+ * Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary
+ * number of concurrent tasks. Most typically, core and maximum pool
+ * sizes are set only upon construction, but they may also be changed
+ * dynamically using {@link #setCorePoolSize} and {@link
+ * #setMaximumPoolSize}. </dd>
+ *
+ * <dt>On-demand construction</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * By default, even core threads are initially created and
+ * started only when new tasks arrive, but this can be overridden
+ * dynamically using method {@link #prestartCoreThread} or {@link
+ * #prestartAllCoreThreads}.  You probably want to prestart threads if
+ * you construct the pool with a non-empty queue. </dd>
+ *
+ * <dt>Creating new threads</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * New threads are created using a {@link ThreadFactory}.  If not
+ * otherwise specified, a {@link Executors#defaultThreadFactory} is
+ * used, that creates threads to all be in the same {@link
+ * ThreadGroup} and with the same {@code NORM_PRIORITY} priority and
+ * non-daemon status. By supplying a different ThreadFactory, you can
+ * alter the thread's name, thread group, priority, daemon status,
+ * etc. If a {@code ThreadFactory} fails to create a thread when asked
+ * by returning null from {@code newThread}, the executor will
+ * continue, but might not be able to execute any tasks. Threads
+ * should possess the "modifyThread" {@code RuntimePermission}. If
+ * worker threads or other threads using the pool do not possess this
+ * permission, service may be degraded: configuration changes may not
+ * take effect in a timely manner, and a shutdown pool may remain in a
+ * state in which termination is possible but not completed.</dd>
+ *
+ * <dt>Keep-alive times</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * If the pool currently has more than corePoolSize threads,
+ * excess threads will be terminated if they have been idle for more
+ * than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}).
+ * This provides a means of reducing resource consumption when the
+ * pool is not being actively used. If the pool becomes more active
+ * later, new threads will be constructed. This parameter can also be
+ * changed dynamically using method {@link #setKeepAliveTime(long,
+ * TimeUnit)}.  Using a value of {@code Long.MAX_VALUE} {@link
+ * TimeUnit#NANOSECONDS} effectively disables idle threads from ever
+ * terminating prior to shut down. By default, the keep-alive policy
+ * applies only when there are more than corePoolSize threads, but
+ * method {@link #allowCoreThreadTimeOut(boolean)} can be used to
+ * apply this time-out policy to core threads as well, so long as the
+ * keepAliveTime value is non-zero. </dd>
+ *
+ * <dt>Queuing</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * Any {@link BlockingQueue} may be used to transfer and hold
+ * submitted tasks.  The use of this queue interacts with pool sizing:
+ *
+ * <ul>
+ *
+ * <li>If fewer than corePoolSize threads are running, the Executor
+ * always prefers adding a new thread
+ * rather than queuing.
+ *
+ * <li>If corePoolSize or more threads are running, the Executor
+ * always prefers queuing a request rather than adding a new
+ * thread.
+ *
+ * <li>If a request cannot be queued, a new thread is created unless
+ * this would exceed maximumPoolSize, in which case, the task will be
+ * rejected.
+ *
+ * </ul>
+ *
+ * There are three general strategies for queuing:
+ * <ol>
+ *
+ * <li><em> Direct handoffs.</em> A good default choice for a work
+ * queue is a {@link SynchronousQueue} that hands off tasks to threads
+ * without otherwise holding them. Here, an attempt to queue a task
+ * will fail if no threads are immediately available to run it, so a
+ * new thread will be constructed. This policy avoids lockups when
+ * handling sets of requests that might have internal dependencies.
+ * Direct handoffs generally require unbounded maximumPoolSizes to
+ * avoid rejection of new submitted tasks. This in turn admits the
+ * possibility of unbounded thread growth when commands continue to
+ * arrive on average faster than they can be processed.
+ *
+ * <li><em> Unbounded queues.</em> Using an unbounded queue (for
+ * example a {@link LinkedBlockingQueue} without a predefined
+ * capacity) will cause new tasks to wait in the queue when all
+ * corePoolSize threads are busy. Thus, no more than corePoolSize
+ * threads will ever be created. (And the value of the maximumPoolSize
+ * therefore doesn't have any effect.)  This may be appropriate when
+ * each task is completely independent of others, so tasks cannot
+ * affect each others execution; for example, in a web page server.
+ * While this style of queuing can be useful in smoothing out
+ * transient bursts of requests, it admits the possibility of
+ * unbounded work queue growth when commands continue to arrive on
+ * average faster than they can be processed.
+ *
+ * <li><em>Bounded queues.</em> A bounded queue (for example, an
+ * {@link ArrayBlockingQueue}) helps prevent resource exhaustion when
+ * used with finite maximumPoolSizes, but can be more difficult to
+ * tune and control.  Queue sizes and maximum pool sizes may be traded
+ * off for each other: Using large queues and small pools minimizes
+ * CPU usage, OS resources, and context-switching overhead, but can
+ * lead to artificially low throughput.  If tasks frequently block (for
+ * example if they are I/O bound), a system may be able to schedule
+ * time for more threads than you otherwise allow. Use of small queues
+ * generally requires larger pool sizes, which keeps CPUs busier but
+ * may encounter unacceptable scheduling overhead, which also
+ * decreases throughput.
+ *
+ * </ol>
+ *
+ * </dd>
+ *
+ * <dt>Rejected tasks</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * New tasks submitted in method {@link #execute(Runnable)} will be
+ * <em>rejected</em> when the Executor has been shut down, and also when
+ * the Executor uses finite bounds for both maximum threads and work queue
+ * capacity, and is saturated.  In either case, the {@code execute} method
+ * invokes the {@link
+ * RejectedExecutionHandler#rejectedExecution(Runnable, ThreadPoolExecutor)}
+ * method of its {@link RejectedExecutionHandler}.  Four predefined handler
+ * policies are provided:
+ *
+ * <ol>
+ *
+ * <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the
+ * handler throws a runtime {@link RejectedExecutionException} upon
+ * rejection.
+ *
+ * <li>In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
+ * that invokes {@code execute} itself runs the task. This provides a
+ * simple feedback control mechanism that will slow down the rate that
+ * new tasks are submitted.
+ *
+ * <li>In {@link ThreadPoolExecutor.DiscardPolicy}, a task that
+ * cannot be executed is simply dropped.
+ *
+ * <li>In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the
+ * executor is not shut down, the task at the head of the work queue
+ * is dropped, and then execution is retried (which can fail again,
+ * causing this to be repeated.)
+ *
+ * </ol>
+ *
+ * It is possible to define and use other kinds of {@link
+ * RejectedExecutionHandler} classes. Doing so requires some care
+ * especially when policies are designed to work only under particular
+ * capacity or queuing policies. </dd>
+ *
+ * <dt>Hook methods</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * This class provides {@code protected} overridable
+ * {@link #beforeExecute(Thread, Runnable)} and
+ * {@link #afterExecute(Runnable, Throwable)} methods that are called
+ * before and after execution of each task.  These can be used to
+ * manipulate the execution environment; for example, reinitializing
+ * ThreadLocals, gathering statistics, or adding log entries.
+ * Additionally, method {@link #terminated} can be overridden to perform
+ * any special processing that needs to be done once the Executor has
+ * fully terminated.
+ *
+ * <p>If hook, callback, or BlockingQueue methods throw exceptions,
+ * internal worker threads may in turn fail, abruptly terminate, and
+ * possibly be replaced.</dd>
+ *
+ * <dt>Queue maintenance</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * Method {@link #getQueue()} allows access to the work queue
+ * for purposes of monitoring and debugging.  Use of this method for
+ * any other purpose is strongly discouraged.  Two supplied methods,
+ * {@link #remove(Runnable)} and {@link #purge} are available to
+ * assist in storage reclamation when large numbers of queued tasks
+ * become cancelled.</dd>
+ *
+ * <dt>Finalization</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * A pool that is no longer referenced in a program <em>AND</em>
+ * has no remaining threads will be {@code shutdown} automatically. If
+ * you would like to ensure that unreferenced pools are reclaimed even
+ * if users forget to call {@link #shutdown}, then you must arrange
+ * that unused threads eventually die, by setting appropriate
+ * keep-alive times, using a lower bound of zero core threads and/or
+ * setting {@link #allowCoreThreadTimeOut(boolean)}.  </dd>
+ *
+ * </dl>
+ *
+ * <p><b>Extension example</b>. Most extensions of this class
+ * override one or more of the protected hook methods. For example,
+ * here is a subclass that adds a simple pause/resume feature:
+ *
+ * <pre> {@code
+ * class PausableThreadPoolExecutor extends ThreadPoolExecutor {
+ *   private boolean isPaused;
+ *   private ReentrantLock pauseLock = new ReentrantLock();
+ *   private Condition unpaused = pauseLock.newCondition();
+ *
+ *   public PausableThreadPoolExecutor(...) { super(...); }
+ *
+ *   protected void beforeExecute(Thread t, Runnable r) {
+ *     super.beforeExecute(t, r);
+ *     pauseLock.lock();
+ *     try {
+ *       while (isPaused) unpaused.await();
+ *     } catch (InterruptedException ie) {
+ *       t.interrupt();
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ *
+ *   public void pause() {
+ *     pauseLock.lock();
+ *     try {
+ *       isPaused = true;
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ *
+ *   public void resume() {
+ *     pauseLock.lock();
+ *     try {
+ *       isPaused = false;
+ *       unpaused.signalAll();
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ThreadPoolExecutor extends AbstractExecutorService {
+    /**
+     * The main pool control state, ctl, is an atomic integer packing
+     * two conceptual fields
+     *   workerCount, indicating the effective number of threads
+     *   runState,    indicating whether running, shutting down etc
+     *
+     * In order to pack them into one int, we limit workerCount to
+     * (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2
+     * billion) otherwise representable. If this is ever an issue in
+     * the future, the variable can be changed to be an AtomicLong,
+     * and the shift/mask constants below adjusted. But until the need
+     * arises, this code is a bit faster and simpler using an int.
+     *
+     * The workerCount is the number of workers that have been
+     * permitted to start and not permitted to stop.  The value may be
+     * transiently different from the actual number of live threads,
+     * for example when a ThreadFactory fails to create a thread when
+     * asked, and when exiting threads are still performing
+     * bookkeeping before terminating. The user-visible pool size is
+     * reported as the current size of the workers set.
+     *
+     * The runState provides the main lifecycle control, taking on values:
+     *
+     *   RUNNING:  Accept new tasks and process queued tasks
+     *   SHUTDOWN: Don't accept new tasks, but process queued tasks
+     *   STOP:     Don't accept new tasks, don't process queued tasks,
+     *             and interrupt in-progress tasks
+     *   TIDYING:  All tasks have terminated, workerCount is zero,
+     *             the thread transitioning to state TIDYING
+     *             will run the terminated() hook method
+     *   TERMINATED: terminated() has completed
+     *
+     * The numerical order among these values matters, to allow
+     * ordered comparisons. The runState monotonically increases over
+     * time, but need not hit each state. The transitions are:
+     *
+     * RUNNING -> SHUTDOWN
+     *    On invocation of shutdown(), perhaps implicitly in finalize()
+     * (RUNNING or SHUTDOWN) -> STOP
+     *    On invocation of shutdownNow()
+     * SHUTDOWN -> TIDYING
+     *    When both queue and pool are empty
+     * STOP -> TIDYING
+     *    When pool is empty
+     * TIDYING -> TERMINATED
+     *    When the terminated() hook method has completed
+     *
+     * Threads waiting in awaitTermination() will return when the
+     * state reaches TERMINATED.
+     *
+     * Detecting the transition from SHUTDOWN to TIDYING is less
+     * straightforward than you'd like because the queue may become
+     * empty after non-empty and vice versa during SHUTDOWN state, but
+     * we can only terminate if, after seeing that it is empty, we see
+     * that workerCount is 0 (which sometimes entails a recheck -- see
+     * below).
+     */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
+    private static final int COUNT_BITS = Integer.SIZE - 3;
+    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
+
+    // runState is stored in the high-order bits
+    private static final int RUNNING    = -1 << COUNT_BITS;
+    private static final int SHUTDOWN   =  0 << COUNT_BITS;
+    private static final int STOP       =  1 << COUNT_BITS;
+    private static final int TIDYING    =  2 << COUNT_BITS;
+    private static final int TERMINATED =  3 << COUNT_BITS;
+
+    // Packing and unpacking ctl
+    private static int runStateOf(int c)     { return c & ~CAPACITY; }
+    private static int workerCountOf(int c)  { return c & CAPACITY; }
+    private static int ctlOf(int rs, int wc) { return rs | wc; }
+
+    /*
+     * Bit field accessors that don't require unpacking ctl.
+     * These depend on the bit layout and on workerCount being never negative.
+     */
+
+    private static boolean runStateLessThan(int c, int s) {
+        return c < s;
+    }
+
+    private static boolean runStateAtLeast(int c, int s) {
+        return c >= s;
+    }
+
+    private static boolean isRunning(int c) {
+        return c < SHUTDOWN;
+    }
+
+    /**
+     * Attempts to CAS-increment the workerCount field of ctl.
+     */
+    private boolean compareAndIncrementWorkerCount(int expect) {
+        return ctl.compareAndSet(expect, expect + 1);
+    }
+
+    /**
+     * Attempts to CAS-decrement the workerCount field of ctl.
+     */
+    private boolean compareAndDecrementWorkerCount(int expect) {
+        return ctl.compareAndSet(expect, expect - 1);
+    }
+
+    /**
+     * Decrements the workerCount field of ctl. This is called only on
+     * abrupt termination of a thread (see processWorkerExit). Other
+     * decrements are performed within getTask.
+     */
+    private void decrementWorkerCount() {
+        do {} while (! compareAndDecrementWorkerCount(ctl.get()));
+    }
+
+    /**
+     * The queue used for holding tasks and handing off to worker
+     * threads.  We do not require that workQueue.poll() returning
+     * null necessarily means that workQueue.isEmpty(), so rely
+     * solely on isEmpty to see if the queue is empty (which we must
+     * do for example when deciding whether to transition from
+     * SHUTDOWN to TIDYING).  This accommodates special-purpose
+     * queues such as DelayQueues for which poll() is allowed to
+     * return null even if it may later return non-null when delays
+     * expire.
+     */
+    private final BlockingQueue<Runnable> workQueue;
+
+    /**
+     * Lock held on access to workers set and related bookkeeping.
+     * While we could use a concurrent set of some sort, it turns out
+     * to be generally preferable to use a lock. Among the reasons is
+     * that this serializes interruptIdleWorkers, which avoids
+     * unnecessary interrupt storms, especially during shutdown.
+     * Otherwise exiting threads would concurrently interrupt those
+     * that have not yet interrupted. It also simplifies some of the
+     * associated statistics bookkeeping of largestPoolSize etc. We
+     * also hold mainLock on shutdown and shutdownNow, for the sake of
+     * ensuring workers set is stable while separately checking
+     * permission to interrupt and actually interrupting.
+     */
+    private final ReentrantLock mainLock = new ReentrantLock();
+
+    /**
+     * Set containing all worker threads in pool. Accessed only when
+     * holding mainLock.
+     */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private final HashSet<Worker> workers = new HashSet<>();
+
+    /**
+     * Wait condition to support awaitTermination.
+     */
+    private final Condition termination = mainLock.newCondition();
+
+    /**
+     * Tracks largest attained pool size. Accessed only under
+     * mainLock.
+     */
+    private int largestPoolSize;
+
+    /**
+     * Counter for completed tasks. Updated only on termination of
+     * worker threads. Accessed only under mainLock.
+     */
+    private long completedTaskCount;
+
+    /*
+     * All user control parameters are declared as volatiles so that
+     * ongoing actions are based on freshest values, but without need
+     * for locking, since no internal invariants depend on them
+     * changing synchronously with respect to other actions.
+     */
+
+    /**
+     * Factory for new threads. All threads are created using this
+     * factory (via method addWorker).  All callers must be prepared
+     * for addWorker to fail, which may reflect a system or user's
+     * policy limiting the number of threads.  Even though it is not
+     * treated as an error, failure to create threads may result in
+     * new tasks being rejected or existing ones remaining stuck in
+     * the queue.
+     *
+     * We go further and preserve pool invariants even in the face of
+     * errors such as OutOfMemoryError, that might be thrown while
+     * trying to create threads.  Such errors are rather common due to
+     * the need to allocate a native stack in Thread.start, and users
+     * will want to perform clean pool shutdown to clean up.  There
+     * will likely be enough memory available for the cleanup code to
+     * complete without encountering yet another OutOfMemoryError.
+     */
+    private volatile ThreadFactory threadFactory;
+
+    /**
+     * Handler called when saturated or shutdown in execute.
+     */
+    private volatile RejectedExecutionHandler handler;
+
+    /**
+     * Timeout in nanoseconds for idle threads waiting for work.
+     * Threads use this timeout when there are more than corePoolSize
+     * present or if allowCoreThreadTimeOut. Otherwise they wait
+     * forever for new work.
+     */
+    private volatile long keepAliveTime;
+
+    /**
+     * If false (default), core threads stay alive even when idle.
+     * If true, core threads use keepAliveTime to time out waiting
+     * for work.
+     */
+    private volatile boolean allowCoreThreadTimeOut;
+
+    /**
+     * Core pool size is the minimum number of workers to keep alive
+     * (and not allow to time out etc) unless allowCoreThreadTimeOut
+     * is set, in which case the minimum is zero.
+     */
+    private volatile int corePoolSize;
+
+    /**
+     * Maximum pool size. Note that the actual maximum is internally
+     * bounded by CAPACITY.
+     */
+    private volatile int maximumPoolSize;
+
+    /**
+     * The default rejected execution handler.
+     */
+    private static final RejectedExecutionHandler defaultHandler =
+        new AbortPolicy();
+
+    /**
+     * Permission required for callers of shutdown and shutdownNow.
+     * We additionally require (see checkShutdownAccess) that callers
+     * have permission to actually interrupt threads in the worker set
+     * (as governed by Thread.interrupt, which relies on
+     * ThreadGroup.checkAccess, which in turn relies on
+     * SecurityManager.checkAccess). Shutdowns are attempted only if
+     * these checks pass.
+     *
+     * All actual invocations of Thread.interrupt (see
+     * interruptIdleWorkers and interruptWorkers) ignore
+     * SecurityExceptions, meaning that the attempted interrupts
+     * silently fail. In the case of shutdown, they should not fail
+     * unless the SecurityManager has inconsistent policies, sometimes
+     * allowing access to a thread and sometimes not. In such cases,
+     * failure to actually interrupt threads may disable or delay full
+     * termination. Other uses of interruptIdleWorkers are advisory,
+     * and failure to actually interrupt will merely delay response to
+     * configuration changes so is not handled exceptionally.
+     */
+    private static final RuntimePermission shutdownPerm =
+        new RuntimePermission("modifyThread");
+
+    /**
+     * Class Worker mainly maintains interrupt control state for
+     * threads running tasks, along with other minor bookkeeping.
+     * This class opportunistically extends AbstractQueuedSynchronizer
+     * to simplify acquiring and releasing a lock surrounding each
+     * task execution.  This protects against interrupts that are
+     * intended to wake up a worker thread waiting for a task from
+     * instead interrupting a task being run.  We implement a simple
+     * non-reentrant mutual exclusion lock rather than use
+     * ReentrantLock because we do not want worker tasks to be able to
+     * reacquire the lock when they invoke pool control methods like
+     * setCorePoolSize.  Additionally, to suppress interrupts until
+     * the thread actually starts running tasks, we initialize lock
+     * state to a negative value, and clear it upon start (in
+     * runWorker).
+     */
+    private final class Worker
+        extends AbstractQueuedSynchronizer
+        implements Runnable
+    {
+        /**
+         * This class will never be serialized, but we provide a
+         * serialVersionUID to suppress a javac warning.
+         */
+        private static final long serialVersionUID = 6138294804551838833L;
+
+        /** Thread this worker is running in.  Null if factory fails. */
+        final Thread thread;
+        /** Initial task to run.  Possibly null. */
+        Runnable firstTask;
+        /** Per-thread task counter */
+        volatile long completedTasks;
+
+        /**
+         * Creates with given first task and thread from ThreadFactory.
+         * @param firstTask the first task (null if none)
+         */
+        Worker(Runnable firstTask) {
+            setState(-1); // inhibit interrupts until runWorker
+            this.firstTask = firstTask;
+            this.thread = getThreadFactory().newThread(this);
+        }
+
+        /** Delegates main run loop to outer runWorker. */
+        public void run() {
+            runWorker(this);
+        }
+
+        // Lock methods
+        //
+        // The value 0 represents the unlocked state.
+        // The value 1 represents the locked state.
+
+        protected boolean isHeldExclusively() {
+            return getState() != 0;
+        }
+
+        protected boolean tryAcquire(int unused) {
+            if (compareAndSetState(0, 1)) {
+                setExclusiveOwnerThread(Thread.currentThread());
+                return true;
+            }
+            return false;
+        }
+
+        protected boolean tryRelease(int unused) {
+            setExclusiveOwnerThread(null);
+            setState(0);
+            return true;
+        }
+
+        public void lock()        { acquire(1); }
+        public boolean tryLock()  { return tryAcquire(1); }
+        public void unlock()      { release(1); }
+        public boolean isLocked() { return isHeldExclusively(); }
+
+        void interruptIfStarted() {
+            Thread t;
+            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
+                try {
+                    t.interrupt();
+                } catch (SecurityException ignore) {
+                }
+            }
+        }
+    }
+
+    /*
+     * Methods for setting control state
+     */
+
+    /**
+     * Transitions runState to given target, or leaves it alone if
+     * already at least the given target.
+     *
+     * @param targetState the desired state, either SHUTDOWN or STOP
+     *        (but not TIDYING or TERMINATED -- use tryTerminate for that)
+     */
+    private void advanceRunState(int targetState) {
+        // assert targetState == SHUTDOWN || targetState == STOP;
+        for (;;) {
+            int c = ctl.get();
+            if (runStateAtLeast(c, targetState) ||
+                ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
+                break;
+        }
+    }
+
+    /**
+     * Transitions to TERMINATED state if either (SHUTDOWN and pool
+     * and queue empty) or (STOP and pool empty).  If otherwise
+     * eligible to terminate but workerCount is nonzero, interrupts an
+     * idle worker to ensure that shutdown signals propagate. This
+     * method must be called following any action that might make
+     * termination possible -- reducing worker count or removing tasks
+     * from the queue during shutdown. The method is non-private to
+     * allow access from ScheduledThreadPoolExecutor.
+     */
+    final void tryTerminate() {
+        for (;;) {
+            int c = ctl.get();
+            if (isRunning(c) ||
+                runStateAtLeast(c, TIDYING) ||
+                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
+                return;
+            if (workerCountOf(c) != 0) { // Eligible to terminate
+                interruptIdleWorkers(ONLY_ONE);
+                return;
+            }
+
+            final ReentrantLock mainLock = this.mainLock;
+            mainLock.lock();
+            try {
+                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
+                    try {
+                        terminated();
+                    } finally {
+                        ctl.set(ctlOf(TERMINATED, 0));
+                        termination.signalAll();
+                    }
+                    return;
+                }
+            } finally {
+                mainLock.unlock();
+            }
+            // else retry on failed CAS
+        }
+    }
+
+    /*
+     * Methods for controlling interrupts to worker threads.
+     */
+
+    /**
+     * If there is a security manager, makes sure caller has
+     * permission to shut down threads in general (see shutdownPerm).
+     * If this passes, additionally makes sure the caller is allowed
+     * to interrupt each worker thread. This might not be true even if
+     * first check passed, if the SecurityManager treats some threads
+     * specially.
+     */
+    private void checkShutdownAccess() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(shutdownPerm);
+            final ReentrantLock mainLock = this.mainLock;
+            mainLock.lock();
+            try {
+                for (Worker w : workers)
+                    security.checkAccess(w.thread);
+            } finally {
+                mainLock.unlock();
+            }
+        }
+    }
+
+    /**
+     * Interrupts all threads, even if active. Ignores SecurityExceptions
+     * (in which case some threads may remain uninterrupted).
+     */
+    private void interruptWorkers() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            for (Worker w : workers)
+                w.interruptIfStarted();
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Interrupts threads that might be waiting for tasks (as
+     * indicated by not being locked) so they can check for
+     * termination or configuration changes. Ignores
+     * SecurityExceptions (in which case some threads may remain
+     * uninterrupted).
+     *
+     * @param onlyOne If true, interrupt at most one worker. This is
+     * called only from tryTerminate when termination is otherwise
+     * enabled but there are still other workers.  In this case, at
+     * most one waiting worker is interrupted to propagate shutdown
+     * signals in case all threads are currently waiting.
+     * Interrupting any arbitrary thread ensures that newly arriving
+     * workers since shutdown began will also eventually exit.
+     * To guarantee eventual termination, it suffices to always
+     * interrupt only one idle worker, but shutdown() interrupts all
+     * idle workers so that redundant workers exit promptly, not
+     * waiting for a straggler task to finish.
+     */
+    private void interruptIdleWorkers(boolean onlyOne) {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            for (Worker w : workers) {
+                Thread t = w.thread;
+                if (!t.isInterrupted() && w.tryLock()) {
+                    try {
+                        t.interrupt();
+                    } catch (SecurityException ignore) {
+                    } finally {
+                        w.unlock();
+                    }
+                }
+                if (onlyOne)
+                    break;
+            }
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Common form of interruptIdleWorkers, to avoid having to
+     * remember what the boolean argument means.
+     */
+    private void interruptIdleWorkers() {
+        interruptIdleWorkers(false);
+    }
+
+    private static final boolean ONLY_ONE = true;
+
+    /*
+     * Misc utilities, most of which are also exported to
+     * ScheduledThreadPoolExecutor
+     */
+
+    /**
+     * Invokes the rejected execution handler for the given command.
+     * Package-protected for use by ScheduledThreadPoolExecutor.
+     */
+    final void reject(Runnable command) {
+        handler.rejectedExecution(command, this);
+    }
+
+    /**
+     * Performs any further cleanup following run state transition on
+     * invocation of shutdown.  A no-op here, but used by
+     * ScheduledThreadPoolExecutor to cancel delayed tasks.
+     */
+    void onShutdown() {
+    }
+
+    /**
+     * State check needed by ScheduledThreadPoolExecutor to
+     * enable running tasks during shutdown.
+     *
+     * @param shutdownOK true if should return true if SHUTDOWN
+     */
+    final boolean isRunningOrShutdown(boolean shutdownOK) {
+        int rs = runStateOf(ctl.get());
+        return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
+    }
+
+    /**
+     * Drains the task queue into a new list, normally using
+     * drainTo. But if the queue is a DelayQueue or any other kind of
+     * queue for which poll or drainTo may fail to remove some
+     * elements, it deletes them one by one.
+     */
+    private List<Runnable> drainQueue() {
+        BlockingQueue<Runnable> q = workQueue;
+        ArrayList<Runnable> taskList = new ArrayList<>();
+        q.drainTo(taskList);
+        if (!q.isEmpty()) {
+            for (Runnable r : q.toArray(new Runnable[0])) {
+                if (q.remove(r))
+                    taskList.add(r);
+            }
+        }
+        return taskList;
+    }
+
+    /*
+     * Methods for creating, running and cleaning up after workers
+     */
+
+    /**
+     * Checks if a new worker can be added with respect to current
+     * pool state and the given bound (either core or maximum). If so,
+     * the worker count is adjusted accordingly, and, if possible, a
+     * new worker is created and started, running firstTask as its
+     * first task. This method returns false if the pool is stopped or
+     * eligible to shut down. It also returns false if the thread
+     * factory fails to create a thread when asked.  If the thread
+     * creation fails, either due to the thread factory returning
+     * null, or due to an exception (typically OutOfMemoryError in
+     * Thread.start()), we roll back cleanly.
+     *
+     * @param firstTask the task the new thread should run first (or
+     * null if none). Workers are created with an initial first task
+     * (in method execute()) to bypass queuing when there are fewer
+     * than corePoolSize threads (in which case we always start one),
+     * or when the queue is full (in which case we must bypass queue).
+     * Initially idle threads are usually created via
+     * prestartCoreThread or to replace other dying workers.
+     *
+     * @param core if true use corePoolSize as bound, else
+     * maximumPoolSize. (A boolean indicator is used here rather than a
+     * value to ensure reads of fresh values after checking other pool
+     * state).
+     * @return true if successful
+     */
+    private boolean addWorker(Runnable firstTask, boolean core) {
+        retry:
+        for (;;) {
+            int c = ctl.get();
+            int rs = runStateOf(c);
+
+            // Check if queue empty only if necessary.
+            if (rs >= SHUTDOWN &&
+                ! (rs == SHUTDOWN &&
+                   firstTask == null &&
+                   ! workQueue.isEmpty()))
+                return false;
+
+            for (;;) {
+                int wc = workerCountOf(c);
+                if (wc >= CAPACITY ||
+                    wc >= (core ? corePoolSize : maximumPoolSize))
+                    return false;
+                if (compareAndIncrementWorkerCount(c))
+                    break retry;
+                c = ctl.get();  // Re-read ctl
+                if (runStateOf(c) != rs)
+                    continue retry;
+                // else CAS failed due to workerCount change; retry inner loop
+            }
+        }
+
+        boolean workerStarted = false;
+        boolean workerAdded = false;
+        Worker w = null;
+        try {
+            w = new Worker(firstTask);
+            final Thread t = w.thread;
+            if (t != null) {
+                final ReentrantLock mainLock = this.mainLock;
+                mainLock.lock();
+                try {
+                    // Recheck while holding lock.
+                    // Back out on ThreadFactory failure or if
+                    // shut down before lock acquired.
+                    int rs = runStateOf(ctl.get());
+
+                    if (rs < SHUTDOWN ||
+                        (rs == SHUTDOWN && firstTask == null)) {
+                        if (t.isAlive()) // precheck that t is startable
+                            throw new IllegalThreadStateException();
+                        workers.add(w);
+                        int s = workers.size();
+                        if (s > largestPoolSize)
+                            largestPoolSize = s;
+                        workerAdded = true;
+                    }
+                } finally {
+                    mainLock.unlock();
+                }
+                if (workerAdded) {
+                    t.start();
+                    workerStarted = true;
+                }
+            }
+        } finally {
+            if (! workerStarted)
+                addWorkerFailed(w);
+        }
+        return workerStarted;
+    }
+
+    /**
+     * Rolls back the worker thread creation.
+     * - removes worker from workers, if present
+     * - decrements worker count
+     * - rechecks for termination, in case the existence of this
+     *   worker was holding up termination
+     */
+    private void addWorkerFailed(Worker w) {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            if (w != null)
+                workers.remove(w);
+            decrementWorkerCount();
+            tryTerminate();
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Performs cleanup and bookkeeping for a dying worker. Called
+     * only from worker threads. Unless completedAbruptly is set,
+     * assumes that workerCount has already been adjusted to account
+     * for exit.  This method removes thread from worker set, and
+     * possibly terminates the pool or replaces the worker if either
+     * it exited due to user task exception or if fewer than
+     * corePoolSize workers are running or queue is non-empty but
+     * there are no workers.
+     *
+     * @param w the worker
+     * @param completedAbruptly if the worker died due to user exception
+     */
+    private void processWorkerExit(Worker w, boolean completedAbruptly) {
+        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
+            decrementWorkerCount();
+
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            completedTaskCount += w.completedTasks;
+            workers.remove(w);
+        } finally {
+            mainLock.unlock();
+        }
+
+        tryTerminate();
+
+        int c = ctl.get();
+        if (runStateLessThan(c, STOP)) {
+            if (!completedAbruptly) {
+                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
+                if (min == 0 && ! workQueue.isEmpty())
+                    min = 1;
+                if (workerCountOf(c) >= min)
+                    return; // replacement not needed
+            }
+            addWorker(null, false);
+        }
+    }
+
+    /**
+     * Performs blocking or timed wait for a task, depending on
+     * current configuration settings, or returns null if this worker
+     * must exit because of any of:
+     * 1. There are more than maximumPoolSize workers (due to
+     *    a call to setMaximumPoolSize).
+     * 2. The pool is stopped.
+     * 3. The pool is shutdown and the queue is empty.
+     * 4. This worker timed out waiting for a task, and timed-out
+     *    workers are subject to termination (that is,
+     *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
+     *    both before and after the timed wait, and if the queue is
+     *    non-empty, this worker is not the last thread in the pool.
+     *
+     * @return task, or null if the worker must exit, in which case
+     *         workerCount is decremented
+     */
+    private Runnable getTask() {
+        boolean timedOut = false; // Did the last poll() time out?
+
+        for (;;) {
+            int c = ctl.get();
+            int rs = runStateOf(c);
+
+            // Check if queue empty only if necessary.
+            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+                decrementWorkerCount();
+                return null;
+            }
+
+            int wc = workerCountOf(c);
+
+            // Are workers subject to culling?
+            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
+
+            if ((wc > maximumPoolSize || (timed && timedOut))
+                && (wc > 1 || workQueue.isEmpty())) {
+                if (compareAndDecrementWorkerCount(c))
+                    return null;
+                continue;
+            }
+
+            try {
+                Runnable r = timed ?
+                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
+                    workQueue.take();
+                if (r != null)
+                    return r;
+                timedOut = true;
+            } catch (InterruptedException retry) {
+                timedOut = false;
+            }
+        }
+    }
+
+    /**
+     * Main worker run loop.  Repeatedly gets tasks from queue and
+     * executes them, while coping with a number of issues:
+     *
+     * 1. We may start out with an initial task, in which case we
+     * don't need to get the first one. Otherwise, as long as pool is
+     * running, we get tasks from getTask. If it returns null then the
+     * worker exits due to changed pool state or configuration
+     * parameters.  Other exits result from exception throws in
+     * external code, in which case completedAbruptly holds, which
+     * usually leads processWorkerExit to replace this thread.
+     *
+     * 2. Before running any task, the lock is acquired to prevent
+     * other pool interrupts while the task is executing, and then we
+     * ensure that unless pool is stopping, this thread does not have
+     * its interrupt set.
+     *
+     * 3. Each task run is preceded by a call to beforeExecute, which
+     * might throw an exception, in which case we cause thread to die
+     * (breaking loop with completedAbruptly true) without processing
+     * the task.
+     *
+     * 4. Assuming beforeExecute completes normally, we run the task,
+     * gathering any of its thrown exceptions to send to afterExecute.
+     * We separately handle RuntimeException, Error (both of which the
+     * specs guarantee that we trap) and arbitrary Throwables.
+     * Because we cannot rethrow Throwables within Runnable.run, we
+     * wrap them within Errors on the way out (to the thread's
+     * UncaughtExceptionHandler).  Any thrown exception also
+     * conservatively causes thread to die.
+     *
+     * 5. After task.run completes, we call afterExecute, which may
+     * also throw an exception, which will also cause thread to
+     * die. According to JLS Sec 14.20, this exception is the one that
+     * will be in effect even if task.run throws.
+     *
+     * The net effect of the exception mechanics is that afterExecute
+     * and the thread's UncaughtExceptionHandler have as accurate
+     * information as we can provide about any problems encountered by
+     * user code.
+     *
+     * @param w the worker
+     */
+    final void runWorker(Worker w) {
+        Thread wt = Thread.currentThread();
+        Runnable task = w.firstTask;
+        w.firstTask = null;
+        w.unlock(); // allow interrupts
+        boolean completedAbruptly = true;
+        try {
+            while (task != null || (task = getTask()) != null) {
+                w.lock();
+                // If pool is stopping, ensure thread is interrupted;
+                // if not, ensure thread is not interrupted.  This
+                // requires a recheck in second case to deal with
+                // shutdownNow race while clearing interrupt
+                if ((runStateAtLeast(ctl.get(), STOP) ||
+                     (Thread.interrupted() &&
+                      runStateAtLeast(ctl.get(), STOP))) &&
+                    !wt.isInterrupted())
+                    wt.interrupt();
+                try {
+                    beforeExecute(wt, task);
+                    Throwable thrown = null;
+                    try {
+                        task.run();
+                    } catch (RuntimeException x) {
+                        thrown = x; throw x;
+                    } catch (Error x) {
+                        thrown = x; throw x;
+                    } catch (Throwable x) {
+                        thrown = x; throw new Error(x);
+                    } finally {
+                        afterExecute(task, thrown);
+                    }
+                } finally {
+                    task = null;
+                    w.completedTasks++;
+                    w.unlock();
+                }
+            }
+            completedAbruptly = false;
+        } finally {
+            processWorkerExit(w, completedAbruptly);
+        }
+    }
+
+    // Public constructors and methods
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters and default thread factory and rejected execution handler.
+     * It may be more convenient to use one of the {@link Executors} factory
+     * methods instead of this general purpose constructor.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue) {
+        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+             Executors.defaultThreadFactory(), defaultHandler);
+    }
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters and default rejected execution handler.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue}
+     *         or {@code threadFactory} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue,
+                              ThreadFactory threadFactory) {
+        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+             threadFactory, defaultHandler);
+    }
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters and default thread factory.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue}
+     *         or {@code handler} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue,
+                              RejectedExecutionHandler handler) {
+        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+             Executors.defaultThreadFactory(), handler);
+    }
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue}
+     *         or {@code threadFactory} or {@code handler} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue,
+                              ThreadFactory threadFactory,
+                              RejectedExecutionHandler handler) {
+        if (corePoolSize < 0 ||
+            maximumPoolSize <= 0 ||
+            maximumPoolSize < corePoolSize ||
+            keepAliveTime < 0)
+            throw new IllegalArgumentException();
+        if (workQueue == null || threadFactory == null || handler == null)
+            throw new NullPointerException();
+        this.corePoolSize = corePoolSize;
+        this.maximumPoolSize = maximumPoolSize;
+        this.workQueue = workQueue;
+        this.keepAliveTime = unit.toNanos(keepAliveTime);
+        this.threadFactory = threadFactory;
+        this.handler = handler;
+    }
+
+    /**
+     * Executes the given task sometime in the future.  The task
+     * may execute in a new thread or in an existing pooled thread.
+     *
+     * If the task cannot be submitted for execution, either because this
+     * executor has been shutdown or because its capacity has been reached,
+     * the task is handled by the current {@code RejectedExecutionHandler}.
+     *
+     * @param command the task to execute
+     * @throws RejectedExecutionException at discretion of
+     *         {@code RejectedExecutionHandler}, if the task
+     *         cannot be accepted for execution
+     * @throws NullPointerException if {@code command} is null
+     */
+    public void execute(Runnable command) {
+        if (command == null)
+            throw new NullPointerException();
+        /*
+         * Proceed in 3 steps:
+         *
+         * 1. If fewer than corePoolSize threads are running, try to
+         * start a new thread with the given command as its first
+         * task.  The call to addWorker atomically checks runState and
+         * workerCount, and so prevents false alarms that would add
+         * threads when it shouldn't, by returning false.
+         *
+         * 2. If a task can be successfully queued, then we still need
+         * to double-check whether we should have added a thread
+         * (because existing ones died since last checking) or that
+         * the pool shut down since entry into this method. So we
+         * recheck state and if necessary roll back the enqueuing if
+         * stopped, or start a new thread if there are none.
+         *
+         * 3. If we cannot queue task, then we try to add a new
+         * thread.  If it fails, we know we are shut down or saturated
+         * and so reject the task.
+         */
+        int c = ctl.get();
+        if (workerCountOf(c) < corePoolSize) {
+            if (addWorker(command, true))
+                return;
+            c = ctl.get();
+        }
+        if (isRunning(c) && workQueue.offer(command)) {
+            int recheck = ctl.get();
+            if (! isRunning(recheck) && remove(command))
+                reject(command);
+            else if (workerCountOf(recheck) == 0)
+                addWorker(null, false);
+        }
+        else if (!addWorker(command, false))
+            reject(command);
+    }
+
+    /**
+     * Initiates an orderly shutdown in which previously submitted
+     * tasks are executed, but no new tasks will be accepted.
+     * Invocation has no additional effect if already shut down.
+     *
+     * <p>This method does not wait for previously submitted tasks to
+     * complete execution.  Use {@link #awaitTermination awaitTermination}
+     * to do that.
+     */
+    // android-note: Removed @throws SecurityException
+    public void shutdown() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            checkShutdownAccess();
+            advanceRunState(SHUTDOWN);
+            interruptIdleWorkers();
+            onShutdown(); // hook for ScheduledThreadPoolExecutor
+        } finally {
+            mainLock.unlock();
+        }
+        tryTerminate();
+    }
+
+    /**
+     * Attempts to stop all actively executing tasks, halts the
+     * processing of waiting tasks, and returns a list of the tasks
+     * that were awaiting execution. These tasks are drained (removed)
+     * from the task queue upon return from this method.
+     *
+     * <p>This method does not wait for actively executing tasks to
+     * terminate.  Use {@link #awaitTermination awaitTermination} to
+     * do that.
+     *
+     * <p>There are no guarantees beyond best-effort attempts to stop
+     * processing actively executing tasks.  This implementation
+     * interrupts tasks via {@link Thread#interrupt}; any task that
+     * fails to respond to interrupts may never terminate.
+     */
+    // android-note: Removed @throws SecurityException
+    public List<Runnable> shutdownNow() {
+        List<Runnable> tasks;
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            checkShutdownAccess();
+            advanceRunState(STOP);
+            interruptWorkers();
+            tasks = drainQueue();
+        } finally {
+            mainLock.unlock();
+        }
+        tryTerminate();
+        return tasks;
+    }
+
+    public boolean isShutdown() {
+        return ! isRunning(ctl.get());
+    }
+
+    /**
+     * Returns true if this executor is in the process of terminating
+     * after {@link #shutdown} or {@link #shutdownNow} but has not
+     * completely terminated.  This method may be useful for
+     * debugging. A return of {@code true} reported a sufficient
+     * period after shutdown may indicate that submitted tasks have
+     * ignored or suppressed interruption, causing this executor not
+     * to properly terminate.
+     *
+     * @return {@code true} if terminating but not yet terminated
+     */
+    public boolean isTerminating() {
+        int c = ctl.get();
+        return ! isRunning(c) && runStateLessThan(c, TERMINATED);
+    }
+
+    public boolean isTerminated() {
+        return runStateAtLeast(ctl.get(), TERMINATED);
+    }
+
+    public boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            while (!runStateAtLeast(ctl.get(), TERMINATED)) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = termination.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Invokes {@code shutdown} when this executor is no longer
+     * referenced and it has no threads.
+     */
+    protected void finalize() {
+        shutdown();
+    }
+
+    /**
+     * Sets the thread factory used to create new threads.
+     *
+     * @param threadFactory the new thread factory
+     * @throws NullPointerException if threadFactory is null
+     * @see #getThreadFactory
+     */
+    public void setThreadFactory(ThreadFactory threadFactory) {
+        if (threadFactory == null)
+            throw new NullPointerException();
+        this.threadFactory = threadFactory;
+    }
+
+    /**
+     * Returns the thread factory used to create new threads.
+     *
+     * @return the current thread factory
+     * @see #setThreadFactory(ThreadFactory)
+     */
+    public ThreadFactory getThreadFactory() {
+        return threadFactory;
+    }
+
+    /**
+     * Sets a new handler for unexecutable tasks.
+     *
+     * @param handler the new handler
+     * @throws NullPointerException if handler is null
+     * @see #getRejectedExecutionHandler
+     */
+    public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
+        if (handler == null)
+            throw new NullPointerException();
+        this.handler = handler;
+    }
+
+    /**
+     * Returns the current handler for unexecutable tasks.
+     *
+     * @return the current handler
+     * @see #setRejectedExecutionHandler(RejectedExecutionHandler)
+     */
+    public RejectedExecutionHandler getRejectedExecutionHandler() {
+        return handler;
+    }
+
+    // Android-changed: Tolerate maximumPoolSize >= corePoolSize during setCorePoolSize().
+    /**
+     * Sets the core number of threads.  This overrides any value set
+     * in the constructor.  If the new value is smaller than the
+     * current value, excess existing threads will be terminated when
+     * they next become idle.  If larger, new threads will, if needed,
+     * be started to execute any queued tasks.
+     *
+     * @param corePoolSize the new core size
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @see #getCorePoolSize
+     */
+    public void setCorePoolSize(int corePoolSize) {
+        // BEGIN Android-changed: Tolerate maximumPoolSize >= corePoolSize during setCorePoolSize().
+        // This reverts a change that threw an IAE on that condition. This is due to defective code
+        // in a commonly used third party library that does something like exec.setCorePoolSize(N)
+        // before doing exec.setMaxPoolSize(N).
+        //
+        // if (corePoolSize < 0 || maximumPoolSize < corePoolSize)
+        if (corePoolSize < 0)
+        // END Android-changed: Tolerate maximumPoolSize >= corePoolSize during setCorePoolSize().
+            throw new IllegalArgumentException();
+        int delta = corePoolSize - this.corePoolSize;
+        this.corePoolSize = corePoolSize;
+        if (workerCountOf(ctl.get()) > corePoolSize)
+            interruptIdleWorkers();
+        else if (delta > 0) {
+            // We don't really know how many new threads are "needed".
+            // As a heuristic, prestart enough new workers (up to new
+            // core size) to handle the current number of tasks in
+            // queue, but stop if queue becomes empty while doing so.
+            int k = Math.min(delta, workQueue.size());
+            while (k-- > 0 && addWorker(null, true)) {
+                if (workQueue.isEmpty())
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Returns the core number of threads.
+     *
+     * @return the core number of threads
+     * @see #setCorePoolSize
+     */
+    public int getCorePoolSize() {
+        return corePoolSize;
+    }
+
+    /**
+     * Starts a core thread, causing it to idly wait for work. This
+     * overrides the default policy of starting core threads only when
+     * new tasks are executed. This method will return {@code false}
+     * if all core threads have already been started.
+     *
+     * @return {@code true} if a thread was started
+     */
+    public boolean prestartCoreThread() {
+        return workerCountOf(ctl.get()) < corePoolSize &&
+            addWorker(null, true);
+    }
+
+    /**
+     * Same as prestartCoreThread except arranges that at least one
+     * thread is started even if corePoolSize is 0.
+     */
+    void ensurePrestart() {
+        int wc = workerCountOf(ctl.get());
+        if (wc < corePoolSize)
+            addWorker(null, true);
+        else if (wc == 0)
+            addWorker(null, false);
+    }
+
+    /**
+     * Starts all core threads, causing them to idly wait for work. This
+     * overrides the default policy of starting core threads only when
+     * new tasks are executed.
+     *
+     * @return the number of threads started
+     */
+    public int prestartAllCoreThreads() {
+        int n = 0;
+        while (addWorker(null, true))
+            ++n;
+        return n;
+    }
+
+    /**
+     * Returns true if this pool allows core threads to time out and
+     * terminate if no tasks arrive within the keepAlive time, being
+     * replaced if needed when new tasks arrive. When true, the same
+     * keep-alive policy applying to non-core threads applies also to
+     * core threads. When false (the default), core threads are never
+     * terminated due to lack of incoming tasks.
+     *
+     * @return {@code true} if core threads are allowed to time out,
+     *         else {@code false}
+     *
+     * @since 1.6
+     */
+    public boolean allowsCoreThreadTimeOut() {
+        return allowCoreThreadTimeOut;
+    }
+
+    /**
+     * Sets the policy governing whether core threads may time out and
+     * terminate if no tasks arrive within the keep-alive time, being
+     * replaced if needed when new tasks arrive. When false, core
+     * threads are never terminated due to lack of incoming
+     * tasks. When true, the same keep-alive policy applying to
+     * non-core threads applies also to core threads. To avoid
+     * continual thread replacement, the keep-alive time must be
+     * greater than zero when setting {@code true}. This method
+     * should in general be called before the pool is actively used.
+     *
+     * @param value {@code true} if should time out, else {@code false}
+     * @throws IllegalArgumentException if value is {@code true}
+     *         and the current keep-alive time is not greater than zero
+     *
+     * @since 1.6
+     */
+    public void allowCoreThreadTimeOut(boolean value) {
+        if (value && keepAliveTime <= 0)
+            throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
+        if (value != allowCoreThreadTimeOut) {
+            allowCoreThreadTimeOut = value;
+            if (value)
+                interruptIdleWorkers();
+        }
+    }
+
+    /**
+     * Sets the maximum allowed number of threads. This overrides any
+     * value set in the constructor. If the new value is smaller than
+     * the current value, excess existing threads will be
+     * terminated when they next become idle.
+     *
+     * @param maximumPoolSize the new maximum
+     * @throws IllegalArgumentException if the new maximum is
+     *         less than or equal to zero, or
+     *         less than the {@linkplain #getCorePoolSize core pool size}
+     * @see #getMaximumPoolSize
+     */
+    public void setMaximumPoolSize(int maximumPoolSize) {
+        if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
+            throw new IllegalArgumentException();
+        this.maximumPoolSize = maximumPoolSize;
+        if (workerCountOf(ctl.get()) > maximumPoolSize)
+            interruptIdleWorkers();
+    }
+
+    /**
+     * Returns the maximum allowed number of threads.
+     *
+     * @return the maximum allowed number of threads
+     * @see #setMaximumPoolSize
+     */
+    public int getMaximumPoolSize() {
+        return maximumPoolSize;
+    }
+
+    /**
+     * Sets the thread keep-alive time, which is the amount of time
+     * that threads may remain idle before being terminated.
+     * Threads that wait this amount of time without processing a
+     * task will be terminated if there are more than the core
+     * number of threads currently in the pool, or if this pool
+     * {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
+     * This overrides any value set in the constructor.
+     *
+     * @param time the time to wait.  A time value of zero will cause
+     *        excess threads to terminate immediately after executing tasks.
+     * @param unit the time unit of the {@code time} argument
+     * @throws IllegalArgumentException if {@code time} less than zero or
+     *         if {@code time} is zero and {@code allowsCoreThreadTimeOut}
+     * @see #getKeepAliveTime(TimeUnit)
+     */
+    public void setKeepAliveTime(long time, TimeUnit unit) {
+        if (time < 0)
+            throw new IllegalArgumentException();
+        if (time == 0 && allowsCoreThreadTimeOut())
+            throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
+        long keepAliveTime = unit.toNanos(time);
+        long delta = keepAliveTime - this.keepAliveTime;
+        this.keepAliveTime = keepAliveTime;
+        if (delta < 0)
+            interruptIdleWorkers();
+    }
+
+    /**
+     * Returns the thread keep-alive time, which is the amount of time
+     * that threads may remain idle before being terminated.
+     * Threads that wait this amount of time without processing a
+     * task will be terminated if there are more than the core
+     * number of threads currently in the pool, or if this pool
+     * {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
+     *
+     * @param unit the desired time unit of the result
+     * @return the time limit
+     * @see #setKeepAliveTime(long, TimeUnit)
+     */
+    public long getKeepAliveTime(TimeUnit unit) {
+        return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
+    }
+
+    /* User-level queue utilities */
+
+    /**
+     * Returns the task queue used by this executor. Access to the
+     * task queue is intended primarily for debugging and monitoring.
+     * This queue may be in active use.  Retrieving the task queue
+     * does not prevent queued tasks from executing.
+     *
+     * @return the task queue
+     */
+    public BlockingQueue<Runnable> getQueue() {
+        return workQueue;
+    }
+
+    /**
+     * Removes this task from the executor's internal queue if it is
+     * present, thus causing it not to be run if it has not already
+     * started.
+     *
+     * <p>This method may be useful as one part of a cancellation
+     * scheme.  It may fail to remove tasks that have been converted
+     * into other forms before being placed on the internal queue.
+     * For example, a task entered using {@code submit} might be
+     * converted into a form that maintains {@code Future} status.
+     * However, in such cases, method {@link #purge} may be used to
+     * remove those Futures that have been cancelled.
+     *
+     * @param task the task to remove
+     * @return {@code true} if the task was removed
+     */
+    public boolean remove(Runnable task) {
+        boolean removed = workQueue.remove(task);
+        tryTerminate(); // In case SHUTDOWN and now empty
+        return removed;
+    }
+
+    /**
+     * Tries to remove from the work queue all {@link Future}
+     * tasks that have been cancelled. This method can be useful as a
+     * storage reclamation operation, that has no other impact on
+     * functionality. Cancelled tasks are never executed, but may
+     * accumulate in work queues until worker threads can actively
+     * remove them. Invoking this method instead tries to remove them now.
+     * However, this method may fail to remove tasks in
+     * the presence of interference by other threads.
+     */
+    public void purge() {
+        final BlockingQueue<Runnable> q = workQueue;
+        try {
+            Iterator<Runnable> it = q.iterator();
+            while (it.hasNext()) {
+                Runnable r = it.next();
+                if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
+                    it.remove();
+            }
+        } catch (ConcurrentModificationException fallThrough) {
+            // Take slow path if we encounter interference during traversal.
+            // Make copy for traversal and call remove for cancelled entries.
+            // The slow path is more likely to be O(N*N).
+            for (Object r : q.toArray())
+                if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
+                    q.remove(r);
+        }
+
+        tryTerminate(); // In case SHUTDOWN and now empty
+    }
+
+    /* Statistics */
+
+    /**
+     * Returns the current number of threads in the pool.
+     *
+     * @return the number of threads
+     */
+    public int getPoolSize() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            // Remove rare and surprising possibility of
+            // isTerminated() && getPoolSize() > 0
+            return runStateAtLeast(ctl.get(), TIDYING) ? 0
+                : workers.size();
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the approximate number of threads that are actively
+     * executing tasks.
+     *
+     * @return the number of threads
+     */
+    public int getActiveCount() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            int n = 0;
+            for (Worker w : workers)
+                if (w.isLocked())
+                    ++n;
+            return n;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the largest number of threads that have ever
+     * simultaneously been in the pool.
+     *
+     * @return the number of threads
+     */
+    public int getLargestPoolSize() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            return largestPoolSize;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the approximate total number of tasks that have ever been
+     * scheduled for execution. Because the states of tasks and
+     * threads may change dynamically during computation, the returned
+     * value is only an approximation.
+     *
+     * @return the number of tasks
+     */
+    public long getTaskCount() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            long n = completedTaskCount;
+            for (Worker w : workers) {
+                n += w.completedTasks;
+                if (w.isLocked())
+                    ++n;
+            }
+            return n + workQueue.size();
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the approximate total number of tasks that have
+     * completed execution. Because the states of tasks and threads
+     * may change dynamically during computation, the returned value
+     * is only an approximation, but one that does not ever decrease
+     * across successive calls.
+     *
+     * @return the number of tasks
+     */
+    public long getCompletedTaskCount() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            long n = completedTaskCount;
+            for (Worker w : workers)
+                n += w.completedTasks;
+            return n;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns a string identifying this pool, as well as its state,
+     * including indications of run state and estimated worker and
+     * task counts.
+     *
+     * @return a string identifying this pool, as well as its state
+     */
+    public String toString() {
+        long ncompleted;
+        int nworkers, nactive;
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            ncompleted = completedTaskCount;
+            nactive = 0;
+            nworkers = workers.size();
+            for (Worker w : workers) {
+                ncompleted += w.completedTasks;
+                if (w.isLocked())
+                    ++nactive;
+            }
+        } finally {
+            mainLock.unlock();
+        }
+        int c = ctl.get();
+        String runState =
+            runStateLessThan(c, SHUTDOWN) ? "Running" :
+            runStateAtLeast(c, TERMINATED) ? "Terminated" :
+            "Shutting down";
+        return super.toString() +
+            "[" + runState +
+            ", pool size = " + nworkers +
+            ", active threads = " + nactive +
+            ", queued tasks = " + workQueue.size() +
+            ", completed tasks = " + ncompleted +
+            "]";
+    }
+
+    /* Extension hooks */
+
+    /**
+     * Method invoked prior to executing the given Runnable in the
+     * given thread.  This method is invoked by thread {@code t} that
+     * will execute task {@code r}, and may be used to re-initialize
+     * ThreadLocals, or to perform logging.
+     *
+     * <p>This implementation does nothing, but may be customized in
+     * subclasses. Note: To properly nest multiple overridings, subclasses
+     * should generally invoke {@code super.beforeExecute} at the end of
+     * this method.
+     *
+     * @param t the thread that will run task {@code r}
+     * @param r the task that will be executed
+     */
+    protected void beforeExecute(Thread t, Runnable r) { }
+
+    /**
+     * Method invoked upon completion of execution of the given Runnable.
+     * This method is invoked by the thread that executed the task. If
+     * non-null, the Throwable is the uncaught {@code RuntimeException}
+     * or {@code Error} that caused execution to terminate abruptly.
+     *
+     * <p>This implementation does nothing, but may be customized in
+     * subclasses. Note: To properly nest multiple overridings, subclasses
+     * should generally invoke {@code super.afterExecute} at the
+     * beginning of this method.
+     *
+     * <p><b>Note:</b> When actions are enclosed in tasks (such as
+     * {@link FutureTask}) either explicitly or via methods such as
+     * {@code submit}, these task objects catch and maintain
+     * computational exceptions, and so they do not cause abrupt
+     * termination, and the internal exceptions are <em>not</em>
+     * passed to this method. If you would like to trap both kinds of
+     * failures in this method, you can further probe for such cases,
+     * as in this sample subclass that prints either the direct cause
+     * or the underlying exception if a task has been aborted:
+     *
+     * <pre> {@code
+     * class ExtendedExecutor extends ThreadPoolExecutor {
+     *   // ...
+     *   protected void afterExecute(Runnable r, Throwable t) {
+     *     super.afterExecute(r, t);
+     *     if (t == null
+     *         && r instanceof Future<?>
+     *         && ((Future<?>)r).isDone()) {
+     *       try {
+     *         Object result = ((Future<?>) r).get();
+     *       } catch (CancellationException ce) {
+     *         t = ce;
+     *       } catch (ExecutionException ee) {
+     *         t = ee.getCause();
+     *       } catch (InterruptedException ie) {
+     *         // ignore/reset
+     *         Thread.currentThread().interrupt();
+     *       }
+     *     }
+     *     if (t != null)
+     *       System.out.println(t);
+     *   }
+     * }}</pre>
+     *
+     * @param r the runnable that has completed
+     * @param t the exception that caused termination, or null if
+     * execution completed normally
+     */
+    protected void afterExecute(Runnable r, Throwable t) { }
+
+    /**
+     * Method invoked when the Executor has terminated.  Default
+     * implementation does nothing. Note: To properly nest multiple
+     * overridings, subclasses should generally invoke
+     * {@code super.terminated} within this method.
+     */
+    protected void terminated() { }
+
+    /* Predefined RejectedExecutionHandlers */
+
+    /**
+     * A handler for rejected tasks that runs the rejected task
+     * directly in the calling thread of the {@code execute} method,
+     * unless the executor has been shut down, in which case the task
+     * is discarded.
+     */
+    public static class CallerRunsPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates a {@code CallerRunsPolicy}.
+         */
+        public CallerRunsPolicy() { }
+
+        /**
+         * Executes task r in the caller's thread, unless the executor
+         * has been shut down, in which case the task is discarded.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+            if (!e.isShutdown()) {
+                r.run();
+            }
+        }
+    }
+
+    /**
+     * A handler for rejected tasks that throws a
+     * {@code RejectedExecutionException}.
+     */
+    public static class AbortPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates an {@code AbortPolicy}.
+         */
+        public AbortPolicy() { }
+
+        /**
+         * Always throws RejectedExecutionException.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         * @throws RejectedExecutionException always
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+            throw new RejectedExecutionException("Task " + r.toString() +
+                                                 " rejected from " +
+                                                 e.toString());
+        }
+    }
+
+    /**
+     * A handler for rejected tasks that silently discards the
+     * rejected task.
+     */
+    public static class DiscardPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates a {@code DiscardPolicy}.
+         */
+        public DiscardPolicy() { }
+
+        /**
+         * Does nothing, which has the effect of discarding task r.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+        }
+    }
+
+    /**
+     * A handler for rejected tasks that discards the oldest unhandled
+     * request and then retries {@code execute}, unless the executor
+     * is shut down, in which case the task is discarded.
+     */
+    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates a {@code DiscardOldestPolicy} for the given executor.
+         */
+        public DiscardOldestPolicy() { }
+
+        /**
+         * Obtains and ignores the next task that the executor
+         * would otherwise execute, if one is immediately available,
+         * and then retries execution of task r, unless the executor
+         * is shut down, in which case task r is instead discarded.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+            if (!e.isShutdown()) {
+                e.getQueue().poll();
+                e.execute(r);
+            }
+        }
+    }
+}
diff --git a/java/util/concurrent/TimeUnit.java b/java/util/concurrent/TimeUnit.java
new file mode 100644
index 0000000..44d7964
--- /dev/null
+++ b/java/util/concurrent/TimeUnit.java
@@ -0,0 +1,443 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Objects;
+
+/**
+ * A {@code TimeUnit} represents time durations at a given unit of
+ * granularity and provides utility methods to convert across units,
+ * and to perform timing and delay operations in these units.  A
+ * {@code TimeUnit} does not maintain time information, but only
+ * helps organize and use time representations that may be maintained
+ * separately across various contexts.  A nanosecond is defined as one
+ * thousandth of a microsecond, a microsecond as one thousandth of a
+ * millisecond, a millisecond as one thousandth of a second, a minute
+ * as sixty seconds, an hour as sixty minutes, and a day as twenty four
+ * hours.
+ *
+ * <p>A {@code TimeUnit} is mainly used to inform time-based methods
+ * how a given timing parameter should be interpreted. For example,
+ * the following code will timeout in 50 milliseconds if the {@link
+ * java.util.concurrent.locks.Lock lock} is not available:
+ *
+ * <pre> {@code
+ * Lock lock = ...;
+ * if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...}</pre>
+ *
+ * while this code will timeout in 50 seconds:
+ * <pre> {@code
+ * Lock lock = ...;
+ * if (lock.tryLock(50L, TimeUnit.SECONDS)) ...}</pre>
+ *
+ * Note however, that there is no guarantee that a particular timeout
+ * implementation will be able to notice the passage of time at the
+ * same granularity as the given {@code TimeUnit}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public enum TimeUnit {
+    /**
+     * Time unit representing one thousandth of a microsecond.
+     */
+    NANOSECONDS {
+        public long toNanos(long d)   { return d; }
+        public long toMicros(long d)  { return d/(C1/C0); }
+        public long toMillis(long d)  { return d/(C2/C0); }
+        public long toSeconds(long d) { return d/(C3/C0); }
+        public long toMinutes(long d) { return d/(C4/C0); }
+        public long toHours(long d)   { return d/(C5/C0); }
+        public long toDays(long d)    { return d/(C6/C0); }
+        public long convert(long d, TimeUnit u) { return u.toNanos(d); }
+        int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
+    },
+
+    /**
+     * Time unit representing one thousandth of a millisecond.
+     */
+    MICROSECONDS {
+        public long toNanos(long d)   { return x(d, C1/C0, MAX/(C1/C0)); }
+        public long toMicros(long d)  { return d; }
+        public long toMillis(long d)  { return d/(C2/C1); }
+        public long toSeconds(long d) { return d/(C3/C1); }
+        public long toMinutes(long d) { return d/(C4/C1); }
+        public long toHours(long d)   { return d/(C5/C1); }
+        public long toDays(long d)    { return d/(C6/C1); }
+        public long convert(long d, TimeUnit u) { return u.toMicros(d); }
+        int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); }
+    },
+
+    /**
+     * Time unit representing one thousandth of a second.
+     */
+    MILLISECONDS {
+        public long toNanos(long d)   { return x(d, C2/C0, MAX/(C2/C0)); }
+        public long toMicros(long d)  { return x(d, C2/C1, MAX/(C2/C1)); }
+        public long toMillis(long d)  { return d; }
+        public long toSeconds(long d) { return d/(C3/C2); }
+        public long toMinutes(long d) { return d/(C4/C2); }
+        public long toHours(long d)   { return d/(C5/C2); }
+        public long toDays(long d)    { return d/(C6/C2); }
+        public long convert(long d, TimeUnit u) { return u.toMillis(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
+    /**
+     * Time unit representing one second.
+     */
+    SECONDS {
+        public long toNanos(long d)   { return x(d, C3/C0, MAX/(C3/C0)); }
+        public long toMicros(long d)  { return x(d, C3/C1, MAX/(C3/C1)); }
+        public long toMillis(long d)  { return x(d, C3/C2, MAX/(C3/C2)); }
+        public long toSeconds(long d) { return d; }
+        public long toMinutes(long d) { return d/(C4/C3); }
+        public long toHours(long d)   { return d/(C5/C3); }
+        public long toDays(long d)    { return d/(C6/C3); }
+        public long convert(long d, TimeUnit u) { return u.toSeconds(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
+    /**
+     * Time unit representing sixty seconds.
+     * @since 1.6
+     */
+    MINUTES {
+        public long toNanos(long d)   { return x(d, C4/C0, MAX/(C4/C0)); }
+        public long toMicros(long d)  { return x(d, C4/C1, MAX/(C4/C1)); }
+        public long toMillis(long d)  { return x(d, C4/C2, MAX/(C4/C2)); }
+        public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); }
+        public long toMinutes(long d) { return d; }
+        public long toHours(long d)   { return d/(C5/C4); }
+        public long toDays(long d)    { return d/(C6/C4); }
+        public long convert(long d, TimeUnit u) { return u.toMinutes(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
+    /**
+     * Time unit representing sixty minutes.
+     * @since 1.6
+     */
+    HOURS {
+        public long toNanos(long d)   { return x(d, C5/C0, MAX/(C5/C0)); }
+        public long toMicros(long d)  { return x(d, C5/C1, MAX/(C5/C1)); }
+        public long toMillis(long d)  { return x(d, C5/C2, MAX/(C5/C2)); }
+        public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); }
+        public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); }
+        public long toHours(long d)   { return d; }
+        public long toDays(long d)    { return d/(C6/C5); }
+        public long convert(long d, TimeUnit u) { return u.toHours(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
+    /**
+     * Time unit representing twenty four hours.
+     * @since 1.6
+     */
+    DAYS {
+        public long toNanos(long d)   { return x(d, C6/C0, MAX/(C6/C0)); }
+        public long toMicros(long d)  { return x(d, C6/C1, MAX/(C6/C1)); }
+        public long toMillis(long d)  { return x(d, C6/C2, MAX/(C6/C2)); }
+        public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); }
+        public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); }
+        public long toHours(long d)   { return x(d, C6/C5, MAX/(C6/C5)); }
+        public long toDays(long d)    { return d; }
+        public long convert(long d, TimeUnit u) { return u.toDays(d); }
+        int excessNanos(long d, long m) { return 0; }
+    };
+
+    // Handy constants for conversion methods
+    static final long C0 = 1L;
+    static final long C1 = C0 * 1000L;
+    static final long C2 = C1 * 1000L;
+    static final long C3 = C2 * 1000L;
+    static final long C4 = C3 * 60L;
+    static final long C5 = C4 * 60L;
+    static final long C6 = C5 * 24L;
+
+    static final long MAX = Long.MAX_VALUE;
+
+    /**
+     * Scale d by m, checking for overflow.
+     * This has a short name to make above code more readable.
+     */
+    static long x(long d, long m, long over) {
+        if (d > +over) return Long.MAX_VALUE;
+        if (d < -over) return Long.MIN_VALUE;
+        return d * m;
+    }
+
+    // To maintain full signature compatibility with 1.5, and to improve the
+    // clarity of the generated javadoc (see 6287639: Abstract methods in
+    // enum classes should not be listed as abstract), method convert
+    // etc. are not declared abstract but otherwise act as abstract methods.
+
+    /**
+     * Converts the given time duration in the given unit to this unit.
+     * Conversions from finer to coarser granularities truncate, so
+     * lose precision. For example, converting {@code 999} milliseconds
+     * to seconds results in {@code 0}. Conversions from coarser to
+     * finer granularities with arguments that would numerically
+     * overflow saturate to {@code Long.MIN_VALUE} if negative or
+     * {@code Long.MAX_VALUE} if positive.
+     *
+     * <p>For example, to convert 10 minutes to milliseconds, use:
+     * {@code TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES)}
+     *
+     * @param sourceDuration the time duration in the given {@code sourceUnit}
+     * @param sourceUnit the unit of the {@code sourceDuration} argument
+     * @return the converted duration in this unit,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long convert(long sourceDuration, TimeUnit sourceUnit) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) NANOSECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toNanos(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) MICROSECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toMicros(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) MILLISECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toMillis(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) SECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toSeconds(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) MINUTES.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     * @since 1.6
+     */
+    public long toMinutes(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) HOURS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     * @since 1.6
+     */
+    public long toHours(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) DAYS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration
+     * @since 1.6
+     */
+    public long toDays(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Utility to compute the excess-nanosecond argument to wait,
+     * sleep, join.
+     * @param d the duration
+     * @param m the number of milliseconds
+     * @return the number of nanoseconds
+     */
+    abstract int excessNanos(long d, long m);
+
+    /**
+     * Performs a timed {@link Object#wait(long, int) Object.wait}
+     * using this time unit.
+     * This is a convenience method that converts timeout arguments
+     * into the form required by the {@code Object.wait} method.
+     *
+     * <p>For example, you could implement a blocking {@code poll}
+     * method (see {@link BlockingQueue#poll BlockingQueue.poll})
+     * using:
+     *
+     * <pre> {@code
+     * public synchronized Object poll(long timeout, TimeUnit unit)
+     *     throws InterruptedException {
+     *   while (empty) {
+     *     unit.timedWait(this, timeout);
+     *     ...
+     *   }
+     * }}</pre>
+     *
+     * @param obj the object to wait on
+     * @param timeout the maximum time to wait. If less than
+     * or equal to zero, do not wait at all.
+     * @throws InterruptedException if interrupted while waiting
+     */
+    public void timedWait(Object obj, long timeout)
+            throws InterruptedException {
+        if (timeout > 0) {
+            long ms = toMillis(timeout);
+            int ns = excessNanos(timeout, ms);
+            obj.wait(ms, ns);
+        }
+    }
+
+    /**
+     * Performs a timed {@link Thread#join(long, int) Thread.join}
+     * using this time unit.
+     * This is a convenience method that converts time arguments into the
+     * form required by the {@code Thread.join} method.
+     *
+     * @param thread the thread to wait for
+     * @param timeout the maximum time to wait. If less than
+     * or equal to zero, do not wait at all.
+     * @throws InterruptedException if interrupted while waiting
+     */
+    public void timedJoin(Thread thread, long timeout)
+            throws InterruptedException {
+        if (timeout > 0) {
+            long ms = toMillis(timeout);
+            int ns = excessNanos(timeout, ms);
+            thread.join(ms, ns);
+        }
+    }
+
+    /**
+     * Performs a {@link Thread#sleep(long, int) Thread.sleep} using
+     * this time unit.
+     * This is a convenience method that converts time arguments into the
+     * form required by the {@code Thread.sleep} method.
+     *
+     * @param timeout the minimum time to sleep. If less than
+     * or equal to zero, do not sleep at all.
+     * @throws InterruptedException if interrupted while sleeping
+     */
+    public void sleep(long timeout) throws InterruptedException {
+        if (timeout > 0) {
+            long ms = toMillis(timeout);
+            int ns = excessNanos(timeout, ms);
+            Thread.sleep(ms, ns);
+        }
+    }
+
+    // BEGIN Android-removed: OpenJDK 9 ChronoUnit related code.
+    /*
+    /**
+     * Converts this {@code TimeUnit} to the equivalent {@code ChronoUnit}.
+     *
+     * @return the converted equivalent ChronoUnit
+     * @since 9
+     *
+    public ChronoUnit toChronoUnit() {
+        switch (this) {
+        case NANOSECONDS:  return ChronoUnit.NANOS;
+        case MICROSECONDS: return ChronoUnit.MICROS;
+        case MILLISECONDS: return ChronoUnit.MILLIS;
+        case SECONDS:      return ChronoUnit.SECONDS;
+        case MINUTES:      return ChronoUnit.MINUTES;
+        case HOURS:        return ChronoUnit.HOURS;
+        case DAYS:         return ChronoUnit.DAYS;
+        default: throw new AssertionError();
+        }
+    }
+
+    /**
+     * Converts a {@code ChronoUnit} to the equivalent {@code TimeUnit}.
+     *
+     * @param chronoUnit the ChronoUnit to convert
+     * @return the converted equivalent TimeUnit
+     * @throws IllegalArgumentException if {@code chronoUnit} has no
+     *         equivalent TimeUnit
+     * @throws NullPointerException if {@code chronoUnit} is null
+     * @since 9
+     *
+    public static TimeUnit of(ChronoUnit chronoUnit) {
+        switch (Objects.requireNonNull(chronoUnit, "chronoUnit")) {
+        case NANOS:   return TimeUnit.NANOSECONDS;
+        case MICROS:  return TimeUnit.MICROSECONDS;
+        case MILLIS:  return TimeUnit.MILLISECONDS;
+        case SECONDS: return TimeUnit.SECONDS;
+        case MINUTES: return TimeUnit.MINUTES;
+        case HOURS:   return TimeUnit.HOURS;
+        case DAYS:    return TimeUnit.DAYS;
+        default:
+            throw new IllegalArgumentException(
+                "No TimeUnit equivalent for " + chronoUnit);
+        }
+    }
+    */
+    // END Android-removed: OpenJDK 9 ChronoUnit related code.
+
+}
diff --git a/java/util/concurrent/TimeoutException.java b/java/util/concurrent/TimeoutException.java
new file mode 100644
index 0000000..b54c52b
--- /dev/null
+++ b/java/util/concurrent/TimeoutException.java
@@ -0,0 +1,67 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when a blocking operation times out.  Blocking
+ * operations for which a timeout is specified need a means to
+ * indicate that the timeout has occurred. For many such operations it
+ * is possible to return a value that indicates timeout; when that is
+ * not possible or desirable then {@code TimeoutException} should be
+ * declared and thrown.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class TimeoutException extends Exception {
+    private static final long serialVersionUID = 1900926677490660714L;
+
+    /**
+     * Constructs a {@code TimeoutException} with no specified detail
+     * message.
+     */
+    public TimeoutException() {}
+
+    /**
+     * Constructs a {@code TimeoutException} with the specified detail
+     * message.
+     *
+     * @param message the detail message
+     */
+    public TimeoutException(String message) {
+        super(message);
+    }
+}
diff --git a/java/util/concurrent/TransferQueue.java b/java/util/concurrent/TransferQueue.java
new file mode 100644
index 0000000..53da597
--- /dev/null
+++ b/java/util/concurrent/TransferQueue.java
@@ -0,0 +1,161 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A {@link BlockingQueue} in which producers may wait for consumers
+ * to receive elements.  A {@code TransferQueue} may be useful for
+ * example in message passing applications in which producers
+ * sometimes (using method {@link #transfer}) await receipt of
+ * elements by consumers invoking {@code take} or {@code poll}, while
+ * at other times enqueue elements (via method {@code put}) without
+ * waiting for receipt.
+ * {@linkplain #tryTransfer(Object) Non-blocking} and
+ * {@linkplain #tryTransfer(Object,long,TimeUnit) time-out} versions of
+ * {@code tryTransfer} are also available.
+ * A {@code TransferQueue} may also be queried, via {@link
+ * #hasWaitingConsumer}, whether there are any threads waiting for
+ * items, which is a converse analogy to a {@code peek} operation.
+ *
+ * <p>Like other blocking queues, a {@code TransferQueue} may be
+ * capacity bounded.  If so, an attempted transfer operation may
+ * initially block waiting for available space, and/or subsequently
+ * block waiting for reception by a consumer.  Note that in a queue
+ * with zero capacity, such as {@link SynchronousQueue}, {@code put}
+ * and {@code transfer} are effectively synonymous.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public interface TransferQueue<E> extends BlockingQueue<E> {
+    /**
+     * Transfers the element to a waiting consumer immediately, if possible.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * otherwise returning {@code false} without enqueuing the element.
+     *
+     * @param e the element to transfer
+     * @return {@code true} if the element was transferred, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean tryTransfer(E e);
+
+    /**
+     * Transfers the element to a consumer, waiting if necessary to do so.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else waits until the element is received by a consumer.
+     *
+     * @param e the element to transfer
+     * @throws InterruptedException if interrupted while waiting,
+     *         in which case the element is not left enqueued
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    void transfer(E e) throws InterruptedException;
+
+    /**
+     * Transfers the element to a consumer if it is possible to do so
+     * before the timeout elapses.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else waits until the element is received by a consumer,
+     * returning {@code false} if the specified wait time elapses
+     * before the element can be transferred.
+     *
+     * @param e the element to transfer
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before completion,
+     *         in which case the element is not left enqueued
+     * @throws InterruptedException if interrupted while waiting,
+     *         in which case the element is not left enqueued
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean tryTransfer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Returns {@code true} if there is at least one consumer waiting
+     * to receive an element via {@link #take} or
+     * timed {@link #poll(long,TimeUnit) poll}.
+     * The return value represents a momentary state of affairs.
+     *
+     * @return {@code true} if there is at least one waiting consumer
+     */
+    boolean hasWaitingConsumer();
+
+    /**
+     * Returns an estimate of the number of consumers waiting to
+     * receive elements via {@link #take} or timed
+     * {@link #poll(long,TimeUnit) poll}.  The return value is an
+     * approximation of a momentary state of affairs, that may be
+     * inaccurate if consumers have completed or given up waiting.
+     * The value may be useful for monitoring and heuristics, but
+     * not for synchronization control.  Implementations of this
+     * method are likely to be noticeably slower than those for
+     * {@link #hasWaitingConsumer}.
+     *
+     * @return the number of consumers waiting to receive elements
+     */
+    int getWaitingConsumerCount();
+}
diff --git a/java/util/concurrent/atomic/AtomicBoolean.java b/java/util/concurrent/atomic/AtomicBoolean.java
new file mode 100644
index 0000000..b2a2390
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicBoolean.java
@@ -0,0 +1,164 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+/**
+ * A {@code boolean} value that may be updated atomically. See the
+ * {@link java.util.concurrent.atomic} package specification for
+ * description of the properties of atomic variables. An
+ * {@code AtomicBoolean} is used in applications such as atomically
+ * updated flags, and cannot be used as a replacement for a
+ * {@link java.lang.Boolean}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicBoolean implements java.io.Serializable {
+    private static final long serialVersionUID = 4654671469794556979L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long VALUE;
+
+    static {
+        try {
+            VALUE = U.objectFieldOffset
+                (AtomicBoolean.class.getDeclaredField("value"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private volatile int value;
+
+    /**
+     * Creates a new {@code AtomicBoolean} with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicBoolean(boolean initialValue) {
+        value = initialValue ? 1 : 0;
+    }
+
+    /**
+     * Creates a new {@code AtomicBoolean} with initial value {@code false}.
+     */
+    public AtomicBoolean() {
+    }
+
+    /**
+     * Returns the current value.
+     *
+     * @return the current value
+     */
+    public final boolean get() {
+        return value != 0;
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(boolean expect, boolean update) {
+        return U.compareAndSwapInt(this, VALUE,
+                                   (expect ? 1 : 0),
+                                   (update ? 1 : 0));
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public boolean weakCompareAndSet(boolean expect, boolean update) {
+        return U.compareAndSwapInt(this, VALUE,
+                                   (expect ? 1 : 0),
+                                   (update ? 1 : 0));
+    }
+
+    /**
+     * Unconditionally sets to the given value.
+     *
+     * @param newValue the new value
+     */
+    public final void set(boolean newValue) {
+        value = newValue ? 1 : 0;
+    }
+
+    /**
+     * Eventually sets to the given value.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(boolean newValue) {
+        U.putOrderedInt(this, VALUE, (newValue ? 1 : 0));
+    }
+
+    /**
+     * Atomically sets to the given value and returns the previous value.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final boolean getAndSet(boolean newValue) {
+        boolean prev;
+        do {
+            prev = get();
+        } while (!compareAndSet(prev, newValue));
+        return prev;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Boolean.toString(get());
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicInteger.java b/java/util/concurrent/atomic/AtomicInteger.java
new file mode 100644
index 0000000..19b3418
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicInteger.java
@@ -0,0 +1,338 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntUnaryOperator;
+
+/**
+ * An {@code int} value that may be updated atomically.  See the
+ * {@link java.util.concurrent.atomic} package specification for
+ * description of the properties of atomic variables. An
+ * {@code AtomicInteger} is used in applications such as atomically
+ * incremented counters, and cannot be used as a replacement for an
+ * {@link java.lang.Integer}. However, this class does extend
+ * {@code Number} to allow uniform access by tools and utilities that
+ * deal with numerically-based classes.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicInteger extends Number implements java.io.Serializable {
+    private static final long serialVersionUID = 6214790243416807050L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long VALUE;
+
+    static {
+        try {
+            VALUE = U.objectFieldOffset
+                (AtomicInteger.class.getDeclaredField("value"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private volatile int value;
+
+    /**
+     * Creates a new AtomicInteger with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicInteger(int initialValue) {
+        value = initialValue;
+    }
+
+    /**
+     * Creates a new AtomicInteger with initial value {@code 0}.
+     */
+    public AtomicInteger() {
+    }
+
+    /**
+     * Gets the current value.
+     *
+     * @return the current value
+     */
+    public final int get() {
+        return value;
+    }
+
+    /**
+     * Sets to the given value.
+     *
+     * @param newValue the new value
+     */
+    public final void set(int newValue) {
+        value = newValue;
+    }
+
+    /**
+     * Eventually sets to the given value.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int newValue) {
+        U.putOrderedInt(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets to the given value and returns the old value.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final int getAndSet(int newValue) {
+        return U.getAndSetInt(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int expect, int update) {
+        return U.compareAndSwapInt(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(int expect, int update) {
+        return U.compareAndSwapInt(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically increments by one the current value.
+     *
+     * @return the previous value
+     */
+    public final int getAndIncrement() {
+        return U.getAndAddInt(this, VALUE, 1);
+    }
+
+    /**
+     * Atomically decrements by one the current value.
+     *
+     * @return the previous value
+     */
+    public final int getAndDecrement() {
+        return U.getAndAddInt(this, VALUE, -1);
+    }
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final int getAndAdd(int delta) {
+        return U.getAndAddInt(this, VALUE, delta);
+    }
+
+    /**
+     * Atomically increments by one the current value.
+     *
+     * @return the updated value
+     */
+    public final int incrementAndGet() {
+        return U.getAndAddInt(this, VALUE, 1) + 1;
+    }
+
+    /**
+     * Atomically decrements by one the current value.
+     *
+     * @return the updated value
+     */
+    public final int decrementAndGet() {
+        return U.getAndAddInt(this, VALUE, -1) - 1;
+    }
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final int addAndGet(int delta) {
+        return U.getAndAddInt(this, VALUE, delta) + delta;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndUpdate(IntUnaryOperator updateFunction) {
+        int prev, next;
+        do {
+            prev = get();
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int updateAndGet(IntUnaryOperator updateFunction) {
+        int prev, next;
+        do {
+            prev = get();
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndAccumulate(int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int accumulateAndGet(int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Integer.toString(get());
+    }
+
+    /**
+     * Returns the value of this {@code AtomicInteger} as an {@code int}.
+     * Equivalent to {@link #get()}.
+     */
+    public int intValue() {
+        return get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicInteger} as a {@code long}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public long longValue() {
+        return (long)get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicInteger} as a {@code float}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicInteger} as a {@code double}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public double doubleValue() {
+        return (double)get();
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicIntegerArray.java b/java/util/concurrent/atomic/AtomicIntegerArray.java
new file mode 100644
index 0000000..2ea9a27
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicIntegerArray.java
@@ -0,0 +1,364 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntUnaryOperator;
+
+/**
+ * An {@code int} array in which elements may be updated atomically.
+ * See the {@link java.util.concurrent.atomic} package
+ * specification for description of the properties of atomic
+ * variables.
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicIntegerArray implements java.io.Serializable {
+    private static final long serialVersionUID = 2862133569453604235L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final int ABASE;
+    private static final int ASHIFT;
+    private final int[] array;
+
+    static {
+        ABASE = U.arrayBaseOffset(int[].class);
+        int scale = U.arrayIndexScale(int[].class);
+        if ((scale & (scale - 1)) != 0)
+            throw new Error("array index scale not a power of two");
+        ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+    }
+
+    private long checkedByteOffset(int i) {
+        if (i < 0 || i >= array.length)
+            throw new IndexOutOfBoundsException("index " + i);
+
+        return byteOffset(i);
+    }
+
+    private static long byteOffset(int i) {
+        return ((long) i << ASHIFT) + ABASE;
+    }
+
+    /**
+     * Creates a new AtomicIntegerArray of the given length, with all
+     * elements initially zero.
+     *
+     * @param length the length of the array
+     */
+    public AtomicIntegerArray(int length) {
+        array = new int[length];
+    }
+
+    /**
+     * Creates a new AtomicIntegerArray with the same length as, and
+     * all elements copied from, the given array.
+     *
+     * @param array the array to copy elements from
+     * @throws NullPointerException if array is null
+     */
+    public AtomicIntegerArray(int[] array) {
+        // Visibility guaranteed by final field guarantees
+        this.array = array.clone();
+    }
+
+    /**
+     * Returns the length of the array.
+     *
+     * @return the length of the array
+     */
+    public final int length() {
+        return array.length;
+    }
+
+    /**
+     * Gets the current value at position {@code i}.
+     *
+     * @param i the index
+     * @return the current value
+     */
+    public final int get(int i) {
+        return getRaw(checkedByteOffset(i));
+    }
+
+    private int getRaw(long offset) {
+        return U.getIntVolatile(array, offset);
+    }
+
+    /**
+     * Sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     */
+    public final void set(int i, int newValue) {
+        U.putIntVolatile(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Eventually sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int i, int newValue) {
+        U.putOrderedInt(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * value and returns the old value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final int getAndSet(int i, int newValue) {
+        return U.getAndSetInt(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int i, int expect, int update) {
+        return compareAndSetRaw(checkedByteOffset(i), expect, update);
+    }
+
+    private boolean compareAndSetRaw(long offset, int expect, int update) {
+        return U.compareAndSwapInt(array, offset, expect, update);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(int i, int expect, int update) {
+        return compareAndSet(i, expect, update);
+    }
+
+    /**
+     * Atomically increments by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final int getAndIncrement(int i) {
+        return getAndAdd(i, 1);
+    }
+
+    /**
+     * Atomically decrements by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final int getAndDecrement(int i) {
+        return getAndAdd(i, -1);
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final int getAndAdd(int i, int delta) {
+        return U.getAndAddInt(array, checkedByteOffset(i), delta);
+    }
+
+    /**
+     * Atomically increments by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final int incrementAndGet(int i) {
+        return getAndAdd(i, 1) + 1;
+    }
+
+    /**
+     * Atomically decrements by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final int decrementAndGet(int i) {
+        return getAndAdd(i, -1) - 1;
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final int addAndGet(int i, int delta) {
+        return getAndAdd(i, delta) + delta;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndUpdate(int i, IntUnaryOperator updateFunction) {
+        long offset = checkedByteOffset(i);
+        int prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int updateAndGet(int i, IntUnaryOperator updateFunction) {
+        long offset = checkedByteOffset(i);
+        int prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the previous value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndAccumulate(int i, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        int prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the updated value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int accumulateAndGet(int i, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        int prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current values of array.
+     * @return the String representation of the current values of array
+     */
+    public String toString() {
+        int iMax = array.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(getRaw(byteOffset(i)));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(',').append(' ');
+        }
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
new file mode 100644
index 0000000..589d5da
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
@@ -0,0 +1,534 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntUnaryOperator;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+/**
+ * A reflection-based utility that enables atomic updates to
+ * designated {@code volatile int} fields of designated classes.
+ * This class is designed for use in atomic data structures in which
+ * several fields of the same node are independently subject to atomic
+ * updates.
+ *
+ * <p>Note that the guarantees of the {@code compareAndSet}
+ * method in this class are weaker than in other atomic classes.
+ * Because this class cannot ensure that all uses of the field
+ * are appropriate for purposes of atomic access, it can
+ * guarantee atomicity only with respect to other invocations of
+ * {@code compareAndSet} and {@code set} on the same updater.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <T> The type of the object holding the updatable field
+ */
+public abstract class AtomicIntegerFieldUpdater<T> {
+    /**
+     * Creates and returns an updater for objects with the given field.
+     * The Class argument is needed to check that reflective types and
+     * generic types match.
+     *
+     * @param tclass the class of the objects holding the field
+     * @param fieldName the name of the field to be updated
+     * @param <U> the type of instances of tclass
+     * @return the updater
+     * @throws IllegalArgumentException if the field is not a
+     * volatile integer type
+     * @throws RuntimeException with a nested reflection-based
+     * exception if the class does not hold field or is the wrong type,
+     * or the field is inaccessible to the caller according to Java language
+     * access control
+     */
+    @CallerSensitive
+    public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
+                                                              String fieldName) {
+        return new AtomicIntegerFieldUpdaterImpl<U>
+            (tclass, fieldName, Reflection.getCallerClass());
+    }
+
+    /**
+     * Protected do-nothing constructor for use by subclasses.
+     */
+    protected AtomicIntegerFieldUpdater() {
+    }
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     * @throws ClassCastException if {@code obj} is not an instance
+     * of the class possessing the field established in the constructor
+     */
+    public abstract boolean compareAndSet(T obj, int expect, int update);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     * @throws ClassCastException if {@code obj} is not an instance
+     * of the class possessing the field established in the constructor
+     */
+    public abstract boolean weakCompareAndSet(T obj, int expect, int update);
+
+    /**
+     * Sets the field of the given object managed by this updater to the
+     * given updated value. This operation is guaranteed to act as a volatile
+     * store with respect to subsequent invocations of {@code compareAndSet}.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     */
+    public abstract void set(T obj, int newValue);
+
+    /**
+     * Eventually sets the field of the given object managed by this
+     * updater to the given updated value.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public abstract void lazySet(T obj, int newValue);
+
+    /**
+     * Gets the current value held in the field of the given object managed
+     * by this updater.
+     *
+     * @param obj An object whose field to get
+     * @return the current value
+     */
+    public abstract int get(T obj);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given value and returns the old value.
+     *
+     * @param obj An object whose field to get and set
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public int getAndSet(T obj, int newValue) {
+        int prev;
+        do {
+            prev = get(obj);
+        } while (!compareAndSet(obj, prev, newValue));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public int getAndIncrement(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public int getAndDecrement(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public int getAndAdd(T obj, int delta) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public int incrementAndGet(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public int decrementAndGet(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public int addAndGet(T obj, int delta) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the previous
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndUpdate(T obj, IntUnaryOperator updateFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the updated
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int updateAndGet(T obj, IntUnaryOperator updateFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndAccumulate(T obj, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int accumulateAndGet(T obj, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Standard hotspot implementation using intrinsics.
+     */
+    private static final class AtomicIntegerFieldUpdaterImpl<T>
+        extends AtomicIntegerFieldUpdater<T> {
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+
+        AtomicIntegerFieldUpdaterImpl(final Class<T> tclass,
+                                      final String fieldName,
+                                      final Class<?> caller) {
+            final Field field;
+            final int modifiers;
+            try {
+                // BEGIN Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                // END Android-changed: Skip privilege escalation which is a noop on Android.
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // BEGIN Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+                // END Android-removed: Skip checkPackageAccess which is a noop on Android.
+            // BEGIN Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            // END Android-removed: Skip privilege escalation which is a noop on Android.
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (field.getType() != int.class)
+                throw new IllegalArgumentException("Must be integer type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            this.tclass = tclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        // BEGIN Android-removed: isAncestor()'s only usage was removed above.
+        /*
+        /**
+         * Returns true if the second classloader can be found in the first
+         * classloader's delegation chain.
+         * Equivalent to the inaccessible: first.isAncestor(second).
+         *
+        private static boolean isAncestor(ClassLoader first, ClassLoader second) {
+            ClassLoader acl = first;
+            do {
+                acl = acl.getParent();
+                if (second == acl) {
+                    return true;
+                }
+            } while (acl != null);
+            return false;
+        }
+        */
+        // END Android-removed: isAncestor()'s only usage was removed above.
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throwAccessCheckException(obj);
+        }
+
+        /**
+         * Throws access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final void throwAccessCheckException(T obj) {
+            if (cclass == tclass)
+                throw new ClassCastException();
+            else
+                throw new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        public final boolean compareAndSet(T obj, int expect, int update) {
+            accessCheck(obj);
+            return U.compareAndSwapInt(obj, offset, expect, update);
+        }
+
+        public final boolean weakCompareAndSet(T obj, int expect, int update) {
+            accessCheck(obj);
+            return U.compareAndSwapInt(obj, offset, expect, update);
+        }
+
+        public final void set(T obj, int newValue) {
+            accessCheck(obj);
+            U.putIntVolatile(obj, offset, newValue);
+        }
+
+        public final void lazySet(T obj, int newValue) {
+            accessCheck(obj);
+            U.putOrderedInt(obj, offset, newValue);
+        }
+
+        public final int get(T obj) {
+            accessCheck(obj);
+            return U.getIntVolatile(obj, offset);
+        }
+
+        public final int getAndSet(T obj, int newValue) {
+            accessCheck(obj);
+            return U.getAndSetInt(obj, offset, newValue);
+        }
+
+        public final int getAndAdd(T obj, int delta) {
+            accessCheck(obj);
+            return U.getAndAddInt(obj, offset, delta);
+        }
+
+        public final int getAndIncrement(T obj) {
+            return getAndAdd(obj, 1);
+        }
+
+        public final int getAndDecrement(T obj) {
+            return getAndAdd(obj, -1);
+        }
+
+        public final int incrementAndGet(T obj) {
+            return getAndAdd(obj, 1) + 1;
+        }
+
+        public final int decrementAndGet(T obj) {
+            return getAndAdd(obj, -1) - 1;
+        }
+
+        public final int addAndGet(T obj, int delta) {
+            return getAndAdd(obj, delta) + delta;
+        }
+
+    }
+}
diff --git a/java/util/concurrent/atomic/AtomicLong.java b/java/util/concurrent/atomic/AtomicLong.java
new file mode 100644
index 0000000..b919f1e
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicLong.java
@@ -0,0 +1,354 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongUnaryOperator;
+
+/**
+ * A {@code long} value that may be updated atomically.  See the
+ * {@link java.util.concurrent.atomic} package specification for
+ * description of the properties of atomic variables. An
+ * {@code AtomicLong} is used in applications such as atomically
+ * incremented sequence numbers, and cannot be used as a replacement
+ * for a {@link java.lang.Long}. However, this class does extend
+ * {@code Number} to allow uniform access by tools and utilities that
+ * deal with numerically-based classes.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicLong extends Number implements java.io.Serializable {
+    private static final long serialVersionUID = 1927816293512124184L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long VALUE;
+
+    /**
+     * Records whether the underlying JVM supports lockless
+     * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
+     * method works in either case, some constructions should be
+     * handled at Java level to avoid locking user-visible locks.
+     */
+    static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
+
+    /**
+     * Returns whether underlying JVM supports lockless CompareAndSet
+     * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
+     */
+    private static native boolean VMSupportsCS8();
+
+    static {
+        try {
+            VALUE = U.objectFieldOffset
+                (AtomicLong.class.getDeclaredField("value"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private volatile long value;
+
+    /**
+     * Creates a new AtomicLong with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicLong(long initialValue) {
+        value = initialValue;
+    }
+
+    /**
+     * Creates a new AtomicLong with initial value {@code 0}.
+     */
+    public AtomicLong() {
+    }
+
+    /**
+     * Gets the current value.
+     *
+     * @return the current value
+     */
+    public final long get() {
+        return value;
+    }
+
+    /**
+     * Sets to the given value.
+     *
+     * @param newValue the new value
+     */
+    public final void set(long newValue) {
+        // Use putLongVolatile instead of ordinary volatile store when
+        // using compareAndSwapLong, for sake of some 32bit systems.
+        U.putLongVolatile(this, VALUE, newValue);
+    }
+
+    /**
+     * Eventually sets to the given value.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(long newValue) {
+        U.putOrderedLong(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets to the given value and returns the old value.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final long getAndSet(long newValue) {
+        return U.getAndSetLong(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(long expect, long update) {
+        return U.compareAndSwapLong(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(long expect, long update) {
+        return U.compareAndSwapLong(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically increments by one the current value.
+     *
+     * @return the previous value
+     */
+    public final long getAndIncrement() {
+        return U.getAndAddLong(this, VALUE, 1L);
+    }
+
+    /**
+     * Atomically decrements by one the current value.
+     *
+     * @return the previous value
+     */
+    public final long getAndDecrement() {
+        return U.getAndAddLong(this, VALUE, -1L);
+    }
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final long getAndAdd(long delta) {
+        return U.getAndAddLong(this, VALUE, delta);
+    }
+
+    /**
+     * Atomically increments by one the current value.
+     *
+     * @return the updated value
+     */
+    public final long incrementAndGet() {
+        return U.getAndAddLong(this, VALUE, 1L) + 1L;
+    }
+
+    /**
+     * Atomically decrements by one the current value.
+     *
+     * @return the updated value
+     */
+    public final long decrementAndGet() {
+        return U.getAndAddLong(this, VALUE, -1L) - 1L;
+    }
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final long addAndGet(long delta) {
+        return U.getAndAddLong(this, VALUE, delta) + delta;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndUpdate(LongUnaryOperator updateFunction) {
+        long prev, next;
+        do {
+            prev = get();
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long updateAndGet(LongUnaryOperator updateFunction) {
+        long prev, next;
+        do {
+            prev = get();
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndAccumulate(long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long accumulateAndGet(long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Long.toString(get());
+    }
+
+    /**
+     * Returns the value of this {@code AtomicLong} as an {@code int}
+     * after a narrowing primitive conversion.
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public int intValue() {
+        return (int)get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicLong} as a {@code long}.
+     * Equivalent to {@link #get()}.
+     */
+    public long longValue() {
+        return get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicLong} as a {@code float}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicLong} as a {@code double}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public double doubleValue() {
+        return (double)get();
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicLongArray.java b/java/util/concurrent/atomic/AtomicLongArray.java
new file mode 100644
index 0000000..d1af039
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicLongArray.java
@@ -0,0 +1,363 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongUnaryOperator;
+
+/**
+ * A {@code long} array in which elements may be updated atomically.
+ * See the {@link java.util.concurrent.atomic} package specification
+ * for description of the properties of atomic variables.
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicLongArray implements java.io.Serializable {
+    private static final long serialVersionUID = -2308431214976778248L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final int ABASE;
+    private static final int ASHIFT;
+    private final long[] array;
+
+    static {
+        ABASE = U.arrayBaseOffset(long[].class);
+        int scale = U.arrayIndexScale(long[].class);
+        if ((scale & (scale - 1)) != 0)
+            throw new Error("array index scale not a power of two");
+        ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+    }
+
+    private long checkedByteOffset(int i) {
+        if (i < 0 || i >= array.length)
+            throw new IndexOutOfBoundsException("index " + i);
+
+        return byteOffset(i);
+    }
+
+    private static long byteOffset(int i) {
+        return ((long) i << ASHIFT) + ABASE;
+    }
+
+    /**
+     * Creates a new AtomicLongArray of the given length, with all
+     * elements initially zero.
+     *
+     * @param length the length of the array
+     */
+    public AtomicLongArray(int length) {
+        array = new long[length];
+    }
+
+    /**
+     * Creates a new AtomicLongArray with the same length as, and
+     * all elements copied from, the given array.
+     *
+     * @param array the array to copy elements from
+     * @throws NullPointerException if array is null
+     */
+    public AtomicLongArray(long[] array) {
+        // Visibility guaranteed by final field guarantees
+        this.array = array.clone();
+    }
+
+    /**
+     * Returns the length of the array.
+     *
+     * @return the length of the array
+     */
+    public final int length() {
+        return array.length;
+    }
+
+    /**
+     * Gets the current value at position {@code i}.
+     *
+     * @param i the index
+     * @return the current value
+     */
+    public final long get(int i) {
+        return getRaw(checkedByteOffset(i));
+    }
+
+    private long getRaw(long offset) {
+        return U.getLongVolatile(array, offset);
+    }
+
+    /**
+     * Sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     */
+    public final void set(int i, long newValue) {
+        U.putLongVolatile(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Eventually sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int i, long newValue) {
+        U.putOrderedLong(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given value
+     * and returns the old value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final long getAndSet(int i, long newValue) {
+        return U.getAndSetLong(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int i, long expect, long update) {
+        return compareAndSetRaw(checkedByteOffset(i), expect, update);
+    }
+
+    private boolean compareAndSetRaw(long offset, long expect, long update) {
+        return U.compareAndSwapLong(array, offset, expect, update);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(int i, long expect, long update) {
+        return compareAndSet(i, expect, update);
+    }
+
+    /**
+     * Atomically increments by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final long getAndIncrement(int i) {
+        return getAndAdd(i, 1);
+    }
+
+    /**
+     * Atomically decrements by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final long getAndDecrement(int i) {
+        return getAndAdd(i, -1);
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final long getAndAdd(int i, long delta) {
+        return U.getAndAddLong(array, checkedByteOffset(i), delta);
+    }
+
+    /**
+     * Atomically increments by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final long incrementAndGet(int i) {
+        return getAndAdd(i, 1) + 1;
+    }
+
+    /**
+     * Atomically decrements by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final long decrementAndGet(int i) {
+        return getAndAdd(i, -1) - 1;
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public long addAndGet(int i, long delta) {
+        return getAndAdd(i, delta) + delta;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndUpdate(int i, LongUnaryOperator updateFunction) {
+        long offset = checkedByteOffset(i);
+        long prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long updateAndGet(int i, LongUnaryOperator updateFunction) {
+        long offset = checkedByteOffset(i);
+        long prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the previous value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndAccumulate(int i, long x,
+                                      LongBinaryOperator accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        long prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the updated value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long accumulateAndGet(int i, long x,
+                                      LongBinaryOperator accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        long prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current values of array.
+     * @return the String representation of the current values of array
+     */
+    public String toString() {
+        int iMax = array.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(getRaw(byteOffset(i)));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(',').append(' ');
+        }
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
new file mode 100644
index 0000000..447a642
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -0,0 +1,646 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongUnaryOperator;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+/**
+ * A reflection-based utility that enables atomic updates to
+ * designated {@code volatile long} fields of designated classes.
+ * This class is designed for use in atomic data structures in which
+ * several fields of the same node are independently subject to atomic
+ * updates.
+ *
+ * <p>Note that the guarantees of the {@code compareAndSet}
+ * method in this class are weaker than in other atomic classes.
+ * Because this class cannot ensure that all uses of the field
+ * are appropriate for purposes of atomic access, it can
+ * guarantee atomicity only with respect to other invocations of
+ * {@code compareAndSet} and {@code set} on the same updater.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <T> The type of the object holding the updatable field
+ */
+public abstract class AtomicLongFieldUpdater<T> {
+    /**
+     * Creates and returns an updater for objects with the given field.
+     * The Class argument is needed to check that reflective types and
+     * generic types match.
+     *
+     * @param tclass the class of the objects holding the field
+     * @param fieldName the name of the field to be updated
+     * @param <U> the type of instances of tclass
+     * @return the updater
+     * @throws IllegalArgumentException if the field is not a
+     * volatile long type
+     * @throws RuntimeException with a nested reflection-based
+     * exception if the class does not hold field or is the wrong type,
+     * or the field is inaccessible to the caller according to Java language
+     * access control
+     */
+    @CallerSensitive
+    public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass,
+                                                           String fieldName) {
+        Class<?> caller = Reflection.getCallerClass();
+        if (AtomicLong.VM_SUPPORTS_LONG_CAS)
+            return new CASUpdater<U>(tclass, fieldName, caller);
+        else
+            return new LockedUpdater<U>(tclass, fieldName, caller);
+    }
+
+    /**
+     * Protected do-nothing constructor for use by subclasses.
+     */
+    protected AtomicLongFieldUpdater() {
+    }
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     * @throws ClassCastException if {@code obj} is not an instance
+     * of the class possessing the field established in the constructor
+     */
+    public abstract boolean compareAndSet(T obj, long expect, long update);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     * @throws ClassCastException if {@code obj} is not an instance
+     * of the class possessing the field established in the constructor
+     */
+    public abstract boolean weakCompareAndSet(T obj, long expect, long update);
+
+    /**
+     * Sets the field of the given object managed by this updater to the
+     * given updated value. This operation is guaranteed to act as a volatile
+     * store with respect to subsequent invocations of {@code compareAndSet}.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     */
+    public abstract void set(T obj, long newValue);
+
+    /**
+     * Eventually sets the field of the given object managed by this
+     * updater to the given updated value.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public abstract void lazySet(T obj, long newValue);
+
+    /**
+     * Gets the current value held in the field of the given object managed
+     * by this updater.
+     *
+     * @param obj An object whose field to get
+     * @return the current value
+     */
+    public abstract long get(T obj);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given value and returns the old value.
+     *
+     * @param obj An object whose field to get and set
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public long getAndSet(T obj, long newValue) {
+        long prev;
+        do {
+            prev = get(obj);
+        } while (!compareAndSet(obj, prev, newValue));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public long getAndIncrement(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public long getAndDecrement(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public long getAndAdd(T obj, long delta) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public long incrementAndGet(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public long decrementAndGet(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public long addAndGet(T obj, long delta) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the previous
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndUpdate(T obj, LongUnaryOperator updateFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the updated
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long updateAndGet(T obj, LongUnaryOperator updateFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndAccumulate(T obj, long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long accumulateAndGet(T obj, long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+
+        CASUpdater(final Class<T> tclass, final String fieldName,
+                   final Class<?> caller) {
+            final Field field;
+            final int modifiers;
+            try {
+                // Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+            // Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (field.getType() != long.class)
+                throw new IllegalArgumentException("Must be long type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            this.tclass = tclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throwAccessCheckException(obj);
+        }
+
+        /**
+         * Throws access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final void throwAccessCheckException(T obj) {
+            if (cclass == tclass)
+                throw new ClassCastException();
+            else
+                throw new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        public final boolean compareAndSet(T obj, long expect, long update) {
+            accessCheck(obj);
+            return U.compareAndSwapLong(obj, offset, expect, update);
+        }
+
+        public final boolean weakCompareAndSet(T obj, long expect, long update) {
+            accessCheck(obj);
+            return U.compareAndSwapLong(obj, offset, expect, update);
+        }
+
+        public final void set(T obj, long newValue) {
+            accessCheck(obj);
+            U.putLongVolatile(obj, offset, newValue);
+        }
+
+        public final void lazySet(T obj, long newValue) {
+            accessCheck(obj);
+            U.putOrderedLong(obj, offset, newValue);
+        }
+
+        public final long get(T obj) {
+            accessCheck(obj);
+            return U.getLongVolatile(obj, offset);
+        }
+
+        public final long getAndSet(T obj, long newValue) {
+            accessCheck(obj);
+            return U.getAndSetLong(obj, offset, newValue);
+        }
+
+        public final long getAndAdd(T obj, long delta) {
+            accessCheck(obj);
+            return U.getAndAddLong(obj, offset, delta);
+        }
+
+        public final long getAndIncrement(T obj) {
+            return getAndAdd(obj, 1);
+        }
+
+        public final long getAndDecrement(T obj) {
+            return getAndAdd(obj, -1);
+        }
+
+        public final long incrementAndGet(T obj) {
+            return getAndAdd(obj, 1) + 1;
+        }
+
+        public final long decrementAndGet(T obj) {
+            return getAndAdd(obj, -1) - 1;
+        }
+
+        public final long addAndGet(T obj, long delta) {
+            return getAndAdd(obj, delta) + delta;
+        }
+    }
+
+    private static final class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+
+        LockedUpdater(final Class<T> tclass, final String fieldName,
+                      final Class<?> caller) {
+            Field field = null;
+            int modifiers = 0;
+            try {
+                // Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+            // Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (field.getType() != long.class)
+                throw new IllegalArgumentException("Must be long type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            this.tclass = tclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throw accessCheckException(obj);
+        }
+
+        /**
+         * Returns access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final RuntimeException accessCheckException(T obj) {
+            if (cclass == tclass)
+                return new ClassCastException();
+            else
+                return new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        public final boolean compareAndSet(T obj, long expect, long update) {
+            accessCheck(obj);
+            synchronized (this) {
+                long v = U.getLong(obj, offset);
+                if (v != expect)
+                    return false;
+                U.putLong(obj, offset, update);
+                return true;
+            }
+        }
+
+        public final boolean weakCompareAndSet(T obj, long expect, long update) {
+            return compareAndSet(obj, expect, update);
+        }
+
+        public final void set(T obj, long newValue) {
+            accessCheck(obj);
+            synchronized (this) {
+                U.putLong(obj, offset, newValue);
+            }
+        }
+
+        public final void lazySet(T obj, long newValue) {
+            set(obj, newValue);
+        }
+
+        public final long get(T obj) {
+            accessCheck(obj);
+            synchronized (this) {
+                return U.getLong(obj, offset);
+            }
+        }
+    }
+
+    // Android-removed: isAncestor's only usage was removed above.
+    /*
+    /**
+     * Returns true if the second classloader can be found in the first
+     * classloader's delegation chain.
+     * Equivalent to the inaccessible: first.isAncestor(second).
+     *
+    static boolean isAncestor(ClassLoader first, ClassLoader second) {
+        ClassLoader acl = first;
+        do {
+            acl = acl.getParent();
+            if (second == acl) {
+                return true;
+            }
+        } while (acl != null);
+        return false;
+    }
+    */
+}
diff --git a/java/util/concurrent/atomic/AtomicMarkableReference.java b/java/util/concurrent/atomic/AtomicMarkableReference.java
new file mode 100644
index 0000000..b49118b
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicMarkableReference.java
@@ -0,0 +1,207 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+/**
+ * An {@code AtomicMarkableReference} maintains an object reference
+ * along with a mark bit, that can be updated atomically.
+ *
+ * <p>Implementation note: This implementation maintains markable
+ * references by creating internal objects representing "boxed"
+ * [reference, boolean] pairs.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The type of object referred to by this reference
+ */
+public class AtomicMarkableReference<V> {
+
+    private static class Pair<T> {
+        final T reference;
+        final boolean mark;
+        private Pair(T reference, boolean mark) {
+            this.reference = reference;
+            this.mark = mark;
+        }
+        static <T> Pair<T> of(T reference, boolean mark) {
+            return new Pair<T>(reference, mark);
+        }
+    }
+
+    private volatile Pair<V> pair;
+
+    /**
+     * Creates a new {@code AtomicMarkableReference} with the given
+     * initial values.
+     *
+     * @param initialRef the initial reference
+     * @param initialMark the initial mark
+     */
+    public AtomicMarkableReference(V initialRef, boolean initialMark) {
+        pair = Pair.of(initialRef, initialMark);
+    }
+
+    /**
+     * Returns the current value of the reference.
+     *
+     * @return the current value of the reference
+     */
+    public V getReference() {
+        return pair.reference;
+    }
+
+    /**
+     * Returns the current value of the mark.
+     *
+     * @return the current value of the mark
+     */
+    public boolean isMarked() {
+        return pair.mark;
+    }
+
+    /**
+     * Returns the current values of both the reference and the mark.
+     * Typical usage is {@code boolean[1] holder; ref = v.get(holder); }.
+     *
+     * @param markHolder an array of size of at least one. On return,
+     * {@code markHolder[0]} will hold the value of the mark.
+     * @return the current value of the reference
+     */
+    public V get(boolean[] markHolder) {
+        Pair<V> pair = this.pair;
+        markHolder[0] = pair.mark;
+        return pair.reference;
+    }
+
+    /**
+     * Atomically sets the value of both the reference and mark
+     * to the given update values if the
+     * current reference is {@code ==} to the expected reference
+     * and the current mark is equal to the expected mark.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedMark the expected value of the mark
+     * @param newMark the new value for the mark
+     * @return {@code true} if successful
+     */
+    public boolean weakCompareAndSet(V       expectedReference,
+                                     V       newReference,
+                                     boolean expectedMark,
+                                     boolean newMark) {
+        return compareAndSet(expectedReference, newReference,
+                             expectedMark, newMark);
+    }
+
+    /**
+     * Atomically sets the value of both the reference and mark
+     * to the given update values if the
+     * current reference is {@code ==} to the expected reference
+     * and the current mark is equal to the expected mark.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedMark the expected value of the mark
+     * @param newMark the new value for the mark
+     * @return {@code true} if successful
+     */
+    public boolean compareAndSet(V       expectedReference,
+                                 V       newReference,
+                                 boolean expectedMark,
+                                 boolean newMark) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            expectedMark == current.mark &&
+            ((newReference == current.reference &&
+              newMark == current.mark) ||
+             casPair(current, Pair.of(newReference, newMark)));
+    }
+
+    /**
+     * Unconditionally sets the value of both the reference and mark.
+     *
+     * @param newReference the new value for the reference
+     * @param newMark the new value for the mark
+     */
+    public void set(V newReference, boolean newMark) {
+        Pair<V> current = pair;
+        if (newReference != current.reference || newMark != current.mark)
+            this.pair = Pair.of(newReference, newMark);
+    }
+
+    /**
+     * Atomically sets the value of the mark to the given update value
+     * if the current reference is {@code ==} to the expected
+     * reference.  Any given invocation of this operation may fail
+     * (return {@code false}) spuriously, but repeated invocation
+     * when the current value holds the expected value and no other
+     * thread is also attempting to set the value will eventually
+     * succeed.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newMark the new value for the mark
+     * @return {@code true} if successful
+     */
+    public boolean attemptMark(V expectedReference, boolean newMark) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            (newMark == current.mark ||
+             casPair(current, Pair.of(expectedReference, newMark)));
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long PAIR;
+    static {
+        try {
+            PAIR = U.objectFieldOffset
+                (AtomicMarkableReference.class.getDeclaredField("pair"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private boolean casPair(Pair<V> cmp, Pair<V> val) {
+        return U.compareAndSwapObject(this, PAIR, cmp, val);
+    }
+}
diff --git a/java/util/concurrent/atomic/AtomicReference.java b/java/util/concurrent/atomic/AtomicReference.java
new file mode 100644
index 0000000..dbc6685
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicReference.java
@@ -0,0 +1,242 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+
+/**
+ * An object reference that may be updated atomically. See the {@link
+ * java.util.concurrent.atomic} package specification for description
+ * of the properties of atomic variables.
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The type of object referred to by this reference
+ */
+public class AtomicReference<V> implements java.io.Serializable {
+    private static final long serialVersionUID = -1848883965231344442L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long VALUE;
+
+    static {
+        try {
+            VALUE = U.objectFieldOffset
+                (AtomicReference.class.getDeclaredField("value"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private volatile V value;
+
+    /**
+     * Creates a new AtomicReference with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicReference(V initialValue) {
+        value = initialValue;
+    }
+
+    /**
+     * Creates a new AtomicReference with null initial value.
+     */
+    public AtomicReference() {
+    }
+
+    /**
+     * Gets the current value.
+     *
+     * @return the current value
+     */
+    public final V get() {
+        return value;
+    }
+
+    /**
+     * Sets to the given value.
+     *
+     * @param newValue the new value
+     */
+    public final void set(V newValue) {
+        value = newValue;
+    }
+
+    /**
+     * Eventually sets to the given value.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(V newValue) {
+        U.putOrderedObject(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(V expect, V update) {
+        return U.compareAndSwapObject(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(V expect, V update) {
+        return U.compareAndSwapObject(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically sets to the given value and returns the old value.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    @SuppressWarnings("unchecked")
+    public final V getAndSet(V newValue) {
+        return (V)U.getAndSetObject(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndUpdate(UnaryOperator<V> updateFunction) {
+        V prev, next;
+        do {
+            prev = get();
+            next = updateFunction.apply(prev);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V updateAndGet(UnaryOperator<V> updateFunction) {
+        V prev, next;
+        do {
+            prev = get();
+            next = updateFunction.apply(prev);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndAccumulate(V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V accumulateAndGet(V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return String.valueOf(get());
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicReferenceArray.java b/java/util/concurrent/atomic/AtomicReferenceArray.java
new file mode 100644
index 0000000..cce148e
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicReferenceArray.java
@@ -0,0 +1,332 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+
+/**
+ * An array of object references in which elements may be updated
+ * atomically.  See the {@link java.util.concurrent.atomic} package
+ * specification for description of the properties of atomic
+ * variables.
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> The base class of elements held in this array
+ */
+public class AtomicReferenceArray<E> implements java.io.Serializable {
+    private static final long serialVersionUID = -6209656149925076980L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long ARRAY;
+    private static final int ABASE;
+    private static final int ASHIFT;
+    private final Object[] array; // must have exact type Object[]
+
+    static {
+        try {
+            ARRAY = U.objectFieldOffset
+                (AtomicReferenceArray.class.getDeclaredField("array"));
+            ABASE = U.arrayBaseOffset(Object[].class);
+            int scale = U.arrayIndexScale(Object[].class);
+            if ((scale & (scale - 1)) != 0)
+                throw new Error("array index scale not a power of two");
+            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private long checkedByteOffset(int i) {
+        if (i < 0 || i >= array.length)
+            throw new IndexOutOfBoundsException("index " + i);
+
+        return byteOffset(i);
+    }
+
+    private static long byteOffset(int i) {
+        return ((long) i << ASHIFT) + ABASE;
+    }
+
+    /**
+     * Creates a new AtomicReferenceArray of the given length, with all
+     * elements initially null.
+     *
+     * @param length the length of the array
+     */
+    public AtomicReferenceArray(int length) {
+        array = new Object[length];
+    }
+
+    /**
+     * Creates a new AtomicReferenceArray with the same length as, and
+     * all elements copied from, the given array.
+     *
+     * @param array the array to copy elements from
+     * @throws NullPointerException if array is null
+     */
+    public AtomicReferenceArray(E[] array) {
+        // Visibility guaranteed by final field guarantees
+        this.array = Arrays.copyOf(array, array.length, Object[].class);
+    }
+
+    /**
+     * Returns the length of the array.
+     *
+     * @return the length of the array
+     */
+    public final int length() {
+        return array.length;
+    }
+
+    /**
+     * Gets the current value at position {@code i}.
+     *
+     * @param i the index
+     * @return the current value
+     */
+    public final E get(int i) {
+        return getRaw(checkedByteOffset(i));
+    }
+
+    @SuppressWarnings("unchecked")
+    private E getRaw(long offset) {
+        return (E) U.getObjectVolatile(array, offset);
+    }
+
+    /**
+     * Sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     */
+    public final void set(int i, E newValue) {
+        U.putObjectVolatile(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Eventually sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int i, E newValue) {
+        U.putOrderedObject(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * value and returns the old value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @return the previous value
+     */
+    @SuppressWarnings("unchecked")
+    public final E getAndSet(int i, E newValue) {
+        return (E)U.getAndSetObject(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int i, E expect, E update) {
+        return compareAndSetRaw(checkedByteOffset(i), expect, update);
+    }
+
+    private boolean compareAndSetRaw(long offset, E expect, E update) {
+        return U.compareAndSwapObject(array, offset, expect, update);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(int i, E expect, E update) {
+        return compareAndSet(i, expect, update);
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final E getAndUpdate(int i, UnaryOperator<E> updateFunction) {
+        long offset = checkedByteOffset(i);
+        E prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.apply(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final E updateAndGet(int i, UnaryOperator<E> updateFunction) {
+        long offset = checkedByteOffset(i);
+        E prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.apply(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the previous value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final E getAndAccumulate(int i, E x,
+                                    BinaryOperator<E> accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        E prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the updated value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final E accumulateAndGet(int i, E x,
+                                    BinaryOperator<E> accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        E prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current values of array.
+     * @return the String representation of the current values of array
+     */
+    public String toString() {
+        int iMax = array.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(getRaw(byteOffset(i)));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(',').append(' ');
+        }
+    }
+
+    /**
+     * Reconstitutes the instance from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Note: This must be changed if any additional fields are defined
+        Object a = s.readFields().get("array", null);
+        if (a == null || !a.getClass().isArray())
+            throw new java.io.InvalidObjectException("Not array type");
+        if (a.getClass() != Object[].class)
+            a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class);
+        U.putObjectVolatile(this, ARRAY, a);
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
new file mode 100644
index 0000000..17423ad
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -0,0 +1,458 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+/**
+ * A reflection-based utility that enables atomic updates to
+ * designated {@code volatile} reference fields of designated
+ * classes.  This class is designed for use in atomic data structures
+ * in which several reference fields of the same node are
+ * independently subject to atomic updates. For example, a tree node
+ * might be declared as
+ *
+ * <pre> {@code
+ * class Node {
+ *   private volatile Node left, right;
+ *
+ *   private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
+ *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
+ *   private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
+ *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
+ *
+ *   Node getLeft() { return left; }
+ *   boolean compareAndSetLeft(Node expect, Node update) {
+ *     return leftUpdater.compareAndSet(this, expect, update);
+ *   }
+ *   // ... and so on
+ * }}</pre>
+ *
+ * <p>Note that the guarantees of the {@code compareAndSet}
+ * method in this class are weaker than in other atomic classes.
+ * Because this class cannot ensure that all uses of the field
+ * are appropriate for purposes of atomic access, it can
+ * guarantee atomicity only with respect to other invocations of
+ * {@code compareAndSet} and {@code set} on the same updater.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <T> The type of the object holding the updatable field
+ * @param <V> The type of the field
+ */
+public abstract class AtomicReferenceFieldUpdater<T,V> {
+
+    /**
+     * Creates and returns an updater for objects with the given field.
+     * The Class arguments are needed to check that reflective types and
+     * generic types match.
+     *
+     * @param tclass the class of the objects holding the field
+     * @param vclass the class of the field
+     * @param fieldName the name of the field to be updated
+     * @param <U> the type of instances of tclass
+     * @param <W> the type of instances of vclass
+     * @return the updater
+     * @throws ClassCastException if the field is of the wrong type
+     * @throws IllegalArgumentException if the field is not volatile
+     * @throws RuntimeException with a nested reflection-based
+     * exception if the class does not hold field or is the wrong type,
+     * or the field is inaccessible to the caller according to Java language
+     * access control
+     */
+    @CallerSensitive
+    public static <U,W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass,
+                                                                    Class<W> vclass,
+                                                                    String fieldName) {
+        return new AtomicReferenceFieldUpdaterImpl<U,W>
+            (tclass, vclass, fieldName, Reflection.getCallerClass());
+    }
+
+    /**
+     * Protected do-nothing constructor for use by subclasses.
+     */
+    protected AtomicReferenceFieldUpdater() {
+    }
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public abstract boolean compareAndSet(T obj, V expect, V update);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public abstract boolean weakCompareAndSet(T obj, V expect, V update);
+
+    /**
+     * Sets the field of the given object managed by this updater to the
+     * given updated value. This operation is guaranteed to act as a volatile
+     * store with respect to subsequent invocations of {@code compareAndSet}.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     */
+    public abstract void set(T obj, V newValue);
+
+    /**
+     * Eventually sets the field of the given object managed by this
+     * updater to the given updated value.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public abstract void lazySet(T obj, V newValue);
+
+    /**
+     * Gets the current value held in the field of the given object managed
+     * by this updater.
+     *
+     * @param obj An object whose field to get
+     * @return the current value
+     */
+    public abstract V get(T obj);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given value and returns the old value.
+     *
+     * @param obj An object whose field to get and set
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public V getAndSet(T obj, V newValue) {
+        V prev;
+        do {
+            prev = get(obj);
+        } while (!compareAndSet(obj, prev, newValue));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the previous
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndUpdate(T obj, UnaryOperator<V> updateFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.apply(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the updated
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V updateAndGet(T obj, UnaryOperator<V> updateFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.apply(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndAccumulate(T obj, V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V accumulateAndGet(T obj, V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    private static final class AtomicReferenceFieldUpdaterImpl<T,V>
+        extends AtomicReferenceFieldUpdater<T,V> {
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+        /** field value type */
+        private final Class<V> vclass;
+
+        /*
+         * Internal type checks within all update methods contain
+         * internal inlined optimizations checking for the common
+         * cases where the class is final (in which case a simple
+         * getClass comparison suffices) or is of type Object (in
+         * which case no check is needed because all objects are
+         * instances of Object). The Object case is handled simply by
+         * setting vclass to null in constructor.  The targetCheck and
+         * updateCheck methods are invoked when these faster
+         * screenings fail.
+         */
+
+        AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
+                                        final Class<V> vclass,
+                                        final String fieldName,
+                                        final Class<?> caller) {
+            final Field field;
+            final Class<?> fieldClass;
+            final int modifiers;
+            try {
+                // Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+                fieldClass = field.getType();
+            // Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (vclass != fieldClass)
+                throw new ClassCastException();
+            if (vclass.isPrimitive())
+                throw new IllegalArgumentException("Must be reference type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            this.tclass = tclass;
+            this.vclass = vclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        // Android-removed: isAncestor's only usage was removed above.
+        /*
+        /**
+         * Returns true if the second classloader can be found in the first
+         * classloader's delegation chain.
+         * Equivalent to the inaccessible: first.isAncestor(second).
+         *
+        private static boolean isAncestor(ClassLoader first, ClassLoader second) {
+            ClassLoader acl = first;
+            do {
+                acl = acl.getParent();
+                if (second == acl) {
+                    return true;
+                }
+            } while (acl != null);
+            return false;
+        }
+        */
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throwAccessCheckException(obj);
+        }
+
+        /**
+         * Throws access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final void throwAccessCheckException(T obj) {
+            if (cclass == tclass)
+                throw new ClassCastException();
+            else
+                throw new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        private final void valueCheck(V v) {
+            if (v != null && !(vclass.isInstance(v)))
+                throwCCE();
+        }
+
+        static void throwCCE() {
+            throw new ClassCastException();
+        }
+
+        public final boolean compareAndSet(T obj, V expect, V update) {
+            accessCheck(obj);
+            valueCheck(update);
+            return U.compareAndSwapObject(obj, offset, expect, update);
+        }
+
+        public final boolean weakCompareAndSet(T obj, V expect, V update) {
+            // same implementation as strong form for now
+            accessCheck(obj);
+            valueCheck(update);
+            return U.compareAndSwapObject(obj, offset, expect, update);
+        }
+
+        public final void set(T obj, V newValue) {
+            accessCheck(obj);
+            valueCheck(newValue);
+            U.putObjectVolatile(obj, offset, newValue);
+        }
+
+        public final void lazySet(T obj, V newValue) {
+            accessCheck(obj);
+            valueCheck(newValue);
+            U.putOrderedObject(obj, offset, newValue);
+        }
+
+        @SuppressWarnings("unchecked")
+        public final V get(T obj) {
+            accessCheck(obj);
+            return (V)U.getObjectVolatile(obj, offset);
+        }
+
+        @SuppressWarnings("unchecked")
+        public final V getAndSet(T obj, V newValue) {
+            accessCheck(obj);
+            valueCheck(newValue);
+            return (V)U.getAndSetObject(obj, offset, newValue);
+        }
+    }
+}
diff --git a/java/util/concurrent/atomic/AtomicStampedReference.java b/java/util/concurrent/atomic/AtomicStampedReference.java
new file mode 100644
index 0000000..40ceeb2
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicStampedReference.java
@@ -0,0 +1,207 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+/**
+ * An {@code AtomicStampedReference} maintains an object reference
+ * along with an integer "stamp", that can be updated atomically.
+ *
+ * <p>Implementation note: This implementation maintains stamped
+ * references by creating internal objects representing "boxed"
+ * [reference, integer] pairs.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The type of object referred to by this reference
+ */
+public class AtomicStampedReference<V> {
+
+    private static class Pair<T> {
+        final T reference;
+        final int stamp;
+        private Pair(T reference, int stamp) {
+            this.reference = reference;
+            this.stamp = stamp;
+        }
+        static <T> Pair<T> of(T reference, int stamp) {
+            return new Pair<T>(reference, stamp);
+        }
+    }
+
+    private volatile Pair<V> pair;
+
+    /**
+     * Creates a new {@code AtomicStampedReference} with the given
+     * initial values.
+     *
+     * @param initialRef the initial reference
+     * @param initialStamp the initial stamp
+     */
+    public AtomicStampedReference(V initialRef, int initialStamp) {
+        pair = Pair.of(initialRef, initialStamp);
+    }
+
+    /**
+     * Returns the current value of the reference.
+     *
+     * @return the current value of the reference
+     */
+    public V getReference() {
+        return pair.reference;
+    }
+
+    /**
+     * Returns the current value of the stamp.
+     *
+     * @return the current value of the stamp
+     */
+    public int getStamp() {
+        return pair.stamp;
+    }
+
+    /**
+     * Returns the current values of both the reference and the stamp.
+     * Typical usage is {@code int[1] holder; ref = v.get(holder); }.
+     *
+     * @param stampHolder an array of size of at least one.  On return,
+     * {@code stampHolder[0]} will hold the value of the stamp.
+     * @return the current value of the reference
+     */
+    public V get(int[] stampHolder) {
+        Pair<V> pair = this.pair;
+        stampHolder[0] = pair.stamp;
+        return pair.reference;
+    }
+
+    /**
+     * Atomically sets the value of both the reference and stamp
+     * to the given update values if the
+     * current reference is {@code ==} to the expected reference
+     * and the current stamp is equal to the expected stamp.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedStamp the expected value of the stamp
+     * @param newStamp the new value for the stamp
+     * @return {@code true} if successful
+     */
+    public boolean weakCompareAndSet(V   expectedReference,
+                                     V   newReference,
+                                     int expectedStamp,
+                                     int newStamp) {
+        return compareAndSet(expectedReference, newReference,
+                             expectedStamp, newStamp);
+    }
+
+    /**
+     * Atomically sets the value of both the reference and stamp
+     * to the given update values if the
+     * current reference is {@code ==} to the expected reference
+     * and the current stamp is equal to the expected stamp.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedStamp the expected value of the stamp
+     * @param newStamp the new value for the stamp
+     * @return {@code true} if successful
+     */
+    public boolean compareAndSet(V   expectedReference,
+                                 V   newReference,
+                                 int expectedStamp,
+                                 int newStamp) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            expectedStamp == current.stamp &&
+            ((newReference == current.reference &&
+              newStamp == current.stamp) ||
+             casPair(current, Pair.of(newReference, newStamp)));
+    }
+
+    /**
+     * Unconditionally sets the value of both the reference and stamp.
+     *
+     * @param newReference the new value for the reference
+     * @param newStamp the new value for the stamp
+     */
+    public void set(V newReference, int newStamp) {
+        Pair<V> current = pair;
+        if (newReference != current.reference || newStamp != current.stamp)
+            this.pair = Pair.of(newReference, newStamp);
+    }
+
+    /**
+     * Atomically sets the value of the stamp to the given update value
+     * if the current reference is {@code ==} to the expected
+     * reference.  Any given invocation of this operation may fail
+     * (return {@code false}) spuriously, but repeated invocation
+     * when the current value holds the expected value and no other
+     * thread is also attempting to set the value will eventually
+     * succeed.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newStamp the new value for the stamp
+     * @return {@code true} if successful
+     */
+    public boolean attemptStamp(V expectedReference, int newStamp) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            (newStamp == current.stamp ||
+             casPair(current, Pair.of(expectedReference, newStamp)));
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long PAIR;
+    static {
+        try {
+            PAIR = U.objectFieldOffset
+                (AtomicStampedReference.class.getDeclaredField("pair"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private boolean casPair(Pair<V> cmp, Pair<V> val) {
+        return U.compareAndSwapObject(this, PAIR, cmp, val);
+    }
+}
diff --git a/java/util/concurrent/atomic/DoubleAccumulator.java b/java/util/concurrent/atomic/DoubleAccumulator.java
new file mode 100644
index 0000000..f3e3531
--- /dev/null
+++ b/java/util/concurrent/atomic/DoubleAccumulator.java
@@ -0,0 +1,299 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+import java.util.function.DoubleBinaryOperator;
+
+/**
+ * One or more variables that together maintain a running {@code double}
+ * value updated using a supplied function.  When updates (method
+ * {@link #accumulate}) are contended across threads, the set of variables
+ * may grow dynamically to reduce contention.  Method {@link #get}
+ * (or, equivalently, {@link #doubleValue}) returns the current value
+ * across the variables maintaining updates.
+ *
+ * <p>This class is usually preferable to alternatives when multiple
+ * threads update a common value that is used for purposes such as
+ * summary statistics that are frequently updated but less frequently
+ * read.
+ *
+ * <p>The supplied accumulator function should be side-effect-free,
+ * since it may be re-applied when attempted updates fail due to
+ * contention among threads. The function is applied with the current
+ * value as its first argument, and the given update as the second
+ * argument.  For example, to maintain a running maximum value, you
+ * could supply {@code Double::max} along with {@code
+ * Double.NEGATIVE_INFINITY} as the identity. The order of
+ * accumulation within or across threads is not guaranteed. Thus, this
+ * class may not be applicable if numerical stability is required,
+ * especially when combining values of substantially different orders
+ * of magnitude.
+ *
+ * <p>Class {@link DoubleAdder} provides analogs of the functionality
+ * of this class for the common special case of maintaining sums.  The
+ * call {@code new DoubleAdder()} is equivalent to {@code new
+ * DoubleAccumulator((x, y) -> x + y, 0.0)}.
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class DoubleAccumulator extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    private final DoubleBinaryOperator function;
+    private final long identity; // use long representation
+
+    /**
+     * Creates a new instance using the given accumulator function
+     * and identity element.
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @param identity identity (initial value) for the accumulator function
+     */
+    public DoubleAccumulator(DoubleBinaryOperator accumulatorFunction,
+                             double identity) {
+        this.function = accumulatorFunction;
+        base = this.identity = Double.doubleToRawLongBits(identity);
+    }
+
+    /**
+     * Updates with the given value.
+     *
+     * @param x the value
+     */
+    public void accumulate(double x) {
+        Cell[] as; long b, v, r; int m; Cell a;
+        if ((as = cells) != null ||
+            (r = Double.doubleToRawLongBits
+             (function.applyAsDouble
+              (Double.longBitsToDouble(b = base), x))) != b  && !casBase(b, r)) {
+            boolean uncontended = true;
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[getProbe() & m]) == null ||
+                !(uncontended =
+                  (r = Double.doubleToRawLongBits
+                   (function.applyAsDouble
+                    (Double.longBitsToDouble(v = a.value), x))) == v ||
+                  a.cas(v, r)))
+                doubleAccumulate(x, function, uncontended);
+        }
+    }
+
+    /**
+     * Returns the current value.  The returned value is <em>NOT</em>
+     * an atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the value is being calculated might not be
+     * incorporated.
+     *
+     * @return the current value
+     */
+    public double get() {
+        Cell[] as = cells;
+        double result = Double.longBitsToDouble(base);
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    result = function.applyAsDouble
+                        (result, Double.longBitsToDouble(a.value));
+        }
+        return result;
+    }
+
+    /**
+     * Resets variables maintaining updates to the identity value.
+     * This method may be a useful alternative to creating a new
+     * updater, but is only effective if there are no concurrent
+     * updates.  Because this method is intrinsically racy, it should
+     * only be used when it is known that no threads are concurrently
+     * updating.
+     */
+    public void reset() {
+        Cell[] as = cells;
+        base = identity;
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    a.reset(identity);
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #get} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the value before reset
+     */
+    public double getThenReset() {
+        Cell[] as = cells;
+        double result = Double.longBitsToDouble(base);
+        base = identity;
+        if (as != null) {
+            for (Cell a : as) {
+                if (a != null) {
+                    double v = Double.longBitsToDouble(a.value);
+                    a.reset(identity);
+                    result = function.applyAsDouble(result, v);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Double.toString(get());
+    }
+
+    /**
+     * Equivalent to {@link #get}.
+     *
+     * @return the current value
+     */
+    public double doubleValue() {
+        return get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code long}
+     * after a narrowing primitive conversion.
+     */
+    public long longValue() {
+        return (long)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as an {@code int}
+     * after a narrowing primitive conversion.
+     */
+    public int intValue() {
+        return (int)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code float}
+     * after a narrowing primitive conversion.
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by get().
+         * @serial
+         */
+        private final double value;
+
+        /**
+         * The function used for updates.
+         * @serial
+         */
+        private final DoubleBinaryOperator function;
+
+        /**
+         * The identity value, represented as a long, as converted by
+         * {@link Double#doubleToRawLongBits}.  The original identity
+         * can be recovered using {@link Double#longBitsToDouble}.
+         * @serial
+         */
+        private final long identity;
+
+        SerializationProxy(double value,
+                           DoubleBinaryOperator function,
+                           long identity) {
+            this.value = value;
+            this.function = function;
+            this.identity = identity;
+        }
+
+        /**
+         * Returns a {@code DoubleAccumulator} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code DoubleAccumulator} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            double d = Double.longBitsToDouble(identity);
+            DoubleAccumulator a = new DoubleAccumulator(function, d);
+            a.base = Double.doubleToRawLongBits(value);
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.DoubleAccumulator.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(get(), function, identity);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/java/util/concurrent/atomic/DoubleAdder.java b/java/util/concurrent/atomic/DoubleAdder.java
new file mode 100644
index 0000000..57bd8c5
--- /dev/null
+++ b/java/util/concurrent/atomic/DoubleAdder.java
@@ -0,0 +1,266 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+
+/**
+ * One or more variables that together maintain an initially zero
+ * {@code double} sum.  When updates (method {@link #add}) are
+ * contended across threads, the set of variables may grow dynamically
+ * to reduce contention.  Method {@link #sum} (or, equivalently {@link
+ * #doubleValue}) returns the current total combined across the
+ * variables maintaining the sum. The order of accumulation within or
+ * across threads is not guaranteed. Thus, this class may not be
+ * applicable if numerical stability is required, especially when
+ * combining values of substantially different orders of magnitude.
+ *
+ * <p>This class is usually preferable to alternatives when multiple
+ * threads update a common value that is used for purposes such as
+ * summary statistics that are frequently updated but less frequently
+ * read.
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class DoubleAdder extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    /*
+     * Note that we must use "long" for underlying representations,
+     * because there is no compareAndSet for double, due to the fact
+     * that the bitwise equals used in any CAS implementation is not
+     * the same as double-precision equals.  However, we use CAS only
+     * to detect and alleviate contention, for which bitwise equals
+     * works best anyway. In principle, the long/double conversions
+     * used here should be essentially free on most platforms since
+     * they just re-interpret bits.
+     */
+
+    /**
+     * Creates a new adder with initial sum of zero.
+     */
+    public DoubleAdder() {
+    }
+
+    /**
+     * Adds the given value.
+     *
+     * @param x the value to add
+     */
+    public void add(double x) {
+        Cell[] as; long b, v; int m; Cell a;
+        if ((as = cells) != null ||
+            !casBase(b = base,
+                     Double.doubleToRawLongBits
+                     (Double.longBitsToDouble(b) + x))) {
+            boolean uncontended = true;
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[getProbe() & m]) == null ||
+                !(uncontended = a.cas(v = a.value,
+                                      Double.doubleToRawLongBits
+                                      (Double.longBitsToDouble(v) + x))))
+                doubleAccumulate(x, null, uncontended);
+        }
+    }
+
+    /**
+     * Returns the current sum.  The returned value is <em>NOT</em> an
+     * atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the sum is being calculated might not be
+     * incorporated.  Also, because floating-point arithmetic is not
+     * strictly associative, the returned result need not be identical
+     * to the value that would be obtained in a sequential series of
+     * updates to a single variable.
+     *
+     * @return the sum
+     */
+    public double sum() {
+        Cell[] as = cells;
+        double sum = Double.longBitsToDouble(base);
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    sum += Double.longBitsToDouble(a.value);
+        }
+        return sum;
+    }
+
+    /**
+     * Resets variables maintaining the sum to zero.  This method may
+     * be a useful alternative to creating a new adder, but is only
+     * effective if there are no concurrent updates.  Because this
+     * method is intrinsically racy, it should only be used when it is
+     * known that no threads are concurrently updating.
+     */
+    public void reset() {
+        Cell[] as = cells;
+        base = 0L; // relies on fact that double 0 must have same rep as long
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    a.reset();
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #sum} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the sum
+     */
+    public double sumThenReset() {
+        Cell[] as = cells;
+        double sum = Double.longBitsToDouble(base);
+        base = 0L;
+        if (as != null) {
+            for (Cell a : as) {
+                if (a != null) {
+                    long v = a.value;
+                    a.reset();
+                    sum += Double.longBitsToDouble(v);
+                }
+            }
+        }
+        return sum;
+    }
+
+    /**
+     * Returns the String representation of the {@link #sum}.
+     * @return the String representation of the {@link #sum}
+     */
+    public String toString() {
+        return Double.toString(sum());
+    }
+
+    /**
+     * Equivalent to {@link #sum}.
+     *
+     * @return the sum
+     */
+    public double doubleValue() {
+        return sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code long} after a
+     * narrowing primitive conversion.
+     */
+    public long longValue() {
+        return (long)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as an {@code int} after a
+     * narrowing primitive conversion.
+     */
+    public int intValue() {
+        return (int)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code float}
+     * after a narrowing primitive conversion.
+     */
+    public float floatValue() {
+        return (float)sum();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by sum().
+         * @serial
+         */
+        private final double value;
+
+        SerializationProxy(DoubleAdder a) {
+            value = a.sum();
+        }
+
+        /**
+         * Returns a {@code DoubleAdder} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code DoubleAdder} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            DoubleAdder a = new DoubleAdder();
+            a.base = Double.doubleToRawLongBits(value);
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.DoubleAdder.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(this);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/java/util/concurrent/atomic/LongAccumulator.java b/java/util/concurrent/atomic/LongAccumulator.java
new file mode 100644
index 0000000..0e9a8f5
--- /dev/null
+++ b/java/util/concurrent/atomic/LongAccumulator.java
@@ -0,0 +1,293 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+import java.util.function.LongBinaryOperator;
+
+/**
+ * One or more variables that together maintain a running {@code long}
+ * value updated using a supplied function.  When updates (method
+ * {@link #accumulate}) are contended across threads, the set of variables
+ * may grow dynamically to reduce contention.  Method {@link #get}
+ * (or, equivalently, {@link #longValue}) returns the current value
+ * across the variables maintaining updates.
+ *
+ * <p>This class is usually preferable to {@link AtomicLong} when
+ * multiple threads update a common value that is used for purposes such
+ * as collecting statistics, not for fine-grained synchronization
+ * control.  Under low update contention, the two classes have similar
+ * characteristics. But under high contention, expected throughput of
+ * this class is significantly higher, at the expense of higher space
+ * consumption.
+ *
+ * <p>The order of accumulation within or across threads is not
+ * guaranteed and cannot be depended upon, so this class is only
+ * applicable to functions for which the order of accumulation does
+ * not matter. The supplied accumulator function should be
+ * side-effect-free, since it may be re-applied when attempted updates
+ * fail due to contention among threads. The function is applied with
+ * the current value as its first argument, and the given update as
+ * the second argument.  For example, to maintain a running maximum
+ * value, you could supply {@code Long::max} along with {@code
+ * Long.MIN_VALUE} as the identity.
+ *
+ * <p>Class {@link LongAdder} provides analogs of the functionality of
+ * this class for the common special case of maintaining counts and
+ * sums.  The call {@code new LongAdder()} is equivalent to {@code new
+ * LongAccumulator((x, y) -> x + y, 0L}.
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class LongAccumulator extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    private final LongBinaryOperator function;
+    private final long identity;
+
+    /**
+     * Creates a new instance using the given accumulator function
+     * and identity element.
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @param identity identity (initial value) for the accumulator function
+     */
+    public LongAccumulator(LongBinaryOperator accumulatorFunction,
+                           long identity) {
+        this.function = accumulatorFunction;
+        base = this.identity = identity;
+    }
+
+    /**
+     * Updates with the given value.
+     *
+     * @param x the value
+     */
+    public void accumulate(long x) {
+        Cell[] as; long b, v, r; int m; Cell a;
+        if ((as = cells) != null ||
+            (r = function.applyAsLong(b = base, x)) != b && !casBase(b, r)) {
+            boolean uncontended = true;
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[getProbe() & m]) == null ||
+                !(uncontended =
+                  (r = function.applyAsLong(v = a.value, x)) == v ||
+                  a.cas(v, r)))
+                longAccumulate(x, function, uncontended);
+        }
+    }
+
+    /**
+     * Returns the current value.  The returned value is <em>NOT</em>
+     * an atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the value is being calculated might not be
+     * incorporated.
+     *
+     * @return the current value
+     */
+    public long get() {
+        Cell[] as = cells;
+        long result = base;
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    result = function.applyAsLong(result, a.value);
+        }
+        return result;
+    }
+
+    /**
+     * Resets variables maintaining updates to the identity value.
+     * This method may be a useful alternative to creating a new
+     * updater, but is only effective if there are no concurrent
+     * updates.  Because this method is intrinsically racy, it should
+     * only be used when it is known that no threads are concurrently
+     * updating.
+     */
+    public void reset() {
+        Cell[] as = cells;
+        base = identity;
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    a.reset(identity);
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #get} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the value before reset
+     */
+    public long getThenReset() {
+        Cell[] as = cells;
+        long result = base;
+        base = identity;
+        if (as != null) {
+            for (Cell a : as) {
+                if (a != null) {
+                    long v = a.value;
+                    a.reset(identity);
+                    result = function.applyAsLong(result, v);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Long.toString(get());
+    }
+
+    /**
+     * Equivalent to {@link #get}.
+     *
+     * @return the current value
+     */
+    public long longValue() {
+        return get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as an {@code int}
+     * after a narrowing primitive conversion.
+     */
+    public int intValue() {
+        return (int)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code float}
+     * after a widening primitive conversion.
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code double}
+     * after a widening primitive conversion.
+     */
+    public double doubleValue() {
+        return (double)get();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by get().
+         * @serial
+         */
+        private final long value;
+
+        /**
+         * The function used for updates.
+         * @serial
+         */
+        private final LongBinaryOperator function;
+
+        /**
+         * The identity value.
+         * @serial
+         */
+        private final long identity;
+
+        SerializationProxy(long value,
+                           LongBinaryOperator function,
+                           long identity) {
+            this.value = value;
+            this.function = function;
+            this.identity = identity;
+        }
+
+        /**
+         * Returns a {@code LongAccumulator} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code LongAccumulator} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            LongAccumulator a = new LongAccumulator(function, identity);
+            a.base = value;
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.LongAccumulator.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(get(), function, identity);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/java/util/concurrent/atomic/LongAdder.java b/java/util/concurrent/atomic/LongAdder.java
new file mode 100644
index 0000000..0248fad
--- /dev/null
+++ b/java/util/concurrent/atomic/LongAdder.java
@@ -0,0 +1,267 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+
+/**
+ * One or more variables that together maintain an initially zero
+ * {@code long} sum.  When updates (method {@link #add}) are contended
+ * across threads, the set of variables may grow dynamically to reduce
+ * contention. Method {@link #sum} (or, equivalently, {@link
+ * #longValue}) returns the current total combined across the
+ * variables maintaining the sum.
+ *
+ * <p>This class is usually preferable to {@link AtomicLong} when
+ * multiple threads update a common sum that is used for purposes such
+ * as collecting statistics, not for fine-grained synchronization
+ * control.  Under low update contention, the two classes have similar
+ * characteristics. But under high contention, expected throughput of
+ * this class is significantly higher, at the expense of higher space
+ * consumption.
+ *
+ * <p>LongAdders can be used with a {@link
+ * java.util.concurrent.ConcurrentHashMap} to maintain a scalable
+ * frequency map (a form of histogram or multiset). For example, to
+ * add a count to a {@code ConcurrentHashMap<String,LongAdder> freqs},
+ * initializing if not already present, you can use {@code
+ * freqs.computeIfAbsent(key, k -> new LongAdder()).increment();}
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class LongAdder extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    /**
+     * Creates a new adder with initial sum of zero.
+     */
+    public LongAdder() {
+    }
+
+    /**
+     * Adds the given value.
+     *
+     * @param x the value to add
+     */
+    public void add(long x) {
+        Cell[] as; long b, v; int m; Cell a;
+        if ((as = cells) != null || !casBase(b = base, b + x)) {
+            boolean uncontended = true;
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[getProbe() & m]) == null ||
+                !(uncontended = a.cas(v = a.value, v + x)))
+                longAccumulate(x, null, uncontended);
+        }
+    }
+
+    /**
+     * Equivalent to {@code add(1)}.
+     */
+    public void increment() {
+        add(1L);
+    }
+
+    /**
+     * Equivalent to {@code add(-1)}.
+     */
+    public void decrement() {
+        add(-1L);
+    }
+
+    /**
+     * Returns the current sum.  The returned value is <em>NOT</em> an
+     * atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the sum is being calculated might not be
+     * incorporated.
+     *
+     * @return the sum
+     */
+    public long sum() {
+        Cell[] as = cells;
+        long sum = base;
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    sum += a.value;
+        }
+        return sum;
+    }
+
+    /**
+     * Resets variables maintaining the sum to zero.  This method may
+     * be a useful alternative to creating a new adder, but is only
+     * effective if there are no concurrent updates.  Because this
+     * method is intrinsically racy, it should only be used when it is
+     * known that no threads are concurrently updating.
+     */
+    public void reset() {
+        Cell[] as = cells;
+        base = 0L;
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    a.reset();
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #sum} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the sum
+     */
+    public long sumThenReset() {
+        Cell[] as = cells;
+        long sum = base;
+        base = 0L;
+        if (as != null) {
+            for (Cell a : as) {
+                if (a != null) {
+                    sum += a.value;
+                    a.reset();
+                }
+            }
+        }
+        return sum;
+    }
+
+    /**
+     * Returns the String representation of the {@link #sum}.
+     * @return the String representation of the {@link #sum}
+     */
+    public String toString() {
+        return Long.toString(sum());
+    }
+
+    /**
+     * Equivalent to {@link #sum}.
+     *
+     * @return the sum
+     */
+    public long longValue() {
+        return sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as an {@code int} after a narrowing
+     * primitive conversion.
+     */
+    public int intValue() {
+        return (int)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code float}
+     * after a widening primitive conversion.
+     */
+    public float floatValue() {
+        return (float)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code double} after a widening
+     * primitive conversion.
+     */
+    public double doubleValue() {
+        return (double)sum();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by sum().
+         * @serial
+         */
+        private final long value;
+
+        SerializationProxy(LongAdder a) {
+            value = a.sum();
+        }
+
+        /**
+         * Returns a {@code LongAdder} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code LongAdder} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            LongAdder a = new LongAdder();
+            a.base = value;
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.LongAdder.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(this);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/java/util/concurrent/atomic/Striped64.java b/java/util/concurrent/atomic/Striped64.java
new file mode 100644
index 0000000..2a8f327
--- /dev/null
+++ b/java/util/concurrent/atomic/Striped64.java
@@ -0,0 +1,395 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.Arrays;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.LongBinaryOperator;
+
+/**
+ * A package-local class holding common representation and mechanics
+ * for classes supporting dynamic striping on 64bit values. The class
+ * extends Number so that concrete subclasses must publicly do so.
+ */
+@SuppressWarnings("serial")
+abstract class Striped64 extends Number {
+    /*
+     * This class maintains a lazily-initialized table of atomically
+     * updated variables, plus an extra "base" field. The table size
+     * is a power of two. Indexing uses masked per-thread hash codes.
+     * Nearly all declarations in this class are package-private,
+     * accessed directly by subclasses.
+     *
+     * Table entries are of class Cell; a variant of AtomicLong padded
+     * (via @Contended) to reduce cache contention. Padding is
+     * overkill for most Atomics because they are usually irregularly
+     * scattered in memory and thus don't interfere much with each
+     * other. But Atomic objects residing in arrays will tend to be
+     * placed adjacent to each other, and so will most often share
+     * cache lines (with a huge negative performance impact) without
+     * this precaution.
+     *
+     * In part because Cells are relatively large, we avoid creating
+     * them until they are needed.  When there is no contention, all
+     * updates are made to the base field.  Upon first contention (a
+     * failed CAS on base update), the table is initialized to size 2.
+     * The table size is doubled upon further contention until
+     * reaching the nearest power of two greater than or equal to the
+     * number of CPUS. Table slots remain empty (null) until they are
+     * needed.
+     *
+     * A single spinlock ("cellsBusy") is used for initializing and
+     * resizing the table, as well as populating slots with new Cells.
+     * There is no need for a blocking lock; when the lock is not
+     * available, threads try other slots (or the base).  During these
+     * retries, there is increased contention and reduced locality,
+     * which is still better than alternatives.
+     *
+     * The Thread probe fields maintained via ThreadLocalRandom serve
+     * as per-thread hash codes. We let them remain uninitialized as
+     * zero (if they come in this way) until they contend at slot
+     * 0. They are then initialized to values that typically do not
+     * often conflict with others.  Contention and/or table collisions
+     * are indicated by failed CASes when performing an update
+     * operation. Upon a collision, if the table size is less than
+     * the capacity, it is doubled in size unless some other thread
+     * holds the lock. If a hashed slot is empty, and lock is
+     * available, a new Cell is created. Otherwise, if the slot
+     * exists, a CAS is tried.  Retries proceed by "double hashing",
+     * using a secondary hash (Marsaglia XorShift) to try to find a
+     * free slot.
+     *
+     * The table size is capped because, when there are more threads
+     * than CPUs, supposing that each thread were bound to a CPU,
+     * there would exist a perfect hash function mapping threads to
+     * slots that eliminates collisions. When we reach capacity, we
+     * search for this mapping by randomly varying the hash codes of
+     * colliding threads.  Because search is random, and collisions
+     * only become known via CAS failures, convergence can be slow,
+     * and because threads are typically not bound to CPUS forever,
+     * may not occur at all. However, despite these limitations,
+     * observed contention rates are typically low in these cases.
+     *
+     * It is possible for a Cell to become unused when threads that
+     * once hashed to it terminate, as well as in the case where
+     * doubling the table causes no thread to hash to it under
+     * expanded mask.  We do not try to detect or remove such cells,
+     * under the assumption that for long-running instances, observed
+     * contention levels will recur, so the cells will eventually be
+     * needed again; and for short-lived ones, it does not matter.
+     */
+
+    /**
+     * Padded variant of AtomicLong supporting only raw accesses plus CAS.
+     *
+     * JVM intrinsics note: It would be possible to use a release-only
+     * form of CAS here, if it were provided.
+     */
+    // Android-removed: @Contended, this hint is not used by the Android runtime.
+    // @jdk.internal.vm.annotation.Contended
+    static final class Cell {
+        volatile long value;
+        Cell(long x) { value = x; }
+        final boolean cas(long cmp, long val) {
+            return U.compareAndSwapLong(this, VALUE, cmp, val);
+        }
+        final void reset() {
+            U.putLongVolatile(this, VALUE, 0L);
+        }
+        final void reset(long identity) {
+            U.putLongVolatile(this, VALUE, identity);
+        }
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long VALUE;
+        static {
+            try {
+                VALUE = U.objectFieldOffset
+                    (Cell.class.getDeclaredField("value"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /** Number of CPUS, to place bound on table size */
+    static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * Table of cells. When non-null, size is a power of 2.
+     */
+    transient volatile Cell[] cells;
+
+    /**
+     * Base value, used mainly when there is no contention, but also as
+     * a fallback during table initialization races. Updated via CAS.
+     */
+    transient volatile long base;
+
+    /**
+     * Spinlock (locked via CAS) used when resizing and/or creating Cells.
+     */
+    transient volatile int cellsBusy;
+
+    /**
+     * Package-private default constructor.
+     */
+    Striped64() {
+    }
+
+    /**
+     * CASes the base field.
+     */
+    final boolean casBase(long cmp, long val) {
+        return U.compareAndSwapLong(this, BASE, cmp, val);
+    }
+
+    /**
+     * CASes the cellsBusy field from 0 to 1 to acquire lock.
+     */
+    final boolean casCellsBusy() {
+        return U.compareAndSwapInt(this, CELLSBUSY, 0, 1);
+    }
+
+    /**
+     * Returns the probe value for the current thread.
+     * Duplicated from ThreadLocalRandom because of packaging restrictions.
+     */
+    static final int getProbe() {
+        return U.getInt(Thread.currentThread(), PROBE);
+    }
+
+    /**
+     * Pseudo-randomly advances and records the given probe value for the
+     * given thread.
+     * Duplicated from ThreadLocalRandom because of packaging restrictions.
+     */
+    static final int advanceProbe(int probe) {
+        probe ^= probe << 13;   // xorshift
+        probe ^= probe >>> 17;
+        probe ^= probe << 5;
+        U.putInt(Thread.currentThread(), PROBE, probe);
+        return probe;
+    }
+
+    /**
+     * Handles cases of updates involving initialization, resizing,
+     * creating new Cells, and/or contention. See above for
+     * explanation. This method suffers the usual non-modularity
+     * problems of optimistic retry code, relying on rechecked sets of
+     * reads.
+     *
+     * @param x the value
+     * @param fn the update function, or null for add (this convention
+     * avoids the need for an extra field or function in LongAdder).
+     * @param wasUncontended false if CAS failed before call
+     */
+    final void longAccumulate(long x, LongBinaryOperator fn,
+                              boolean wasUncontended) {
+        int h;
+        if ((h = getProbe()) == 0) {
+            ThreadLocalRandom.current(); // force initialization
+            h = getProbe();
+            wasUncontended = true;
+        }
+        boolean collide = false;                // True if last slot nonempty
+        done: for (;;) {
+            Cell[] as; Cell a; int n; long v;
+            if ((as = cells) != null && (n = as.length) > 0) {
+                if ((a = as[(n - 1) & h]) == null) {
+                    if (cellsBusy == 0) {       // Try to attach new Cell
+                        Cell r = new Cell(x);   // Optimistically create
+                        if (cellsBusy == 0 && casCellsBusy()) {
+                            try {               // Recheck under lock
+                                Cell[] rs; int m, j;
+                                if ((rs = cells) != null &&
+                                    (m = rs.length) > 0 &&
+                                    rs[j = (m - 1) & h] == null) {
+                                    rs[j] = r;
+                                    break done;
+                                }
+                            } finally {
+                                cellsBusy = 0;
+                            }
+                            continue;           // Slot is now non-empty
+                        }
+                    }
+                    collide = false;
+                }
+                else if (!wasUncontended)       // CAS already known to fail
+                    wasUncontended = true;      // Continue after rehash
+                else if (a.cas(v = a.value,
+                               (fn == null) ? v + x : fn.applyAsLong(v, x)))
+                    break;
+                else if (n >= NCPU || cells != as)
+                    collide = false;            // At max size or stale
+                else if (!collide)
+                    collide = true;
+                else if (cellsBusy == 0 && casCellsBusy()) {
+                    try {
+                        if (cells == as)        // Expand table unless stale
+                            cells = Arrays.copyOf(as, n << 1);
+                    } finally {
+                        cellsBusy = 0;
+                    }
+                    collide = false;
+                    continue;                   // Retry with expanded table
+                }
+                h = advanceProbe(h);
+            }
+            else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
+                try {                           // Initialize table
+                    if (cells == as) {
+                        Cell[] rs = new Cell[2];
+                        rs[h & 1] = new Cell(x);
+                        cells = rs;
+                        break done;
+                    }
+                } finally {
+                    cellsBusy = 0;
+                }
+            }
+            // Fall back on using base
+            else if (casBase(v = base,
+                             (fn == null) ? v + x : fn.applyAsLong(v, x)))
+                break done;
+        }
+    }
+
+    private static long apply(DoubleBinaryOperator fn, long v, double x) {
+        double d = Double.longBitsToDouble(v);
+        d = (fn == null) ? d + x : fn.applyAsDouble(d, x);
+        return Double.doubleToRawLongBits(d);
+    }
+
+    /**
+     * Same as longAccumulate, but injecting long/double conversions
+     * in too many places to sensibly merge with long version, given
+     * the low-overhead requirements of this class. So must instead be
+     * maintained by copy/paste/adapt.
+     */
+    final void doubleAccumulate(double x, DoubleBinaryOperator fn,
+                                boolean wasUncontended) {
+        int h;
+        if ((h = getProbe()) == 0) {
+            ThreadLocalRandom.current(); // force initialization
+            h = getProbe();
+            wasUncontended = true;
+        }
+        boolean collide = false;                // True if last slot nonempty
+        done: for (;;) {
+            Cell[] as; Cell a; int n; long v;
+            if ((as = cells) != null && (n = as.length) > 0) {
+                if ((a = as[(n - 1) & h]) == null) {
+                    if (cellsBusy == 0) {       // Try to attach new Cell
+                        Cell r = new Cell(Double.doubleToRawLongBits(x));
+                        if (cellsBusy == 0 && casCellsBusy()) {
+                            try {               // Recheck under lock
+                                Cell[] rs; int m, j;
+                                if ((rs = cells) != null &&
+                                    (m = rs.length) > 0 &&
+                                    rs[j = (m - 1) & h] == null) {
+                                    rs[j] = r;
+                                    break done;
+                                }
+                            } finally {
+                                cellsBusy = 0;
+                            }
+                            continue;           // Slot is now non-empty
+                        }
+                    }
+                    collide = false;
+                }
+                else if (!wasUncontended)       // CAS already known to fail
+                    wasUncontended = true;      // Continue after rehash
+                else if (a.cas(v = a.value, apply(fn, v, x)))
+                    break;
+                else if (n >= NCPU || cells != as)
+                    collide = false;            // At max size or stale
+                else if (!collide)
+                    collide = true;
+                else if (cellsBusy == 0 && casCellsBusy()) {
+                    try {
+                        if (cells == as)        // Expand table unless stale
+                            cells = Arrays.copyOf(as, n << 1);
+                    } finally {
+                        cellsBusy = 0;
+                    }
+                    collide = false;
+                    continue;                   // Retry with expanded table
+                }
+                h = advanceProbe(h);
+            }
+            else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
+                try {                           // Initialize table
+                    if (cells == as) {
+                        Cell[] rs = new Cell[2];
+                        rs[h & 1] = new Cell(Double.doubleToRawLongBits(x));
+                        cells = rs;
+                        break done;
+                    }
+                } finally {
+                    cellsBusy = 0;
+                }
+            }
+            // Fall back on using base
+            else if (casBase(v = base, apply(fn, v, x)))
+                break done;
+        }
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long BASE;
+    private static final long CELLSBUSY;
+    private static final long PROBE;
+    static {
+        try {
+            BASE = U.objectFieldOffset
+                (Striped64.class.getDeclaredField("base"));
+            CELLSBUSY = U.objectFieldOffset
+                (Striped64.class.getDeclaredField("cellsBusy"));
+
+            PROBE = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomProbe"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/atomic/package-info.java b/java/util/concurrent/atomic/package-info.java
new file mode 100644
index 0000000..a8e1ff3
--- /dev/null
+++ b/java/util/concurrent/atomic/package-info.java
@@ -0,0 +1,213 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * A small toolkit of classes that support lock-free thread-safe
+ * programming on single variables.  In essence, the classes in this
+ * package extend the notion of {@code volatile} values, fields, and
+ * array elements to those that also provide an atomic conditional update
+ * operation of the form:
+ *
+ * <pre> {@code boolean compareAndSet(expectedValue, updateValue);}</pre>
+ *
+ * <p>This method (which varies in argument types across different
+ * classes) atomically sets a variable to the {@code updateValue} if it
+ * currently holds the {@code expectedValue}, reporting {@code true} on
+ * success.  The classes in this package also contain methods to get and
+ * unconditionally set values, as well as a weaker conditional atomic
+ * update operation {@code weakCompareAndSet} described below.
+ *
+ * <p>The specifications of these methods enable implementations to
+ * employ efficient machine-level atomic instructions that are available
+ * on contemporary processors.  However on some platforms, support may
+ * entail some form of internal locking.  Thus the methods are not
+ * strictly guaranteed to be non-blocking --
+ * a thread may block transiently before performing the operation.
+ *
+ * <p>Instances of classes
+ * {@link java.util.concurrent.atomic.AtomicBoolean},
+ * {@link java.util.concurrent.atomic.AtomicInteger},
+ * {@link java.util.concurrent.atomic.AtomicLong}, and
+ * {@link java.util.concurrent.atomic.AtomicReference}
+ * each provide access and updates to a single variable of the
+ * corresponding type.  Each class also provides appropriate utility
+ * methods for that type.  For example, classes {@code AtomicLong} and
+ * {@code AtomicInteger} provide atomic increment methods.  One
+ * application is to generate sequence numbers, as in:
+ *
+ * <pre> {@code
+ * class Sequencer {
+ *   private final AtomicLong sequenceNumber
+ *     = new AtomicLong(0);
+ *   public long next() {
+ *     return sequenceNumber.getAndIncrement();
+ *   }
+ * }}</pre>
+ *
+ * <p>It is straightforward to define new utility functions that, like
+ * {@code getAndIncrement}, apply a function to a value atomically.
+ * For example, given some transformation
+ * <pre> {@code long transform(long input)}</pre>
+ *
+ * write your utility method as follows:
+ * <pre> {@code
+ * long getAndTransform(AtomicLong var) {
+ *   long prev, next;
+ *   do {
+ *     prev = var.get();
+ *     next = transform(prev);
+ *   } while (!var.compareAndSet(prev, next));
+ *   return prev; // return next; for transformAndGet
+ * }}</pre>
+ *
+ * <p>The memory effects for accesses and updates of atomics generally
+ * follow the rules for volatiles, as stated in
+ * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
+ * Chapter 17 of
+ * <cite>The Java&trade; Language Specification</cite></a>:
+ *
+ * <ul>
+ *
+ *   <li>{@code get} has the memory effects of reading a
+ * {@code volatile} variable.
+ *
+ *   <li>{@code set} has the memory effects of writing (assigning) a
+ * {@code volatile} variable.
+ *
+ *   <li>{@code lazySet} has the memory effects of writing (assigning)
+ *   a {@code volatile} variable except that it permits reorderings with
+ *   subsequent (but not previous) memory actions that do not themselves
+ *   impose reordering constraints with ordinary non-{@code volatile}
+ *   writes.  Among other usage contexts, {@code lazySet} may apply when
+ *   nulling out, for the sake of garbage collection, a reference that is
+ *   never accessed again.
+ *
+ *   <li>{@code weakCompareAndSet} atomically reads and conditionally
+ *   writes a variable but does <em>not</em>
+ *   create any happens-before orderings, so provides no guarantees
+ *   with respect to previous or subsequent reads and writes of any
+ *   variables other than the target of the {@code weakCompareAndSet}.
+ *
+ *   <li>{@code compareAndSet}
+ *   and all other read-and-update operations such as {@code getAndIncrement}
+ *   have the memory effects of both reading and
+ *   writing {@code volatile} variables.
+ * </ul>
+ *
+ * <p>In addition to classes representing single values, this package
+ * contains <em>Updater</em> classes that can be used to obtain
+ * {@code compareAndSet} operations on any selected {@code volatile}
+ * field of any selected class.
+ *
+ * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
+ * {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
+ * {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
+ * reflection-based utilities that provide access to the associated
+ * field types.  These are mainly of use in atomic data structures in
+ * which several {@code volatile} fields of the same node (for
+ * example, the links of a tree node) are independently subject to
+ * atomic updates.  These classes enable greater flexibility in how
+ * and when to use atomic updates, at the expense of more awkward
+ * reflection-based setup, less convenient usage, and weaker
+ * guarantees.
+ *
+ * <p>The
+ * {@link java.util.concurrent.atomic.AtomicIntegerArray},
+ * {@link java.util.concurrent.atomic.AtomicLongArray}, and
+ * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
+ * further extend atomic operation support to arrays of these types.
+ * These classes are also notable in providing {@code volatile} access
+ * semantics for their array elements, which is not supported for
+ * ordinary arrays.
+ *
+ * <p id="weakCompareAndSet">The atomic classes also support method
+ * {@code weakCompareAndSet}, which has limited applicability.  On some
+ * platforms, the weak version may be more efficient than {@code
+ * compareAndSet} in the normal case, but differs in that any given
+ * invocation of the {@code weakCompareAndSet} method may return {@code
+ * false} <em>spuriously</em> (that is, for no apparent reason).  A
+ * {@code false} return means only that the operation may be retried if
+ * desired, relying on the guarantee that repeated invocation when the
+ * variable holds {@code expectedValue} and no other thread is also
+ * attempting to set the variable will eventually succeed.  (Such
+ * spurious failures may for example be due to memory contention effects
+ * that are unrelated to whether the expected and current values are
+ * equal.)  Additionally {@code weakCompareAndSet} does not provide
+ * ordering guarantees that are usually needed for synchronization
+ * control.  However, the method may be useful for updating counters and
+ * statistics when such updates are unrelated to the other
+ * happens-before orderings of a program.  When a thread sees an update
+ * to an atomic variable caused by a {@code weakCompareAndSet}, it does
+ * not necessarily see updates to any <em>other</em> variables that
+ * occurred before the {@code weakCompareAndSet}.  This may be
+ * acceptable when, for example, updating performance statistics, but
+ * rarely otherwise.
+ *
+ * <p>The {@link java.util.concurrent.atomic.AtomicMarkableReference}
+ * class associates a single boolean with a reference.  For example, this
+ * bit might be used inside a data structure to mean that the object
+ * being referenced has logically been deleted.
+ *
+ * The {@link java.util.concurrent.atomic.AtomicStampedReference}
+ * class associates an integer value with a reference.  This may be
+ * used for example, to represent version numbers corresponding to
+ * series of updates.
+ *
+ * <p>Atomic classes are designed primarily as building blocks for
+ * implementing non-blocking data structures and related infrastructure
+ * classes.  The {@code compareAndSet} method is not a general
+ * replacement for locking.  It applies only when critical updates for an
+ * object are confined to a <em>single</em> variable.
+ *
+ * <p>Atomic classes are not general purpose replacements for
+ * {@code java.lang.Integer} and related classes.  They do <em>not</em>
+ * define methods such as {@code equals}, {@code hashCode} and
+ * {@code compareTo}.  (Because atomic variables are expected to be
+ * mutated, they are poor choices for hash table keys.)  Additionally,
+ * classes are provided only for those types that are commonly useful in
+ * intended applications.  For example, there is no atomic class for
+ * representing {@code byte}.  In those infrequent cases where you would
+ * like to do so, you can use an {@code AtomicInteger} to hold
+ * {@code byte} values, and cast appropriately.
+ *
+ * You can also hold floats using
+ * {@link java.lang.Float#floatToRawIntBits} and
+ * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
+ * {@link java.lang.Double#doubleToRawLongBits} and
+ * {@link java.lang.Double#longBitsToDouble} conversions.
+ *
+ * @since 1.5
+ */
+package java.util.concurrent.atomic;
diff --git a/java/util/concurrent/locks/AbstractOwnableSynchronizer.java b/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
new file mode 100644
index 0000000..30dec97
--- /dev/null
+++ b/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
@@ -0,0 +1,86 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+/**
+ * A synchronizer that may be exclusively owned by a thread.  This
+ * class provides a basis for creating locks and related synchronizers
+ * that may entail a notion of ownership.  The
+ * {@code AbstractOwnableSynchronizer} class itself does not manage or
+ * use this information. However, subclasses and tools may use
+ * appropriately maintained values to help control and monitor access
+ * and provide diagnostics.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ */
+public abstract class AbstractOwnableSynchronizer
+    implements java.io.Serializable {
+
+    /** Use serial ID even though all fields transient. */
+    private static final long serialVersionUID = 3737899427754241961L;
+
+    /**
+     * Empty constructor for use by subclasses.
+     */
+    protected AbstractOwnableSynchronizer() { }
+
+    /**
+     * The current owner of exclusive mode synchronization.
+     */
+    private transient Thread exclusiveOwnerThread;
+
+    /**
+     * Sets the thread that currently owns exclusive access.
+     * A {@code null} argument indicates that no thread owns access.
+     * This method does not otherwise impose any synchronization or
+     * {@code volatile} field accesses.
+     * @param thread the owner thread
+     */
+    protected final void setExclusiveOwnerThread(Thread thread) {
+        exclusiveOwnerThread = thread;
+    }
+
+    /**
+     * Returns the thread last set by {@code setExclusiveOwnerThread},
+     * or {@code null} if never set.  This method does not otherwise
+     * impose any synchronization or {@code volatile} field accesses.
+     * @return the owner thread
+     */
+    protected final Thread getExclusiveOwnerThread() {
+        return exclusiveOwnerThread;
+    }
+}
diff --git a/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
new file mode 100644
index 0000000..fb610fb
--- /dev/null
+++ b/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
@@ -0,0 +1,1859 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer.Node;
+
+/**
+ * A version of {@link AbstractQueuedSynchronizer} in
+ * which synchronization state is maintained as a {@code long}.
+ * This class has exactly the same structure, properties, and methods
+ * as {@code AbstractQueuedSynchronizer} with the exception
+ * that all state-related parameters and results are defined
+ * as {@code long} rather than {@code int}. This class
+ * may be useful when creating synchronizers such as
+ * multilevel locks and barriers that require
+ * 64 bits of state.
+ *
+ * <p>See {@link AbstractQueuedSynchronizer} for usage
+ * notes and examples.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ */
+public abstract class AbstractQueuedLongSynchronizer
+    extends AbstractOwnableSynchronizer
+    implements java.io.Serializable {
+
+    private static final long serialVersionUID = 7373984972572414692L;
+
+    /*
+      To keep sources in sync, the remainder of this source file is
+      exactly cloned from AbstractQueuedSynchronizer, replacing class
+      name and changing ints related with sync state to longs. Please
+      keep it that way.
+    */
+
+    /**
+     * Creates a new {@code AbstractQueuedLongSynchronizer} instance
+     * with initial synchronization state of zero.
+     */
+    protected AbstractQueuedLongSynchronizer() { }
+
+    /**
+     * Head of the wait queue, lazily initialized.  Except for
+     * initialization, it is modified only via method setHead.  Note:
+     * If head exists, its waitStatus is guaranteed not to be
+     * CANCELLED.
+     */
+    private transient volatile Node head;
+
+    /**
+     * Tail of the wait queue, lazily initialized.  Modified only via
+     * method enq to add new wait node.
+     */
+    private transient volatile Node tail;
+
+    /**
+     * The synchronization state.
+     */
+    private volatile long state;
+
+    /**
+     * Returns the current value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} read.
+     * @return current state value
+     */
+    protected final long getState() {
+        return state;
+    }
+
+    /**
+     * Sets the value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} write.
+     * @param newState the new state value
+     */
+    protected final void setState(long newState) {
+        // Use putLongVolatile instead of ordinary volatile store when
+        // using compareAndSwapLong, for sake of some 32bit systems.
+        U.putLongVolatile(this, STATE, newState);
+    }
+
+    /**
+     * Atomically sets synchronization state to the given updated
+     * value if the current state value equals the expected value.
+     * This operation has memory semantics of a {@code volatile} read
+     * and write.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that the actual
+     *         value was not equal to the expected value.
+     */
+    protected final boolean compareAndSetState(long expect, long update) {
+        return U.compareAndSwapLong(this, STATE, expect, update);
+    }
+
+    // Queuing utilities
+
+    /**
+     * The number of nanoseconds for which it is faster to spin
+     * rather than to use timed park. A rough estimate suffices
+     * to improve responsiveness with very short timeouts.
+     */
+    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+
+    /**
+     * Inserts node into queue, initializing if necessary. See picture above.
+     * @param node the node to insert
+     * @return node's predecessor
+     */
+    private Node enq(Node node) {
+        for (;;) {
+            Node oldTail = tail;
+            if (oldTail != null) {
+                U.putObject(node, Node.PREV, oldTail);
+                if (compareAndSetTail(oldTail, node)) {
+                    oldTail.next = node;
+                    return oldTail;
+                }
+            } else {
+                initializeSyncQueue();
+            }
+        }
+    }
+
+    /**
+     * Creates and enqueues node for current thread and given mode.
+     *
+     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
+     * @return the new node
+     */
+    private Node addWaiter(Node mode) {
+        Node node = new Node(mode);
+
+        for (;;) {
+            Node oldTail = tail;
+            if (oldTail != null) {
+                U.putObject(node, Node.PREV, oldTail);
+                if (compareAndSetTail(oldTail, node)) {
+                    oldTail.next = node;
+                    return node;
+                }
+            } else {
+                initializeSyncQueue();
+            }
+        }
+    }
+
+    /**
+     * Sets head of queue to be node, thus dequeuing. Called only by
+     * acquire methods.  Also nulls out unused fields for sake of GC
+     * and to suppress unnecessary signals and traversals.
+     *
+     * @param node the node
+     */
+    private void setHead(Node node) {
+        head = node;
+        node.thread = null;
+        node.prev = null;
+    }
+
+    /**
+     * Wakes up node's successor, if one exists.
+     *
+     * @param node the node
+     */
+    private void unparkSuccessor(Node node) {
+        /*
+         * If status is negative (i.e., possibly needing signal) try
+         * to clear in anticipation of signalling.  It is OK if this
+         * fails or if status is changed by waiting thread.
+         */
+        int ws = node.waitStatus;
+        if (ws < 0)
+            node.compareAndSetWaitStatus(ws, 0);
+
+        /*
+         * Thread to unpark is held in successor, which is normally
+         * just the next node.  But if cancelled or apparently null,
+         * traverse backwards from tail to find the actual
+         * non-cancelled successor.
+         */
+        Node s = node.next;
+        if (s == null || s.waitStatus > 0) {
+            s = null;
+            for (Node p = tail; p != node && p != null; p = p.prev)
+                if (p.waitStatus <= 0)
+                    s = p;
+        }
+        if (s != null)
+            LockSupport.unpark(s.thread);
+    }
+
+    /**
+     * Release action for shared mode -- signals successor and ensures
+     * propagation. (Note: For exclusive mode, release just amounts
+     * to calling unparkSuccessor of head if it needs signal.)
+     */
+    private void doReleaseShared() {
+        /*
+         * Ensure that a release propagates, even if there are other
+         * in-progress acquires/releases.  This proceeds in the usual
+         * way of trying to unparkSuccessor of head if it needs
+         * signal. But if it does not, status is set to PROPAGATE to
+         * ensure that upon release, propagation continues.
+         * Additionally, we must loop in case a new node is added
+         * while we are doing this. Also, unlike other uses of
+         * unparkSuccessor, we need to know if CAS to reset status
+         * fails, if so rechecking.
+         */
+        for (;;) {
+            Node h = head;
+            if (h != null && h != tail) {
+                int ws = h.waitStatus;
+                if (ws == Node.SIGNAL) {
+                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
+                        continue;            // loop to recheck cases
+                    unparkSuccessor(h);
+                }
+                else if (ws == 0 &&
+                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
+                    continue;                // loop on failed CAS
+            }
+            if (h == head)                   // loop if head changed
+                break;
+        }
+    }
+
+    /**
+     * Sets head of queue, and checks if successor may be waiting
+     * in shared mode, if so propagating if either propagate > 0 or
+     * PROPAGATE status was set.
+     *
+     * @param node the node
+     * @param propagate the return value from a tryAcquireShared
+     */
+    private void setHeadAndPropagate(Node node, long propagate) {
+        Node h = head; // Record old head for check below
+        setHead(node);
+        /*
+         * Try to signal next queued node if:
+         *   Propagation was indicated by caller,
+         *     or was recorded (as h.waitStatus either before
+         *     or after setHead) by a previous operation
+         *     (note: this uses sign-check of waitStatus because
+         *      PROPAGATE status may transition to SIGNAL.)
+         * and
+         *   The next node is waiting in shared mode,
+         *     or we don't know, because it appears null
+         *
+         * The conservatism in both of these checks may cause
+         * unnecessary wake-ups, but only when there are multiple
+         * racing acquires/releases, so most need signals now or soon
+         * anyway.
+         */
+        if (propagate > 0 || h == null || h.waitStatus < 0 ||
+            (h = head) == null || h.waitStatus < 0) {
+            Node s = node.next;
+            if (s == null || s.isShared())
+                doReleaseShared();
+        }
+    }
+
+    // Utilities for various versions of acquire
+
+    /**
+     * Cancels an ongoing attempt to acquire.
+     *
+     * @param node the node
+     */
+    private void cancelAcquire(Node node) {
+        // Ignore if node doesn't exist
+        if (node == null)
+            return;
+
+        node.thread = null;
+
+        // Skip cancelled predecessors
+        Node pred = node.prev;
+        while (pred.waitStatus > 0)
+            node.prev = pred = pred.prev;
+
+        // predNext is the apparent node to unsplice. CASes below will
+        // fail if not, in which case, we lost race vs another cancel
+        // or signal, so no further action is necessary.
+        Node predNext = pred.next;
+
+        // Can use unconditional write instead of CAS here.
+        // After this atomic step, other Nodes can skip past us.
+        // Before, we are free of interference from other threads.
+        node.waitStatus = Node.CANCELLED;
+
+        // If we are the tail, remove ourselves.
+        if (node == tail && compareAndSetTail(node, pred)) {
+            pred.compareAndSetNext(predNext, null);
+        } else {
+            // If successor needs signal, try to set pred's next-link
+            // so it will get one. Otherwise wake it up to propagate.
+            int ws;
+            if (pred != head &&
+                ((ws = pred.waitStatus) == Node.SIGNAL ||
+                 (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
+                pred.thread != null) {
+                Node next = node.next;
+                if (next != null && next.waitStatus <= 0)
+                    pred.compareAndSetNext(predNext, next);
+            } else {
+                unparkSuccessor(node);
+            }
+
+            node.next = node; // help GC
+        }
+    }
+
+    /**
+     * Checks and updates status for a node that failed to acquire.
+     * Returns true if thread should block. This is the main signal
+     * control in all acquire loops.  Requires that pred == node.prev.
+     *
+     * @param pred node's predecessor holding status
+     * @param node the node
+     * @return {@code true} if thread should block
+     */
+    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
+        int ws = pred.waitStatus;
+        if (ws == Node.SIGNAL)
+            /*
+             * This node has already set status asking a release
+             * to signal it, so it can safely park.
+             */
+            return true;
+        if (ws > 0) {
+            /*
+             * Predecessor was cancelled. Skip over predecessors and
+             * indicate retry.
+             */
+            do {
+                node.prev = pred = pred.prev;
+            } while (pred.waitStatus > 0);
+            pred.next = node;
+        } else {
+            /*
+             * waitStatus must be 0 or PROPAGATE.  Indicate that we
+             * need a signal, but don't park yet.  Caller will need to
+             * retry to make sure it cannot acquire before parking.
+             */
+            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
+        }
+        return false;
+    }
+
+    /**
+     * Convenience method to interrupt current thread.
+     */
+    static void selfInterrupt() {
+        Thread.currentThread().interrupt();
+    }
+
+    /**
+     * Convenience method to park and then check if interrupted.
+     *
+     * @return {@code true} if interrupted
+     */
+    private final boolean parkAndCheckInterrupt() {
+        LockSupport.park(this);
+        return Thread.interrupted();
+    }
+
+    /*
+     * Various flavors of acquire, varying in exclusive/shared and
+     * control modes.  Each is mostly the same, but annoyingly
+     * different.  Only a little bit of factoring is possible due to
+     * interactions of exception mechanics (including ensuring that we
+     * cancel if tryAcquire throws exception) and other control, at
+     * least not without hurting performance too much.
+     */
+
+    /**
+     * Acquires in exclusive uninterruptible mode for thread already in
+     * queue. Used by condition wait methods as well as acquire.
+     *
+     * @param node the node
+     * @param arg the acquire argument
+     * @return {@code true} if interrupted while waiting
+     */
+    final boolean acquireQueued(final Node node, long arg) {
+        try {
+            boolean interrupted = false;
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return interrupted;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    interrupted = true;
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in exclusive interruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireInterruptibly(long arg)
+        throws InterruptedException {
+        final Node node = addWaiter(Node.EXCLUSIVE);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in exclusive timed mode.
+     *
+     * @param arg the acquire argument
+     * @param nanosTimeout max wait time
+     * @return {@code true} if acquired
+     */
+    private boolean doAcquireNanos(long arg, long nanosTimeout)
+            throws InterruptedException {
+        if (nanosTimeout <= 0L)
+            return false;
+        final long deadline = System.nanoTime() + nanosTimeout;
+        final Node node = addWaiter(Node.EXCLUSIVE);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return true;
+                }
+                nanosTimeout = deadline - System.nanoTime();
+                if (nanosTimeout <= 0L) {
+                    cancelAcquire(node);
+                    return false;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if (Thread.interrupted())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared uninterruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireShared(long arg) {
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            boolean interrupted = false;
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    long r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        if (interrupted)
+                            selfInterrupt();
+                        return;
+                    }
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    interrupted = true;
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared interruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireSharedInterruptibly(long arg)
+        throws InterruptedException {
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    long r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        return;
+                    }
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared timed mode.
+     *
+     * @param arg the acquire argument
+     * @param nanosTimeout max wait time
+     * @return {@code true} if acquired
+     */
+    private boolean doAcquireSharedNanos(long arg, long nanosTimeout)
+            throws InterruptedException {
+        if (nanosTimeout <= 0L)
+            return false;
+        final long deadline = System.nanoTime() + nanosTimeout;
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    long r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        return true;
+                    }
+                }
+                nanosTimeout = deadline - System.nanoTime();
+                if (nanosTimeout <= 0L) {
+                    cancelAcquire(node);
+                    return false;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if (Thread.interrupted())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    // Main exported methods
+
+    /**
+     * Attempts to acquire in exclusive mode. This method should query
+     * if the state of the object permits it to be acquired in the
+     * exclusive mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread. This can be used
+     * to implement method {@link Lock#tryLock()}.
+     *
+     * <p>The default
+     * implementation throws {@link UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return {@code true} if successful. Upon success, this object has
+     *         been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryAcquire(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in exclusive
+     * mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this object is now in a fully released
+     *         state, so that any waiting threads may attempt to acquire;
+     *         and {@code false} otherwise.
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryRelease(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to acquire in shared mode. This method should query if
+     * the state of the object permits it to be acquired in the shared
+     * mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread.
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return a negative value on failure; zero if acquisition in shared
+     *         mode succeeded but no subsequent shared-mode acquire can
+     *         succeed; and a positive value if acquisition in shared
+     *         mode succeeded and subsequent shared-mode acquires might
+     *         also succeed, in which case a subsequent waiting thread
+     *         must check availability. (Support for three different
+     *         return values enables this method to be used in contexts
+     *         where acquires only sometimes act exclusively.)  Upon
+     *         success, this object has been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected long tryAcquireShared(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in shared mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this release of shared mode may permit a
+     *         waiting acquire (shared or exclusive) to succeed; and
+     *         {@code false} otherwise
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected boolean tryReleaseShared(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns {@code true} if synchronization is held exclusively with
+     * respect to the current (calling) thread.  This method is invoked
+     * upon each call to a non-waiting {@link ConditionObject} method.
+     * (Waiting methods instead invoke {@link #release}.)
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}. This method is invoked
+     * internally only within {@link ConditionObject} methods, so need
+     * not be defined if conditions are not used.
+     *
+     * @return {@code true} if synchronization is held exclusively;
+     *         {@code false} otherwise
+     * @throws UnsupportedOperationException if conditions are not supported
+     */
+    protected boolean isHeldExclusively() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Acquires in exclusive mode, ignoring interrupts.  Implemented
+     * by invoking at least once {@link #tryAcquire},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquire} until success.  This method can be used
+     * to implement method {@link Lock#lock}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     */
+    public final void acquire(long arg) {
+        if (!tryAcquire(arg) &&
+            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
+            selfInterrupt();
+    }
+
+    /**
+     * Acquires in exclusive mode, aborting if interrupted.
+     * Implemented by first checking interrupt status, then invoking
+     * at least once {@link #tryAcquire}, returning on
+     * success.  Otherwise the thread is queued, possibly repeatedly
+     * blocking and unblocking, invoking {@link #tryAcquire}
+     * until success or the thread is interrupted.  This method can be
+     * used to implement method {@link Lock#lockInterruptibly}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireInterruptibly(long arg)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (!tryAcquire(arg))
+            doAcquireInterruptibly(arg);
+    }
+
+    /**
+     * Attempts to acquire in exclusive mode, aborting if interrupted,
+     * and failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquire}, returning on success.  Otherwise, the thread is
+     * queued, possibly repeatedly blocking and unblocking, invoking
+     * {@link #tryAcquire} until success or the thread is interrupted
+     * or the timeout elapses.  This method can be used to implement
+     * method {@link Lock#tryLock(long, TimeUnit)}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireNanos(long arg, long nanosTimeout)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        return tryAcquire(arg) ||
+            doAcquireNanos(arg, nanosTimeout);
+    }
+
+    /**
+     * Releases in exclusive mode.  Implemented by unblocking one or
+     * more threads if {@link #tryRelease} returns true.
+     * This method can be used to implement method {@link Lock#unlock}.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryRelease} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @return the value returned from {@link #tryRelease}
+     */
+    public final boolean release(long arg) {
+        if (tryRelease(arg)) {
+            Node h = head;
+            if (h != null && h.waitStatus != 0)
+                unparkSuccessor(h);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Acquires in shared mode, ignoring interrupts.  Implemented by
+     * first invoking at least once {@link #tryAcquireShared},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquireShared} until success.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     */
+    public final void acquireShared(long arg) {
+        if (tryAcquireShared(arg) < 0)
+            doAcquireShared(arg);
+    }
+
+    /**
+     * Acquires in shared mode, aborting if interrupted.  Implemented
+     * by first checking interrupt status, then invoking at least once
+     * {@link #tryAcquireShared}, returning on success.  Otherwise the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted.
+     * @param arg the acquire argument.
+     * This value is conveyed to {@link #tryAcquireShared} but is
+     * otherwise uninterpreted and can represent anything
+     * you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireSharedInterruptibly(long arg)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (tryAcquireShared(arg) < 0)
+            doAcquireSharedInterruptibly(arg);
+    }
+
+    /**
+     * Attempts to acquire in shared mode, aborting if interrupted, and
+     * failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquireShared}, returning on success.  Otherwise, the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted or the timeout elapses.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        return tryAcquireShared(arg) >= 0 ||
+            doAcquireSharedNanos(arg, nanosTimeout);
+    }
+
+    /**
+     * Releases in shared mode.  Implemented by unblocking one or more
+     * threads if {@link #tryReleaseShared} returns true.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryReleaseShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return the value returned from {@link #tryReleaseShared}
+     */
+    public final boolean releaseShared(long arg) {
+        if (tryReleaseShared(arg)) {
+            doReleaseShared();
+            return true;
+        }
+        return false;
+    }
+
+    // Queue inspection methods
+
+    /**
+     * Queries whether any threads are waiting to acquire. Note that
+     * because cancellations due to interrupts and timeouts may occur
+     * at any time, a {@code true} return does not guarantee that any
+     * other thread will ever acquire.
+     *
+     * <p>In this implementation, this operation returns in
+     * constant time.
+     *
+     * @return {@code true} if there may be other threads waiting to acquire
+     */
+    public final boolean hasQueuedThreads() {
+        return head != tail;
+    }
+
+    /**
+     * Queries whether any threads have ever contended to acquire this
+     * synchronizer; that is, if an acquire method has ever blocked.
+     *
+     * <p>In this implementation, this operation returns in
+     * constant time.
+     *
+     * @return {@code true} if there has ever been contention
+     */
+    public final boolean hasContended() {
+        return head != null;
+    }
+
+    /**
+     * Returns the first (longest-waiting) thread in the queue, or
+     * {@code null} if no threads are currently queued.
+     *
+     * <p>In this implementation, this operation normally returns in
+     * constant time, but may iterate upon contention if other threads are
+     * concurrently modifying the queue.
+     *
+     * @return the first (longest-waiting) thread in the queue, or
+     *         {@code null} if no threads are currently queued
+     */
+    public final Thread getFirstQueuedThread() {
+        // handle only fast path, else relay
+        return (head == tail) ? null : fullGetFirstQueuedThread();
+    }
+
+    /**
+     * Version of getFirstQueuedThread called when fastpath fails.
+     */
+    private Thread fullGetFirstQueuedThread() {
+        /*
+         * The first node is normally head.next. Try to get its
+         * thread field, ensuring consistent reads: If thread
+         * field is nulled out or s.prev is no longer head, then
+         * some other thread(s) concurrently performed setHead in
+         * between some of our reads. We try this twice before
+         * resorting to traversal.
+         */
+        Node h, s;
+        Thread st;
+        if (((h = head) != null && (s = h.next) != null &&
+             s.prev == head && (st = s.thread) != null) ||
+            ((h = head) != null && (s = h.next) != null &&
+             s.prev == head && (st = s.thread) != null))
+            return st;
+
+        /*
+         * Head's next field might not have been set yet, or may have
+         * been unset after setHead. So we must check to see if tail
+         * is actually first node. If not, we continue on, safely
+         * traversing from tail back to head to find first,
+         * guaranteeing termination.
+         */
+
+        Thread firstThread = null;
+        for (Node p = tail; p != null && p != head; p = p.prev) {
+            Thread t = p.thread;
+            if (t != null)
+                firstThread = t;
+        }
+        return firstThread;
+    }
+
+    /**
+     * Returns true if the given thread is currently queued.
+     *
+     * <p>This implementation traverses the queue to determine
+     * presence of the given thread.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is on the queue
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean isQueued(Thread thread) {
+        if (thread == null)
+            throw new NullPointerException();
+        for (Node p = tail; p != null; p = p.prev)
+            if (p.thread == thread)
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if the apparent first queued thread, if one
+     * exists, is waiting in exclusive mode.  If this method returns
+     * {@code true}, and the current thread is attempting to acquire in
+     * shared mode (that is, this method is invoked from {@link
+     * #tryAcquireShared}) then it is guaranteed that the current thread
+     * is not the first queued thread.  Used only as a heuristic in
+     * ReentrantReadWriteLock.
+     */
+    final boolean apparentlyFirstQueuedIsExclusive() {
+        Node h, s;
+        return (h = head) != null &&
+            (s = h.next)  != null &&
+            !s.isShared()         &&
+            s.thread != null;
+    }
+
+    /**
+     * Queries whether any threads have been waiting to acquire longer
+     * than the current thread.
+     *
+     * <p>An invocation of this method is equivalent to (but may be
+     * more efficient than):
+     * <pre> {@code
+     * getFirstQueuedThread() != Thread.currentThread()
+     *   && hasQueuedThreads()}</pre>
+     *
+     * <p>Note that because cancellations due to interrupts and
+     * timeouts may occur at any time, a {@code true} return does not
+     * guarantee that some other thread will acquire before the current
+     * thread.  Likewise, it is possible for another thread to win a
+     * race to enqueue after this method has returned {@code false},
+     * due to the queue being empty.
+     *
+     * <p>This method is designed to be used by a fair synchronizer to
+     * avoid <a href="AbstractQueuedSynchronizer.html#barging">barging</a>.
+     * Such a synchronizer's {@link #tryAcquire} method should return
+     * {@code false}, and its {@link #tryAcquireShared} method should
+     * return a negative value, if this method returns {@code true}
+     * (unless this is a reentrant acquire).  For example, the {@code
+     * tryAcquire} method for a fair, reentrant, exclusive mode
+     * synchronizer might look like this:
+     *
+     * <pre> {@code
+     * protected boolean tryAcquire(int arg) {
+     *   if (isHeldExclusively()) {
+     *     // A reentrant acquire; increment hold count
+     *     return true;
+     *   } else if (hasQueuedPredecessors()) {
+     *     return false;
+     *   } else {
+     *     // try to acquire normally
+     *   }
+     * }}</pre>
+     *
+     * @return {@code true} if there is a queued thread preceding the
+     *         current thread, and {@code false} if the current thread
+     *         is at the head of the queue or the queue is empty
+     * @since 1.7
+     */
+    public final boolean hasQueuedPredecessors() {
+        // The correctness of this depends on head being initialized
+        // before tail and on head.next being accurate if the current
+        // thread is first in queue.
+        Node t = tail; // Read fields in reverse initialization order
+        Node h = head;
+        Node s;
+        return h != t &&
+            ((s = h.next) == null || s.thread != Thread.currentThread());
+    }
+
+
+    // Instrumentation and monitoring methods
+
+    /**
+     * Returns an estimate of the number of threads waiting to
+     * acquire.  The value is only an estimate because the number of
+     * threads may change dynamically while this method traverses
+     * internal data structures.  This method is designed for use in
+     * monitoring system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting to acquire
+     */
+    public final int getQueueLength() {
+        int n = 0;
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p.thread != null)
+                ++n;
+        }
+        return n;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            Thread t = p.thread;
+            if (t != null)
+                list.add(t);
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in exclusive mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to an exclusive acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getExclusiveQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (!p.isShared()) {
+                Thread t = p.thread;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in shared mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to a shared acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getSharedQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p.isShared()) {
+                Thread t = p.thread;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a string identifying this synchronizer, as well as its state.
+     * The state, in brackets, includes the String {@code "State ="}
+     * followed by the current value of {@link #getState}, and either
+     * {@code "nonempty"} or {@code "empty"} depending on whether the
+     * queue is empty.
+     *
+     * @return a string identifying this synchronizer, as well as its state
+     */
+    public String toString() {
+        return super.toString()
+            + "[State = " + getState() + ", "
+            + (hasQueuedThreads() ? "non" : "") + "empty queue]";
+    }
+
+
+    // Internal support methods for Conditions
+
+    /**
+     * Returns true if a node, always one that was initially placed on
+     * a condition queue, is now waiting to reacquire on sync queue.
+     * @param node the node
+     * @return true if is reacquiring
+     */
+    final boolean isOnSyncQueue(Node node) {
+        if (node.waitStatus == Node.CONDITION || node.prev == null)
+            return false;
+        if (node.next != null) // If has successor, it must be on queue
+            return true;
+        /*
+         * node.prev can be non-null, but not yet on queue because
+         * the CAS to place it on queue can fail. So we have to
+         * traverse from tail to make sure it actually made it.  It
+         * will always be near the tail in calls to this method, and
+         * unless the CAS failed (which is unlikely), it will be
+         * there, so we hardly ever traverse much.
+         */
+        return findNodeFromTail(node);
+    }
+
+    /**
+     * Returns true if node is on sync queue by searching backwards from tail.
+     * Called only when needed by isOnSyncQueue.
+     * @return true if present
+     */
+    private boolean findNodeFromTail(Node node) {
+        // We check for node first, since it's likely to be at or near tail.
+        // tail is known to be non-null, so we could re-order to "save"
+        // one null check, but we leave it this way to help the VM.
+        for (Node p = tail;;) {
+            if (p == node)
+                return true;
+            if (p == null)
+                return false;
+            p = p.prev;
+        }
+    }
+
+    /**
+     * Transfers a node from a condition queue onto sync queue.
+     * Returns true if successful.
+     * @param node the node
+     * @return true if successfully transferred (else the node was
+     * cancelled before signal)
+     */
+    final boolean transferForSignal(Node node) {
+        /*
+         * If cannot change waitStatus, the node has been cancelled.
+         */
+        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
+            return false;
+
+        /*
+         * Splice onto queue and try to set waitStatus of predecessor to
+         * indicate that thread is (probably) waiting. If cancelled or
+         * attempt to set waitStatus fails, wake up to resync (in which
+         * case the waitStatus can be transiently and harmlessly wrong).
+         */
+        Node p = enq(node);
+        int ws = p.waitStatus;
+        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
+            LockSupport.unpark(node.thread);
+        return true;
+    }
+
+    /**
+     * Transfers node, if necessary, to sync queue after a cancelled wait.
+     * Returns true if thread was cancelled before being signalled.
+     *
+     * @param node the node
+     * @return true if cancelled before the node was signalled
+     */
+    final boolean transferAfterCancelledWait(Node node) {
+        if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
+            enq(node);
+            return true;
+        }
+        /*
+         * If we lost out to a signal(), then we can't proceed
+         * until it finishes its enq().  Cancelling during an
+         * incomplete transfer is both rare and transient, so just
+         * spin.
+         */
+        while (!isOnSyncQueue(node))
+            Thread.yield();
+        return false;
+    }
+
+    /**
+     * Invokes release with current state value; returns saved state.
+     * Cancels node and throws exception on failure.
+     * @param node the condition node for this wait
+     * @return previous sync state
+     */
+    final long fullyRelease(Node node) {
+        try {
+            long savedState = getState();
+            if (release(savedState))
+                return savedState;
+            throw new IllegalMonitorStateException();
+        } catch (Throwable t) {
+            node.waitStatus = Node.CANCELLED;
+            throw t;
+        }
+    }
+
+    // Instrumentation methods for conditions
+
+    /**
+     * Queries whether the given ConditionObject
+     * uses this synchronizer as its lock.
+     *
+     * @param condition the condition
+     * @return {@code true} if owned
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean owns(ConditionObject condition) {
+        return condition.isOwnedBy(this);
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with this synchronizer. Note that because timeouts
+     * and interrupts may occur at any time, a {@code true} return
+     * does not guarantee that a future {@code signal} will awaken
+     * any threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean hasWaiters(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.hasWaiters();
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with this synchronizer. Note that
+     * because timeouts and interrupts may occur at any time, the
+     * estimate serves only as an upper bound on the actual number of
+     * waiters.  This method is designed for use in monitoring system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final int getWaitQueueLength(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitQueueLength();
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with this
+     * synchronizer.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate. The elements of the
+     * returned collection are in no particular order.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final Collection<Thread> getWaitingThreads(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitingThreads();
+    }
+
+    /**
+     * Condition implementation for a {@link
+     * AbstractQueuedLongSynchronizer} serving as the basis of a {@link
+     * Lock} implementation.
+     *
+     * <p>Method documentation for this class describes mechanics,
+     * not behavioral specifications from the point of view of Lock
+     * and Condition users. Exported versions of this class will in
+     * general need to be accompanied by documentation describing
+     * condition semantics that rely on those of the associated
+     * {@code AbstractQueuedLongSynchronizer}.
+     *
+     * <p>This class is Serializable, but all fields are transient,
+     * so deserialized conditions have no waiters.
+     *
+     * @since 1.6
+     */
+    public class ConditionObject implements Condition, java.io.Serializable {
+        private static final long serialVersionUID = 1173984872572414699L;
+        /** First node of condition queue. */
+        private transient Node firstWaiter;
+        /** Last node of condition queue. */
+        private transient Node lastWaiter;
+
+        /**
+         * Creates a new {@code ConditionObject} instance.
+         */
+        public ConditionObject() { }
+
+        // Internal methods
+
+        /**
+         * Adds a new waiter to wait queue.
+         * @return its new wait node
+         */
+        private Node addConditionWaiter() {
+            Node t = lastWaiter;
+            // If lastWaiter is cancelled, clean out.
+            if (t != null && t.waitStatus != Node.CONDITION) {
+                unlinkCancelledWaiters();
+                t = lastWaiter;
+            }
+
+            Node node = new Node(Node.CONDITION);
+
+            if (t == null)
+                firstWaiter = node;
+            else
+                t.nextWaiter = node;
+            lastWaiter = node;
+            return node;
+        }
+
+        /**
+         * Removes and transfers nodes until hit non-cancelled one or
+         * null. Split out from signal in part to encourage compilers
+         * to inline the case of no waiters.
+         * @param first (non-null) the first node on condition queue
+         */
+        private void doSignal(Node first) {
+            do {
+                if ( (firstWaiter = first.nextWaiter) == null)
+                    lastWaiter = null;
+                first.nextWaiter = null;
+            } while (!transferForSignal(first) &&
+                     (first = firstWaiter) != null);
+        }
+
+        /**
+         * Removes and transfers all nodes.
+         * @param first (non-null) the first node on condition queue
+         */
+        private void doSignalAll(Node first) {
+            lastWaiter = firstWaiter = null;
+            do {
+                Node next = first.nextWaiter;
+                first.nextWaiter = null;
+                transferForSignal(first);
+                first = next;
+            } while (first != null);
+        }
+
+        /**
+         * Unlinks cancelled waiter nodes from condition queue.
+         * Called only while holding lock. This is called when
+         * cancellation occurred during condition wait, and upon
+         * insertion of a new waiter when lastWaiter is seen to have
+         * been cancelled. This method is needed to avoid garbage
+         * retention in the absence of signals. So even though it may
+         * require a full traversal, it comes into play only when
+         * timeouts or cancellations occur in the absence of
+         * signals. It traverses all nodes rather than stopping at a
+         * particular target to unlink all pointers to garbage nodes
+         * without requiring many re-traversals during cancellation
+         * storms.
+         */
+        private void unlinkCancelledWaiters() {
+            Node t = firstWaiter;
+            Node trail = null;
+            while (t != null) {
+                Node next = t.nextWaiter;
+                if (t.waitStatus != Node.CONDITION) {
+                    t.nextWaiter = null;
+                    if (trail == null)
+                        firstWaiter = next;
+                    else
+                        trail.nextWaiter = next;
+                    if (next == null)
+                        lastWaiter = trail;
+                }
+                else
+                    trail = t;
+                t = next;
+            }
+        }
+
+        // public methods
+
+        /**
+         * Moves the longest-waiting thread, if one exists, from the
+         * wait queue for this condition to the wait queue for the
+         * owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signal() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            Node first = firstWaiter;
+            if (first != null)
+                doSignal(first);
+        }
+
+        /**
+         * Moves all threads from the wait queue for this condition to
+         * the wait queue for the owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signalAll() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            Node first = firstWaiter;
+            if (first != null)
+                doSignalAll(first);
+        }
+
+        /**
+         * Implements uninterruptible condition wait.
+         * <ol>
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * </ol>
+         */
+        public final void awaitUninterruptibly() {
+            Node node = addConditionWaiter();
+            long savedState = fullyRelease(node);
+            boolean interrupted = false;
+            while (!isOnSyncQueue(node)) {
+                LockSupport.park(this);
+                if (Thread.interrupted())
+                    interrupted = true;
+            }
+            if (acquireQueued(node, savedState) || interrupted)
+                selfInterrupt();
+        }
+
+        /*
+         * For interruptible waits, we need to track whether to throw
+         * InterruptedException, if interrupted while blocked on
+         * condition, versus reinterrupt current thread, if
+         * interrupted while blocked waiting to re-acquire.
+         */
+
+        /** Mode meaning to reinterrupt on exit from wait */
+        private static final int REINTERRUPT =  1;
+        /** Mode meaning to throw InterruptedException on exit from wait */
+        private static final int THROW_IE    = -1;
+
+        /**
+         * Checks for interrupt, returning THROW_IE if interrupted
+         * before signalled, REINTERRUPT if after signalled, or
+         * 0 if not interrupted.
+         */
+        private int checkInterruptWhileWaiting(Node node) {
+            return Thread.interrupted() ?
+                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
+                0;
+        }
+
+        /**
+         * Throws InterruptedException, reinterrupts current thread, or
+         * does nothing, depending on mode.
+         */
+        private void reportInterruptAfterWait(int interruptMode)
+            throws InterruptedException {
+            if (interruptMode == THROW_IE)
+                throw new InterruptedException();
+            else if (interruptMode == REINTERRUPT)
+                selfInterrupt();
+        }
+
+        /**
+         * Implements interruptible condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled or interrupted.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final void await() throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            Node node = addConditionWaiter();
+            long savedState = fullyRelease(node);
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                LockSupport.park(this);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null) // clean up if cancelled
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final long awaitNanos(long nanosTimeout)
+                throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            // We don't check for nanosTimeout <= 0L here, to allow
+            // awaitNanos(0) as a way to "yield the lock".
+            final long deadline = System.nanoTime() + nanosTimeout;
+            long initialNanos = nanosTimeout;
+            Node node = addConditionWaiter();
+            long savedState = fullyRelease(node);
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (nanosTimeout <= 0L) {
+                    transferAfterCancelledWait(node);
+                    break;
+                }
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+                nanosTimeout = deadline - System.nanoTime();
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            long remaining = deadline - System.nanoTime(); // avoid overflow
+            return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+        }
+
+        /**
+         * Implements absolute timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean awaitUntil(Date deadline)
+                throws InterruptedException {
+            long abstime = deadline.getTime();
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            Node node = addConditionWaiter();
+            long savedState = fullyRelease(node);
+            boolean timedout = false;
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (System.currentTimeMillis() >= abstime) {
+                    timedout = transferAfterCancelledWait(node);
+                    break;
+                }
+                LockSupport.parkUntil(this, abstime);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            return !timedout;
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean await(long time, TimeUnit unit)
+                throws InterruptedException {
+            long nanosTimeout = unit.toNanos(time);
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            // We don't check for nanosTimeout <= 0L here, to allow
+            // await(0, unit) as a way to "yield the lock".
+            final long deadline = System.nanoTime() + nanosTimeout;
+            Node node = addConditionWaiter();
+            long savedState = fullyRelease(node);
+            boolean timedout = false;
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (nanosTimeout <= 0L) {
+                    timedout = transferAfterCancelledWait(node);
+                    break;
+                }
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+                nanosTimeout = deadline - System.nanoTime();
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            return !timedout;
+        }
+
+        //  support for instrumentation
+
+        /**
+         * Returns true if this condition was created by the given
+         * synchronization object.
+         *
+         * @return {@code true} if owned
+         */
+        final boolean isOwnedBy(AbstractQueuedLongSynchronizer sync) {
+            return sync == AbstractQueuedLongSynchronizer.this;
+        }
+
+        /**
+         * Queries whether any threads are waiting on this condition.
+         * Implements {@link AbstractQueuedLongSynchronizer#hasWaiters(ConditionObject)}.
+         *
+         * @return {@code true} if there are any waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final boolean hasWaiters() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION)
+                    return true;
+            }
+            return false;
+        }
+
+        /**
+         * Returns an estimate of the number of threads waiting on
+         * this condition.
+         * Implements {@link AbstractQueuedLongSynchronizer#getWaitQueueLength(ConditionObject)}.
+         *
+         * @return the estimated number of waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final int getWaitQueueLength() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            int n = 0;
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION)
+                    ++n;
+            }
+            return n;
+        }
+
+        /**
+         * Returns a collection containing those threads that may be
+         * waiting on this Condition.
+         * Implements {@link AbstractQueuedLongSynchronizer#getWaitingThreads(ConditionObject)}.
+         *
+         * @return the collection of threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final Collection<Thread> getWaitingThreads() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            ArrayList<Thread> list = new ArrayList<>();
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION) {
+                    Thread t = w.thread;
+                    if (t != null)
+                        list.add(t);
+                }
+            }
+            return list;
+        }
+    }
+
+    /**
+     * Setup to support compareAndSet. We need to natively implement
+     * this here: For the sake of permitting future enhancements, we
+     * cannot explicitly subclass AtomicLong, which would be
+     * efficient and useful otherwise. So, as the lesser of evils, we
+     * natively implement using hotspot intrinsics API. And while we
+     * are at it, we do the same for other CASable fields (which could
+     * otherwise be done with atomic field updaters).
+     */
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
+    private static final long HEAD;
+    private static final long TAIL;
+
+    static {
+        try {
+            STATE = U.objectFieldOffset
+                (AbstractQueuedLongSynchronizer.class.getDeclaredField("state"));
+            HEAD = U.objectFieldOffset
+                (AbstractQueuedLongSynchronizer.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (AbstractQueuedLongSynchronizer.class.getDeclaredField("tail"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+
+    /**
+     * Initializes head and tail fields on first contention.
+     */
+    private final void initializeSyncQueue() {
+        Node h;
+        if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
+            tail = h;
+    }
+
+    /**
+     * CASes tail field.
+     */
+    private final boolean compareAndSetTail(Node expect, Node update) {
+        return U.compareAndSwapObject(this, TAIL, expect, update);
+    }
+}
diff --git a/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
new file mode 100644
index 0000000..602b5ce
--- /dev/null
+++ b/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -0,0 +1,2331 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provides a framework for implementing blocking locks and related
+ * synchronizers (semaphores, events, etc) that rely on
+ * first-in-first-out (FIFO) wait queues.  This class is designed to
+ * be a useful basis for most kinds of synchronizers that rely on a
+ * single atomic {@code int} value to represent state. Subclasses
+ * must define the protected methods that change this state, and which
+ * define what that state means in terms of this object being acquired
+ * or released.  Given these, the other methods in this class carry
+ * out all queuing and blocking mechanics. Subclasses can maintain
+ * other state fields, but only the atomically updated {@code int}
+ * value manipulated using methods {@link #getState}, {@link
+ * #setState} and {@link #compareAndSetState} is tracked with respect
+ * to synchronization.
+ *
+ * <p>Subclasses should be defined as non-public internal helper
+ * classes that are used to implement the synchronization properties
+ * of their enclosing class.  Class
+ * {@code AbstractQueuedSynchronizer} does not implement any
+ * synchronization interface.  Instead it defines methods such as
+ * {@link #acquireInterruptibly} that can be invoked as
+ * appropriate by concrete locks and related synchronizers to
+ * implement their public methods.
+ *
+ * <p>This class supports either or both a default <em>exclusive</em>
+ * mode and a <em>shared</em> mode. When acquired in exclusive mode,
+ * attempted acquires by other threads cannot succeed. Shared mode
+ * acquires by multiple threads may (but need not) succeed. This class
+ * does not &quot;understand&quot; these differences except in the
+ * mechanical sense that when a shared mode acquire succeeds, the next
+ * waiting thread (if one exists) must also determine whether it can
+ * acquire as well. Threads waiting in the different modes share the
+ * same FIFO queue. Usually, implementation subclasses support only
+ * one of these modes, but both can come into play for example in a
+ * {@link ReadWriteLock}. Subclasses that support only exclusive or
+ * only shared modes need not define the methods supporting the unused mode.
+ *
+ * <p>This class defines a nested {@link ConditionObject} class that
+ * can be used as a {@link Condition} implementation by subclasses
+ * supporting exclusive mode for which method {@link
+ * #isHeldExclusively} reports whether synchronization is exclusively
+ * held with respect to the current thread, method {@link #release}
+ * invoked with the current {@link #getState} value fully releases
+ * this object, and {@link #acquire}, given this saved state value,
+ * eventually restores this object to its previous acquired state.  No
+ * {@code AbstractQueuedSynchronizer} method otherwise creates such a
+ * condition, so if this constraint cannot be met, do not use it.  The
+ * behavior of {@link ConditionObject} depends of course on the
+ * semantics of its synchronizer implementation.
+ *
+ * <p>This class provides inspection, instrumentation, and monitoring
+ * methods for the internal queue, as well as similar methods for
+ * condition objects. These can be exported as desired into classes
+ * using an {@code AbstractQueuedSynchronizer} for their
+ * synchronization mechanics.
+ *
+ * <p>Serialization of this class stores only the underlying atomic
+ * integer maintaining state, so deserialized objects have empty
+ * thread queues. Typical subclasses requiring serializability will
+ * define a {@code readObject} method that restores this to a known
+ * initial state upon deserialization.
+ *
+ * <h3>Usage</h3>
+ *
+ * <p>To use this class as the basis of a synchronizer, redefine the
+ * following methods, as applicable, by inspecting and/or modifying
+ * the synchronization state using {@link #getState}, {@link
+ * #setState} and/or {@link #compareAndSetState}:
+ *
+ * <ul>
+ * <li>{@link #tryAcquire}
+ * <li>{@link #tryRelease}
+ * <li>{@link #tryAcquireShared}
+ * <li>{@link #tryReleaseShared}
+ * <li>{@link #isHeldExclusively}
+ * </ul>
+ *
+ * Each of these methods by default throws {@link
+ * UnsupportedOperationException}.  Implementations of these methods
+ * must be internally thread-safe, and should in general be short and
+ * not block. Defining these methods is the <em>only</em> supported
+ * means of using this class. All other methods are declared
+ * {@code final} because they cannot be independently varied.
+ *
+ * <p>You may also find the inherited methods from {@link
+ * AbstractOwnableSynchronizer} useful to keep track of the thread
+ * owning an exclusive synchronizer.  You are encouraged to use them
+ * -- this enables monitoring and diagnostic tools to assist users in
+ * determining which threads hold locks.
+ *
+ * <p>Even though this class is based on an internal FIFO queue, it
+ * does not automatically enforce FIFO acquisition policies.  The core
+ * of exclusive synchronization takes the form:
+ *
+ * <pre>
+ * Acquire:
+ *     while (!tryAcquire(arg)) {
+ *        <em>enqueue thread if it is not already queued</em>;
+ *        <em>possibly block current thread</em>;
+ *     }
+ *
+ * Release:
+ *     if (tryRelease(arg))
+ *        <em>unblock the first queued thread</em>;
+ * </pre>
+ *
+ * (Shared mode is similar but may involve cascading signals.)
+ *
+ * <p id="barging">Because checks in acquire are invoked before
+ * enqueuing, a newly acquiring thread may <em>barge</em> ahead of
+ * others that are blocked and queued.  However, you can, if desired,
+ * define {@code tryAcquire} and/or {@code tryAcquireShared} to
+ * disable barging by internally invoking one or more of the inspection
+ * methods, thereby providing a <em>fair</em> FIFO acquisition order.
+ * In particular, most fair synchronizers can define {@code tryAcquire}
+ * to return {@code false} if {@link #hasQueuedPredecessors} (a method
+ * specifically designed to be used by fair synchronizers) returns
+ * {@code true}.  Other variations are possible.
+ *
+ * <p>Throughput and scalability are generally highest for the
+ * default barging (also known as <em>greedy</em>,
+ * <em>renouncement</em>, and <em>convoy-avoidance</em>) strategy.
+ * While this is not guaranteed to be fair or starvation-free, earlier
+ * queued threads are allowed to recontend before later queued
+ * threads, and each recontention has an unbiased chance to succeed
+ * against incoming threads.  Also, while acquires do not
+ * &quot;spin&quot; in the usual sense, they may perform multiple
+ * invocations of {@code tryAcquire} interspersed with other
+ * computations before blocking.  This gives most of the benefits of
+ * spins when exclusive synchronization is only briefly held, without
+ * most of the liabilities when it isn't. If so desired, you can
+ * augment this by preceding calls to acquire methods with
+ * "fast-path" checks, possibly prechecking {@link #hasContended}
+ * and/or {@link #hasQueuedThreads} to only do so if the synchronizer
+ * is likely not to be contended.
+ *
+ * <p>This class provides an efficient and scalable basis for
+ * synchronization in part by specializing its range of use to
+ * synchronizers that can rely on {@code int} state, acquire, and
+ * release parameters, and an internal FIFO wait queue. When this does
+ * not suffice, you can build synchronizers from a lower level using
+ * {@link java.util.concurrent.atomic atomic} classes, your own custom
+ * {@link java.util.Queue} classes, and {@link LockSupport} blocking
+ * support.
+ *
+ * <h3>Usage Examples</h3>
+ *
+ * <p>Here is a non-reentrant mutual exclusion lock class that uses
+ * the value zero to represent the unlocked state, and one to
+ * represent the locked state. While a non-reentrant lock
+ * does not strictly require recording of the current owner
+ * thread, this class does so anyway to make usage easier to monitor.
+ * It also supports conditions and exposes
+ * one of the instrumentation methods:
+ *
+ * <pre> {@code
+ * class Mutex implements Lock, java.io.Serializable {
+ *
+ *   // Our internal helper class
+ *   private static class Sync extends AbstractQueuedSynchronizer {
+ *     // Reports whether in locked state
+ *     protected boolean isHeldExclusively() {
+ *       return getState() == 1;
+ *     }
+ *
+ *     // Acquires the lock if state is zero
+ *     public boolean tryAcquire(int acquires) {
+ *       assert acquires == 1; // Otherwise unused
+ *       if (compareAndSetState(0, 1)) {
+ *         setExclusiveOwnerThread(Thread.currentThread());
+ *         return true;
+ *       }
+ *       return false;
+ *     }
+ *
+ *     // Releases the lock by setting state to zero
+ *     protected boolean tryRelease(int releases) {
+ *       assert releases == 1; // Otherwise unused
+ *       if (getState() == 0) throw new IllegalMonitorStateException();
+ *       setExclusiveOwnerThread(null);
+ *       setState(0);
+ *       return true;
+ *     }
+ *
+ *     // Provides a Condition
+ *     Condition newCondition() { return new ConditionObject(); }
+ *
+ *     // Deserializes properly
+ *     private void readObject(ObjectInputStream s)
+ *         throws IOException, ClassNotFoundException {
+ *       s.defaultReadObject();
+ *       setState(0); // reset to unlocked state
+ *     }
+ *   }
+ *
+ *   // The sync object does all the hard work. We just forward to it.
+ *   private final Sync sync = new Sync();
+ *
+ *   public void lock()                { sync.acquire(1); }
+ *   public boolean tryLock()          { return sync.tryAcquire(1); }
+ *   public void unlock()              { sync.release(1); }
+ *   public Condition newCondition()   { return sync.newCondition(); }
+ *   public boolean isLocked()         { return sync.isHeldExclusively(); }
+ *   public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
+ *   public void lockInterruptibly() throws InterruptedException {
+ *     sync.acquireInterruptibly(1);
+ *   }
+ *   public boolean tryLock(long timeout, TimeUnit unit)
+ *       throws InterruptedException {
+ *     return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+ *   }
+ * }}</pre>
+ *
+ * <p>Here is a latch class that is like a
+ * {@link java.util.concurrent.CountDownLatch CountDownLatch}
+ * except that it only requires a single {@code signal} to
+ * fire. Because a latch is non-exclusive, it uses the {@code shared}
+ * acquire and release methods.
+ *
+ * <pre> {@code
+ * class BooleanLatch {
+ *
+ *   private static class Sync extends AbstractQueuedSynchronizer {
+ *     boolean isSignalled() { return getState() != 0; }
+ *
+ *     protected int tryAcquireShared(int ignore) {
+ *       return isSignalled() ? 1 : -1;
+ *     }
+ *
+ *     protected boolean tryReleaseShared(int ignore) {
+ *       setState(1);
+ *       return true;
+ *     }
+ *   }
+ *
+ *   private final Sync sync = new Sync();
+ *   public boolean isSignalled() { return sync.isSignalled(); }
+ *   public void signal()         { sync.releaseShared(1); }
+ *   public void await() throws InterruptedException {
+ *     sync.acquireSharedInterruptibly(1);
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public abstract class AbstractQueuedSynchronizer
+    extends AbstractOwnableSynchronizer
+    implements java.io.Serializable {
+
+    private static final long serialVersionUID = 7373984972572414691L;
+
+    /**
+     * Creates a new {@code AbstractQueuedSynchronizer} instance
+     * with initial synchronization state of zero.
+     */
+    protected AbstractQueuedSynchronizer() { }
+
+    /**
+     * Wait queue node class.
+     *
+     * <p>The wait queue is a variant of a "CLH" (Craig, Landin, and
+     * Hagersten) lock queue. CLH locks are normally used for
+     * spinlocks.  We instead use them for blocking synchronizers, but
+     * use the same basic tactic of holding some of the control
+     * information about a thread in the predecessor of its node.  A
+     * "status" field in each node keeps track of whether a thread
+     * should block.  A node is signalled when its predecessor
+     * releases.  Each node of the queue otherwise serves as a
+     * specific-notification-style monitor holding a single waiting
+     * thread. The status field does NOT control whether threads are
+     * granted locks etc though.  A thread may try to acquire if it is
+     * first in the queue. But being first does not guarantee success;
+     * it only gives the right to contend.  So the currently released
+     * contender thread may need to rewait.
+     *
+     * <p>To enqueue into a CLH lock, you atomically splice it in as new
+     * tail. To dequeue, you just set the head field.
+     * <pre>
+     *      +------+  prev +-----+       +-----+
+     * head |      | <---- |     | <---- |     |  tail
+     *      +------+       +-----+       +-----+
+     * </pre>
+     *
+     * <p>Insertion into a CLH queue requires only a single atomic
+     * operation on "tail", so there is a simple atomic point of
+     * demarcation from unqueued to queued. Similarly, dequeuing
+     * involves only updating the "head". However, it takes a bit
+     * more work for nodes to determine who their successors are,
+     * in part to deal with possible cancellation due to timeouts
+     * and interrupts.
+     *
+     * <p>The "prev" links (not used in original CLH locks), are mainly
+     * needed to handle cancellation. If a node is cancelled, its
+     * successor is (normally) relinked to a non-cancelled
+     * predecessor. For explanation of similar mechanics in the case
+     * of spin locks, see the papers by Scott and Scherer at
+     * http://www.cs.rochester.edu/u/scott/synchronization/
+     *
+     * <p>We also use "next" links to implement blocking mechanics.
+     * The thread id for each node is kept in its own node, so a
+     * predecessor signals the next node to wake up by traversing
+     * next link to determine which thread it is.  Determination of
+     * successor must avoid races with newly queued nodes to set
+     * the "next" fields of their predecessors.  This is solved
+     * when necessary by checking backwards from the atomically
+     * updated "tail" when a node's successor appears to be null.
+     * (Or, said differently, the next-links are an optimization
+     * so that we don't usually need a backward scan.)
+     *
+     * <p>Cancellation introduces some conservatism to the basic
+     * algorithms.  Since we must poll for cancellation of other
+     * nodes, we can miss noticing whether a cancelled node is
+     * ahead or behind us. This is dealt with by always unparking
+     * successors upon cancellation, allowing them to stabilize on
+     * a new predecessor, unless we can identify an uncancelled
+     * predecessor who will carry this responsibility.
+     *
+     * <p>CLH queues need a dummy header node to get started. But
+     * we don't create them on construction, because it would be wasted
+     * effort if there is never contention. Instead, the node
+     * is constructed and head and tail pointers are set upon first
+     * contention.
+     *
+     * <p>Threads waiting on Conditions use the same nodes, but
+     * use an additional link. Conditions only need to link nodes
+     * in simple (non-concurrent) linked queues because they are
+     * only accessed when exclusively held.  Upon await, a node is
+     * inserted into a condition queue.  Upon signal, the node is
+     * transferred to the main queue.  A special value of status
+     * field is used to mark which queue a node is on.
+     *
+     * <p>Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill
+     * Scherer and Michael Scott, along with members of JSR-166
+     * expert group, for helpful ideas, discussions, and critiques
+     * on the design of this class.
+     */
+    static final class Node {
+        /** Marker to indicate a node is waiting in shared mode */
+        static final Node SHARED = new Node();
+        /** Marker to indicate a node is waiting in exclusive mode */
+        static final Node EXCLUSIVE = null;
+
+        /** waitStatus value to indicate thread has cancelled. */
+        static final int CANCELLED =  1;
+        /** waitStatus value to indicate successor's thread needs unparking. */
+        static final int SIGNAL    = -1;
+        /** waitStatus value to indicate thread is waiting on condition. */
+        static final int CONDITION = -2;
+        /**
+         * waitStatus value to indicate the next acquireShared should
+         * unconditionally propagate.
+         */
+        static final int PROPAGATE = -3;
+
+        /**
+         * Status field, taking on only the values:
+         *   SIGNAL:     The successor of this node is (or will soon be)
+         *               blocked (via park), so the current node must
+         *               unpark its successor when it releases or
+         *               cancels. To avoid races, acquire methods must
+         *               first indicate they need a signal,
+         *               then retry the atomic acquire, and then,
+         *               on failure, block.
+         *   CANCELLED:  This node is cancelled due to timeout or interrupt.
+         *               Nodes never leave this state. In particular,
+         *               a thread with cancelled node never again blocks.
+         *   CONDITION:  This node is currently on a condition queue.
+         *               It will not be used as a sync queue node
+         *               until transferred, at which time the status
+         *               will be set to 0. (Use of this value here has
+         *               nothing to do with the other uses of the
+         *               field, but simplifies mechanics.)
+         *   PROPAGATE:  A releaseShared should be propagated to other
+         *               nodes. This is set (for head node only) in
+         *               doReleaseShared to ensure propagation
+         *               continues, even if other operations have
+         *               since intervened.
+         *   0:          None of the above
+         *
+         * The values are arranged numerically to simplify use.
+         * Non-negative values mean that a node doesn't need to
+         * signal. So, most code doesn't need to check for particular
+         * values, just for sign.
+         *
+         * The field is initialized to 0 for normal sync nodes, and
+         * CONDITION for condition nodes.  It is modified using CAS
+         * (or when possible, unconditional volatile writes).
+         */
+        volatile int waitStatus;
+
+        /**
+         * Link to predecessor node that current node/thread relies on
+         * for checking waitStatus. Assigned during enqueuing, and nulled
+         * out (for sake of GC) only upon dequeuing.  Also, upon
+         * cancellation of a predecessor, we short-circuit while
+         * finding a non-cancelled one, which will always exist
+         * because the head node is never cancelled: A node becomes
+         * head only as a result of successful acquire. A
+         * cancelled thread never succeeds in acquiring, and a thread only
+         * cancels itself, not any other node.
+         */
+        volatile Node prev;
+
+        /**
+         * Link to the successor node that the current node/thread
+         * unparks upon release. Assigned during enqueuing, adjusted
+         * when bypassing cancelled predecessors, and nulled out (for
+         * sake of GC) when dequeued.  The enq operation does not
+         * assign next field of a predecessor until after attachment,
+         * so seeing a null next field does not necessarily mean that
+         * node is at end of queue. However, if a next field appears
+         * to be null, we can scan prev's from the tail to
+         * double-check.  The next field of cancelled nodes is set to
+         * point to the node itself instead of null, to make life
+         * easier for isOnSyncQueue.
+         */
+        volatile Node next;
+
+        /**
+         * The thread that enqueued this node.  Initialized on
+         * construction and nulled out after use.
+         */
+        volatile Thread thread;
+
+        /**
+         * Link to next node waiting on condition, or the special
+         * value SHARED.  Because condition queues are accessed only
+         * when holding in exclusive mode, we just need a simple
+         * linked queue to hold nodes while they are waiting on
+         * conditions. They are then transferred to the queue to
+         * re-acquire. And because conditions can only be exclusive,
+         * we save a field by using special value to indicate shared
+         * mode.
+         */
+        Node nextWaiter;
+
+        /**
+         * Returns true if node is waiting in shared mode.
+         */
+        final boolean isShared() {
+            return nextWaiter == SHARED;
+        }
+
+        /**
+         * Returns previous node, or throws NullPointerException if null.
+         * Use when predecessor cannot be null.  The null check could
+         * be elided, but is present to help the VM.
+         *
+         * @return the predecessor of this node
+         */
+        final Node predecessor() throws NullPointerException {
+            Node p = prev;
+            if (p == null)
+                throw new NullPointerException();
+            else
+                return p;
+        }
+
+        /** Establishes initial head or SHARED marker. */
+        Node() {}
+
+        /** Constructor used by addWaiter. */
+        Node(Node nextWaiter) {
+            this.nextWaiter = nextWaiter;
+            U.putObject(this, THREAD, Thread.currentThread());
+        }
+
+        /** Constructor used by addConditionWaiter. */
+        Node(int waitStatus) {
+            U.putInt(this, WAITSTATUS, waitStatus);
+            U.putObject(this, THREAD, Thread.currentThread());
+        }
+
+        /** CASes waitStatus field. */
+        final boolean compareAndSetWaitStatus(int expect, int update) {
+            return U.compareAndSwapInt(this, WAITSTATUS, expect, update);
+        }
+
+        /** CASes next field. */
+        final boolean compareAndSetNext(Node expect, Node update) {
+            return U.compareAndSwapObject(this, NEXT, expect, update);
+        }
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long NEXT;
+        static final long PREV;
+        private static final long THREAD;
+        private static final long WAITSTATUS;
+        static {
+            try {
+                NEXT = U.objectFieldOffset
+                    (Node.class.getDeclaredField("next"));
+                PREV = U.objectFieldOffset
+                    (Node.class.getDeclaredField("prev"));
+                THREAD = U.objectFieldOffset
+                    (Node.class.getDeclaredField("thread"));
+                WAITSTATUS = U.objectFieldOffset
+                    (Node.class.getDeclaredField("waitStatus"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /**
+     * Head of the wait queue, lazily initialized.  Except for
+     * initialization, it is modified only via method setHead.  Note:
+     * If head exists, its waitStatus is guaranteed not to be
+     * CANCELLED.
+     */
+    private transient volatile Node head;
+
+    /**
+     * Tail of the wait queue, lazily initialized.  Modified only via
+     * method enq to add new wait node.
+     */
+    private transient volatile Node tail;
+
+    /**
+     * The synchronization state.
+     */
+    private volatile int state;
+
+    /**
+     * Returns the current value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} read.
+     * @return current state value
+     */
+    protected final int getState() {
+        return state;
+    }
+
+    /**
+     * Sets the value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} write.
+     * @param newState the new state value
+     */
+    protected final void setState(int newState) {
+        state = newState;
+    }
+
+    /**
+     * Atomically sets synchronization state to the given updated
+     * value if the current state value equals the expected value.
+     * This operation has memory semantics of a {@code volatile} read
+     * and write.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that the actual
+     *         value was not equal to the expected value.
+     */
+    protected final boolean compareAndSetState(int expect, int update) {
+        return U.compareAndSwapInt(this, STATE, expect, update);
+    }
+
+    // Queuing utilities
+
+    /**
+     * The number of nanoseconds for which it is faster to spin
+     * rather than to use timed park. A rough estimate suffices
+     * to improve responsiveness with very short timeouts.
+     */
+    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+
+    /**
+     * Inserts node into queue, initializing if necessary. See picture above.
+     * @param node the node to insert
+     * @return node's predecessor
+     */
+    private Node enq(Node node) {
+        for (;;) {
+            Node oldTail = tail;
+            if (oldTail != null) {
+                U.putObject(node, Node.PREV, oldTail);
+                if (compareAndSetTail(oldTail, node)) {
+                    oldTail.next = node;
+                    return oldTail;
+                }
+            } else {
+                initializeSyncQueue();
+            }
+        }
+    }
+
+    /**
+     * Creates and enqueues node for current thread and given mode.
+     *
+     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
+     * @return the new node
+     */
+    private Node addWaiter(Node mode) {
+        Node node = new Node(mode);
+
+        for (;;) {
+            Node oldTail = tail;
+            if (oldTail != null) {
+                U.putObject(node, Node.PREV, oldTail);
+                if (compareAndSetTail(oldTail, node)) {
+                    oldTail.next = node;
+                    return node;
+                }
+            } else {
+                initializeSyncQueue();
+            }
+        }
+    }
+
+    /**
+     * Sets head of queue to be node, thus dequeuing. Called only by
+     * acquire methods.  Also nulls out unused fields for sake of GC
+     * and to suppress unnecessary signals and traversals.
+     *
+     * @param node the node
+     */
+    private void setHead(Node node) {
+        head = node;
+        node.thread = null;
+        node.prev = null;
+    }
+
+    /**
+     * Wakes up node's successor, if one exists.
+     *
+     * @param node the node
+     */
+    private void unparkSuccessor(Node node) {
+        /*
+         * If status is negative (i.e., possibly needing signal) try
+         * to clear in anticipation of signalling.  It is OK if this
+         * fails or if status is changed by waiting thread.
+         */
+        int ws = node.waitStatus;
+        if (ws < 0)
+            node.compareAndSetWaitStatus(ws, 0);
+
+        /*
+         * Thread to unpark is held in successor, which is normally
+         * just the next node.  But if cancelled or apparently null,
+         * traverse backwards from tail to find the actual
+         * non-cancelled successor.
+         */
+        Node s = node.next;
+        if (s == null || s.waitStatus > 0) {
+            s = null;
+            for (Node p = tail; p != node && p != null; p = p.prev)
+                if (p.waitStatus <= 0)
+                    s = p;
+        }
+        if (s != null)
+            LockSupport.unpark(s.thread);
+    }
+
+    /**
+     * Release action for shared mode -- signals successor and ensures
+     * propagation. (Note: For exclusive mode, release just amounts
+     * to calling unparkSuccessor of head if it needs signal.)
+     */
+    private void doReleaseShared() {
+        /*
+         * Ensure that a release propagates, even if there are other
+         * in-progress acquires/releases.  This proceeds in the usual
+         * way of trying to unparkSuccessor of head if it needs
+         * signal. But if it does not, status is set to PROPAGATE to
+         * ensure that upon release, propagation continues.
+         * Additionally, we must loop in case a new node is added
+         * while we are doing this. Also, unlike other uses of
+         * unparkSuccessor, we need to know if CAS to reset status
+         * fails, if so rechecking.
+         */
+        for (;;) {
+            Node h = head;
+            if (h != null && h != tail) {
+                int ws = h.waitStatus;
+                if (ws == Node.SIGNAL) {
+                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
+                        continue;            // loop to recheck cases
+                    unparkSuccessor(h);
+                }
+                else if (ws == 0 &&
+                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
+                    continue;                // loop on failed CAS
+            }
+            if (h == head)                   // loop if head changed
+                break;
+        }
+    }
+
+    /**
+     * Sets head of queue, and checks if successor may be waiting
+     * in shared mode, if so propagating if either propagate > 0 or
+     * PROPAGATE status was set.
+     *
+     * @param node the node
+     * @param propagate the return value from a tryAcquireShared
+     */
+    private void setHeadAndPropagate(Node node, int propagate) {
+        Node h = head; // Record old head for check below
+        setHead(node);
+        /*
+         * Try to signal next queued node if:
+         *   Propagation was indicated by caller,
+         *     or was recorded (as h.waitStatus either before
+         *     or after setHead) by a previous operation
+         *     (note: this uses sign-check of waitStatus because
+         *      PROPAGATE status may transition to SIGNAL.)
+         * and
+         *   The next node is waiting in shared mode,
+         *     or we don't know, because it appears null
+         *
+         * The conservatism in both of these checks may cause
+         * unnecessary wake-ups, but only when there are multiple
+         * racing acquires/releases, so most need signals now or soon
+         * anyway.
+         */
+        if (propagate > 0 || h == null || h.waitStatus < 0 ||
+            (h = head) == null || h.waitStatus < 0) {
+            Node s = node.next;
+            if (s == null || s.isShared())
+                doReleaseShared();
+        }
+    }
+
+    // Utilities for various versions of acquire
+
+    /**
+     * Cancels an ongoing attempt to acquire.
+     *
+     * @param node the node
+     */
+    private void cancelAcquire(Node node) {
+        // Ignore if node doesn't exist
+        if (node == null)
+            return;
+
+        node.thread = null;
+
+        // Skip cancelled predecessors
+        Node pred = node.prev;
+        while (pred.waitStatus > 0)
+            node.prev = pred = pred.prev;
+
+        // predNext is the apparent node to unsplice. CASes below will
+        // fail if not, in which case, we lost race vs another cancel
+        // or signal, so no further action is necessary.
+        Node predNext = pred.next;
+
+        // Can use unconditional write instead of CAS here.
+        // After this atomic step, other Nodes can skip past us.
+        // Before, we are free of interference from other threads.
+        node.waitStatus = Node.CANCELLED;
+
+        // If we are the tail, remove ourselves.
+        if (node == tail && compareAndSetTail(node, pred)) {
+            pred.compareAndSetNext(predNext, null);
+        } else {
+            // If successor needs signal, try to set pred's next-link
+            // so it will get one. Otherwise wake it up to propagate.
+            int ws;
+            if (pred != head &&
+                ((ws = pred.waitStatus) == Node.SIGNAL ||
+                 (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
+                pred.thread != null) {
+                Node next = node.next;
+                if (next != null && next.waitStatus <= 0)
+                    pred.compareAndSetNext(predNext, next);
+            } else {
+                unparkSuccessor(node);
+            }
+
+            node.next = node; // help GC
+        }
+    }
+
+    /**
+     * Checks and updates status for a node that failed to acquire.
+     * Returns true if thread should block. This is the main signal
+     * control in all acquire loops.  Requires that pred == node.prev.
+     *
+     * @param pred node's predecessor holding status
+     * @param node the node
+     * @return {@code true} if thread should block
+     */
+    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
+        int ws = pred.waitStatus;
+        if (ws == Node.SIGNAL)
+            /*
+             * This node has already set status asking a release
+             * to signal it, so it can safely park.
+             */
+            return true;
+        if (ws > 0) {
+            /*
+             * Predecessor was cancelled. Skip over predecessors and
+             * indicate retry.
+             */
+            do {
+                node.prev = pred = pred.prev;
+            } while (pred.waitStatus > 0);
+            pred.next = node;
+        } else {
+            /*
+             * waitStatus must be 0 or PROPAGATE.  Indicate that we
+             * need a signal, but don't park yet.  Caller will need to
+             * retry to make sure it cannot acquire before parking.
+             */
+            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
+        }
+        return false;
+    }
+
+    /**
+     * Convenience method to interrupt current thread.
+     */
+    static void selfInterrupt() {
+        Thread.currentThread().interrupt();
+    }
+
+    /**
+     * Convenience method to park and then check if interrupted.
+     *
+     * @return {@code true} if interrupted
+     */
+    private final boolean parkAndCheckInterrupt() {
+        LockSupport.park(this);
+        return Thread.interrupted();
+    }
+
+    /*
+     * Various flavors of acquire, varying in exclusive/shared and
+     * control modes.  Each is mostly the same, but annoyingly
+     * different.  Only a little bit of factoring is possible due to
+     * interactions of exception mechanics (including ensuring that we
+     * cancel if tryAcquire throws exception) and other control, at
+     * least not without hurting performance too much.
+     */
+
+    /**
+     * Acquires in exclusive uninterruptible mode for thread already in
+     * queue. Used by condition wait methods as well as acquire.
+     *
+     * @param node the node
+     * @param arg the acquire argument
+     * @return {@code true} if interrupted while waiting
+     */
+    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+    // @ReservedStackAccess
+    final boolean acquireQueued(final Node node, int arg) {
+        try {
+            boolean interrupted = false;
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return interrupted;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    interrupted = true;
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in exclusive interruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireInterruptibly(int arg)
+        throws InterruptedException {
+        final Node node = addWaiter(Node.EXCLUSIVE);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in exclusive timed mode.
+     *
+     * @param arg the acquire argument
+     * @param nanosTimeout max wait time
+     * @return {@code true} if acquired
+     */
+    private boolean doAcquireNanos(int arg, long nanosTimeout)
+            throws InterruptedException {
+        if (nanosTimeout <= 0L)
+            return false;
+        final long deadline = System.nanoTime() + nanosTimeout;
+        final Node node = addWaiter(Node.EXCLUSIVE);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return true;
+                }
+                nanosTimeout = deadline - System.nanoTime();
+                if (nanosTimeout <= 0L) {
+                    cancelAcquire(node);
+                    return false;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if (Thread.interrupted())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared uninterruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireShared(int arg) {
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            boolean interrupted = false;
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    int r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        if (interrupted)
+                            selfInterrupt();
+                        return;
+                    }
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    interrupted = true;
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared interruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireSharedInterruptibly(int arg)
+        throws InterruptedException {
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    int r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        return;
+                    }
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared timed mode.
+     *
+     * @param arg the acquire argument
+     * @param nanosTimeout max wait time
+     * @return {@code true} if acquired
+     */
+    private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
+            throws InterruptedException {
+        if (nanosTimeout <= 0L)
+            return false;
+        final long deadline = System.nanoTime() + nanosTimeout;
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    int r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        return true;
+                    }
+                }
+                nanosTimeout = deadline - System.nanoTime();
+                if (nanosTimeout <= 0L) {
+                    cancelAcquire(node);
+                    return false;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if (Thread.interrupted())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    // Main exported methods
+
+    /**
+     * Attempts to acquire in exclusive mode. This method should query
+     * if the state of the object permits it to be acquired in the
+     * exclusive mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread. This can be used
+     * to implement method {@link Lock#tryLock()}.
+     *
+     * <p>The default
+     * implementation throws {@link UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return {@code true} if successful. Upon success, this object has
+     *         been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryAcquire(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in exclusive
+     * mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this object is now in a fully released
+     *         state, so that any waiting threads may attempt to acquire;
+     *         and {@code false} otherwise.
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryRelease(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to acquire in shared mode. This method should query if
+     * the state of the object permits it to be acquired in the shared
+     * mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread.
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return a negative value on failure; zero if acquisition in shared
+     *         mode succeeded but no subsequent shared-mode acquire can
+     *         succeed; and a positive value if acquisition in shared
+     *         mode succeeded and subsequent shared-mode acquires might
+     *         also succeed, in which case a subsequent waiting thread
+     *         must check availability. (Support for three different
+     *         return values enables this method to be used in contexts
+     *         where acquires only sometimes act exclusively.)  Upon
+     *         success, this object has been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected int tryAcquireShared(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in shared mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this release of shared mode may permit a
+     *         waiting acquire (shared or exclusive) to succeed; and
+     *         {@code false} otherwise
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected boolean tryReleaseShared(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns {@code true} if synchronization is held exclusively with
+     * respect to the current (calling) thread.  This method is invoked
+     * upon each call to a non-waiting {@link ConditionObject} method.
+     * (Waiting methods instead invoke {@link #release}.)
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}. This method is invoked
+     * internally only within {@link ConditionObject} methods, so need
+     * not be defined if conditions are not used.
+     *
+     * @return {@code true} if synchronization is held exclusively;
+     *         {@code false} otherwise
+     * @throws UnsupportedOperationException if conditions are not supported
+     */
+    protected boolean isHeldExclusively() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Acquires in exclusive mode, ignoring interrupts.  Implemented
+     * by invoking at least once {@link #tryAcquire},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquire} until success.  This method can be used
+     * to implement method {@link Lock#lock}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     */
+    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+    // @ReservedStackAccess
+    public final void acquire(int arg) {
+        if (!tryAcquire(arg) &&
+            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
+            selfInterrupt();
+    }
+
+    /**
+     * Acquires in exclusive mode, aborting if interrupted.
+     * Implemented by first checking interrupt status, then invoking
+     * at least once {@link #tryAcquire}, returning on
+     * success.  Otherwise the thread is queued, possibly repeatedly
+     * blocking and unblocking, invoking {@link #tryAcquire}
+     * until success or the thread is interrupted.  This method can be
+     * used to implement method {@link Lock#lockInterruptibly}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireInterruptibly(int arg)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (!tryAcquire(arg))
+            doAcquireInterruptibly(arg);
+    }
+
+    /**
+     * Attempts to acquire in exclusive mode, aborting if interrupted,
+     * and failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquire}, returning on success.  Otherwise, the thread is
+     * queued, possibly repeatedly blocking and unblocking, invoking
+     * {@link #tryAcquire} until success or the thread is interrupted
+     * or the timeout elapses.  This method can be used to implement
+     * method {@link Lock#tryLock(long, TimeUnit)}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireNanos(int arg, long nanosTimeout)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        return tryAcquire(arg) ||
+            doAcquireNanos(arg, nanosTimeout);
+    }
+
+    /**
+     * Releases in exclusive mode.  Implemented by unblocking one or
+     * more threads if {@link #tryRelease} returns true.
+     * This method can be used to implement method {@link Lock#unlock}.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryRelease} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @return the value returned from {@link #tryRelease}
+     */
+    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+    // @ReservedStackAccess
+    public final boolean release(int arg) {
+        if (tryRelease(arg)) {
+            Node h = head;
+            if (h != null && h.waitStatus != 0)
+                unparkSuccessor(h);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Acquires in shared mode, ignoring interrupts.  Implemented by
+     * first invoking at least once {@link #tryAcquireShared},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquireShared} until success.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     */
+    public final void acquireShared(int arg) {
+        if (tryAcquireShared(arg) < 0)
+            doAcquireShared(arg);
+    }
+
+    /**
+     * Acquires in shared mode, aborting if interrupted.  Implemented
+     * by first checking interrupt status, then invoking at least once
+     * {@link #tryAcquireShared}, returning on success.  Otherwise the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted.
+     * @param arg the acquire argument.
+     * This value is conveyed to {@link #tryAcquireShared} but is
+     * otherwise uninterpreted and can represent anything
+     * you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireSharedInterruptibly(int arg)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (tryAcquireShared(arg) < 0)
+            doAcquireSharedInterruptibly(arg);
+    }
+
+    /**
+     * Attempts to acquire in shared mode, aborting if interrupted, and
+     * failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquireShared}, returning on success.  Otherwise, the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted or the timeout elapses.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        return tryAcquireShared(arg) >= 0 ||
+            doAcquireSharedNanos(arg, nanosTimeout);
+    }
+
+    /**
+     * Releases in shared mode.  Implemented by unblocking one or more
+     * threads if {@link #tryReleaseShared} returns true.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryReleaseShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return the value returned from {@link #tryReleaseShared}
+     */
+    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+    // @ReservedStackAccess
+    public final boolean releaseShared(int arg) {
+        if (tryReleaseShared(arg)) {
+            doReleaseShared();
+            return true;
+        }
+        return false;
+    }
+
+    // Queue inspection methods
+
+    /**
+     * Queries whether any threads are waiting to acquire. Note that
+     * because cancellations due to interrupts and timeouts may occur
+     * at any time, a {@code true} return does not guarantee that any
+     * other thread will ever acquire.
+     *
+     * <p>In this implementation, this operation returns in
+     * constant time.
+     *
+     * @return {@code true} if there may be other threads waiting to acquire
+     */
+    public final boolean hasQueuedThreads() {
+        return head != tail;
+    }
+
+    /**
+     * Queries whether any threads have ever contended to acquire this
+     * synchronizer; that is, if an acquire method has ever blocked.
+     *
+     * <p>In this implementation, this operation returns in
+     * constant time.
+     *
+     * @return {@code true} if there has ever been contention
+     */
+    public final boolean hasContended() {
+        return head != null;
+    }
+
+    /**
+     * Returns the first (longest-waiting) thread in the queue, or
+     * {@code null} if no threads are currently queued.
+     *
+     * <p>In this implementation, this operation normally returns in
+     * constant time, but may iterate upon contention if other threads are
+     * concurrently modifying the queue.
+     *
+     * @return the first (longest-waiting) thread in the queue, or
+     *         {@code null} if no threads are currently queued
+     */
+    public final Thread getFirstQueuedThread() {
+        // handle only fast path, else relay
+        return (head == tail) ? null : fullGetFirstQueuedThread();
+    }
+
+    /**
+     * Version of getFirstQueuedThread called when fastpath fails.
+     */
+    private Thread fullGetFirstQueuedThread() {
+        /*
+         * The first node is normally head.next. Try to get its
+         * thread field, ensuring consistent reads: If thread
+         * field is nulled out or s.prev is no longer head, then
+         * some other thread(s) concurrently performed setHead in
+         * between some of our reads. We try this twice before
+         * resorting to traversal.
+         */
+        Node h, s;
+        Thread st;
+        if (((h = head) != null && (s = h.next) != null &&
+             s.prev == head && (st = s.thread) != null) ||
+            ((h = head) != null && (s = h.next) != null &&
+             s.prev == head && (st = s.thread) != null))
+            return st;
+
+        /*
+         * Head's next field might not have been set yet, or may have
+         * been unset after setHead. So we must check to see if tail
+         * is actually first node. If not, we continue on, safely
+         * traversing from tail back to head to find first,
+         * guaranteeing termination.
+         */
+
+        Thread firstThread = null;
+        for (Node p = tail; p != null && p != head; p = p.prev) {
+            Thread t = p.thread;
+            if (t != null)
+                firstThread = t;
+        }
+        return firstThread;
+    }
+
+    /**
+     * Returns true if the given thread is currently queued.
+     *
+     * <p>This implementation traverses the queue to determine
+     * presence of the given thread.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is on the queue
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean isQueued(Thread thread) {
+        if (thread == null)
+            throw new NullPointerException();
+        for (Node p = tail; p != null; p = p.prev)
+            if (p.thread == thread)
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if the apparent first queued thread, if one
+     * exists, is waiting in exclusive mode.  If this method returns
+     * {@code true}, and the current thread is attempting to acquire in
+     * shared mode (that is, this method is invoked from {@link
+     * #tryAcquireShared}) then it is guaranteed that the current thread
+     * is not the first queued thread.  Used only as a heuristic in
+     * ReentrantReadWriteLock.
+     */
+    final boolean apparentlyFirstQueuedIsExclusive() {
+        Node h, s;
+        return (h = head) != null &&
+            (s = h.next)  != null &&
+            !s.isShared()         &&
+            s.thread != null;
+    }
+
+    /**
+     * Queries whether any threads have been waiting to acquire longer
+     * than the current thread.
+     *
+     * <p>An invocation of this method is equivalent to (but may be
+     * more efficient than):
+     * <pre> {@code
+     * getFirstQueuedThread() != Thread.currentThread()
+     *   && hasQueuedThreads()}</pre>
+     *
+     * <p>Note that because cancellations due to interrupts and
+     * timeouts may occur at any time, a {@code true} return does not
+     * guarantee that some other thread will acquire before the current
+     * thread.  Likewise, it is possible for another thread to win a
+     * race to enqueue after this method has returned {@code false},
+     * due to the queue being empty.
+     *
+     * <p>This method is designed to be used by a fair synchronizer to
+     * avoid <a href="AbstractQueuedSynchronizer.html#barging">barging</a>.
+     * Such a synchronizer's {@link #tryAcquire} method should return
+     * {@code false}, and its {@link #tryAcquireShared} method should
+     * return a negative value, if this method returns {@code true}
+     * (unless this is a reentrant acquire).  For example, the {@code
+     * tryAcquire} method for a fair, reentrant, exclusive mode
+     * synchronizer might look like this:
+     *
+     * <pre> {@code
+     * protected boolean tryAcquire(int arg) {
+     *   if (isHeldExclusively()) {
+     *     // A reentrant acquire; increment hold count
+     *     return true;
+     *   } else if (hasQueuedPredecessors()) {
+     *     return false;
+     *   } else {
+     *     // try to acquire normally
+     *   }
+     * }}</pre>
+     *
+     * @return {@code true} if there is a queued thread preceding the
+     *         current thread, and {@code false} if the current thread
+     *         is at the head of the queue or the queue is empty
+     * @since 1.7
+     */
+    public final boolean hasQueuedPredecessors() {
+        // The correctness of this depends on head being initialized
+        // before tail and on head.next being accurate if the current
+        // thread is first in queue.
+        Node t = tail; // Read fields in reverse initialization order
+        Node h = head;
+        Node s;
+        return h != t &&
+            ((s = h.next) == null || s.thread != Thread.currentThread());
+    }
+
+
+    // Instrumentation and monitoring methods
+
+    /**
+     * Returns an estimate of the number of threads waiting to
+     * acquire.  The value is only an estimate because the number of
+     * threads may change dynamically while this method traverses
+     * internal data structures.  This method is designed for use in
+     * monitoring system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting to acquire
+     */
+    public final int getQueueLength() {
+        int n = 0;
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p.thread != null)
+                ++n;
+        }
+        return n;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            Thread t = p.thread;
+            if (t != null)
+                list.add(t);
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in exclusive mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to an exclusive acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getExclusiveQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (!p.isShared()) {
+                Thread t = p.thread;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in shared mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to a shared acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getSharedQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p.isShared()) {
+                Thread t = p.thread;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a string identifying this synchronizer, as well as its state.
+     * The state, in brackets, includes the String {@code "State ="}
+     * followed by the current value of {@link #getState}, and either
+     * {@code "nonempty"} or {@code "empty"} depending on whether the
+     * queue is empty.
+     *
+     * @return a string identifying this synchronizer, as well as its state
+     */
+    public String toString() {
+        return super.toString()
+            + "[State = " + getState() + ", "
+            + (hasQueuedThreads() ? "non" : "") + "empty queue]";
+    }
+
+
+    // Internal support methods for Conditions
+
+    /**
+     * Returns true if a node, always one that was initially placed on
+     * a condition queue, is now waiting to reacquire on sync queue.
+     * @param node the node
+     * @return true if is reacquiring
+     */
+    final boolean isOnSyncQueue(Node node) {
+        if (node.waitStatus == Node.CONDITION || node.prev == null)
+            return false;
+        if (node.next != null) // If has successor, it must be on queue
+            return true;
+        /*
+         * node.prev can be non-null, but not yet on queue because
+         * the CAS to place it on queue can fail. So we have to
+         * traverse from tail to make sure it actually made it.  It
+         * will always be near the tail in calls to this method, and
+         * unless the CAS failed (which is unlikely), it will be
+         * there, so we hardly ever traverse much.
+         */
+        return findNodeFromTail(node);
+    }
+
+    /**
+     * Returns true if node is on sync queue by searching backwards from tail.
+     * Called only when needed by isOnSyncQueue.
+     * @return true if present
+     */
+    private boolean findNodeFromTail(Node node) {
+        // We check for node first, since it's likely to be at or near tail.
+        // tail is known to be non-null, so we could re-order to "save"
+        // one null check, but we leave it this way to help the VM.
+        for (Node p = tail;;) {
+            if (p == node)
+                return true;
+            if (p == null)
+                return false;
+            p = p.prev;
+        }
+    }
+
+    /**
+     * Transfers a node from a condition queue onto sync queue.
+     * Returns true if successful.
+     * @param node the node
+     * @return true if successfully transferred (else the node was
+     * cancelled before signal)
+     */
+    final boolean transferForSignal(Node node) {
+        /*
+         * If cannot change waitStatus, the node has been cancelled.
+         */
+        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
+            return false;
+
+        /*
+         * Splice onto queue and try to set waitStatus of predecessor to
+         * indicate that thread is (probably) waiting. If cancelled or
+         * attempt to set waitStatus fails, wake up to resync (in which
+         * case the waitStatus can be transiently and harmlessly wrong).
+         */
+        Node p = enq(node);
+        int ws = p.waitStatus;
+        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
+            LockSupport.unpark(node.thread);
+        return true;
+    }
+
+    /**
+     * Transfers node, if necessary, to sync queue after a cancelled wait.
+     * Returns true if thread was cancelled before being signalled.
+     *
+     * @param node the node
+     * @return true if cancelled before the node was signalled
+     */
+    final boolean transferAfterCancelledWait(Node node) {
+        if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
+            enq(node);
+            return true;
+        }
+        /*
+         * If we lost out to a signal(), then we can't proceed
+         * until it finishes its enq().  Cancelling during an
+         * incomplete transfer is both rare and transient, so just
+         * spin.
+         */
+        while (!isOnSyncQueue(node))
+            Thread.yield();
+        return false;
+    }
+
+    /**
+     * Invokes release with current state value; returns saved state.
+     * Cancels node and throws exception on failure.
+     * @param node the condition node for this wait
+     * @return previous sync state
+     */
+    final int fullyRelease(Node node) {
+        try {
+            int savedState = getState();
+            if (release(savedState))
+                return savedState;
+            throw new IllegalMonitorStateException();
+        } catch (Throwable t) {
+            node.waitStatus = Node.CANCELLED;
+            throw t;
+        }
+    }
+
+    // Instrumentation methods for conditions
+
+    /**
+     * Queries whether the given ConditionObject
+     * uses this synchronizer as its lock.
+     *
+     * @param condition the condition
+     * @return {@code true} if owned
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean owns(ConditionObject condition) {
+        return condition.isOwnedBy(this);
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with this synchronizer. Note that because timeouts
+     * and interrupts may occur at any time, a {@code true} return
+     * does not guarantee that a future {@code signal} will awaken
+     * any threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean hasWaiters(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.hasWaiters();
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with this synchronizer. Note that
+     * because timeouts and interrupts may occur at any time, the
+     * estimate serves only as an upper bound on the actual number of
+     * waiters.  This method is designed for use in monitoring system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final int getWaitQueueLength(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitQueueLength();
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with this
+     * synchronizer.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate. The elements of the
+     * returned collection are in no particular order.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final Collection<Thread> getWaitingThreads(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitingThreads();
+    }
+
+    /**
+     * Condition implementation for a {@link
+     * AbstractQueuedSynchronizer} serving as the basis of a {@link
+     * Lock} implementation.
+     *
+     * <p>Method documentation for this class describes mechanics,
+     * not behavioral specifications from the point of view of Lock
+     * and Condition users. Exported versions of this class will in
+     * general need to be accompanied by documentation describing
+     * condition semantics that rely on those of the associated
+     * {@code AbstractQueuedSynchronizer}.
+     *
+     * <p>This class is Serializable, but all fields are transient,
+     * so deserialized conditions have no waiters.
+     */
+    public class ConditionObject implements Condition, java.io.Serializable {
+        private static final long serialVersionUID = 1173984872572414699L;
+        /** First node of condition queue. */
+        private transient Node firstWaiter;
+        /** Last node of condition queue. */
+        private transient Node lastWaiter;
+
+        /**
+         * Creates a new {@code ConditionObject} instance.
+         */
+        public ConditionObject() { }
+
+        // Internal methods
+
+        /**
+         * Adds a new waiter to wait queue.
+         * @return its new wait node
+         */
+        private Node addConditionWaiter() {
+            Node t = lastWaiter;
+            // If lastWaiter is cancelled, clean out.
+            if (t != null && t.waitStatus != Node.CONDITION) {
+                unlinkCancelledWaiters();
+                t = lastWaiter;
+            }
+
+            Node node = new Node(Node.CONDITION);
+
+            if (t == null)
+                firstWaiter = node;
+            else
+                t.nextWaiter = node;
+            lastWaiter = node;
+            return node;
+        }
+
+        /**
+         * Removes and transfers nodes until hit non-cancelled one or
+         * null. Split out from signal in part to encourage compilers
+         * to inline the case of no waiters.
+         * @param first (non-null) the first node on condition queue
+         */
+        private void doSignal(Node first) {
+            do {
+                if ( (firstWaiter = first.nextWaiter) == null)
+                    lastWaiter = null;
+                first.nextWaiter = null;
+            } while (!transferForSignal(first) &&
+                     (first = firstWaiter) != null);
+        }
+
+        /**
+         * Removes and transfers all nodes.
+         * @param first (non-null) the first node on condition queue
+         */
+        private void doSignalAll(Node first) {
+            lastWaiter = firstWaiter = null;
+            do {
+                Node next = first.nextWaiter;
+                first.nextWaiter = null;
+                transferForSignal(first);
+                first = next;
+            } while (first != null);
+        }
+
+        /**
+         * Unlinks cancelled waiter nodes from condition queue.
+         * Called only while holding lock. This is called when
+         * cancellation occurred during condition wait, and upon
+         * insertion of a new waiter when lastWaiter is seen to have
+         * been cancelled. This method is needed to avoid garbage
+         * retention in the absence of signals. So even though it may
+         * require a full traversal, it comes into play only when
+         * timeouts or cancellations occur in the absence of
+         * signals. It traverses all nodes rather than stopping at a
+         * particular target to unlink all pointers to garbage nodes
+         * without requiring many re-traversals during cancellation
+         * storms.
+         */
+        private void unlinkCancelledWaiters() {
+            Node t = firstWaiter;
+            Node trail = null;
+            while (t != null) {
+                Node next = t.nextWaiter;
+                if (t.waitStatus != Node.CONDITION) {
+                    t.nextWaiter = null;
+                    if (trail == null)
+                        firstWaiter = next;
+                    else
+                        trail.nextWaiter = next;
+                    if (next == null)
+                        lastWaiter = trail;
+                }
+                else
+                    trail = t;
+                t = next;
+            }
+        }
+
+        // public methods
+
+        /**
+         * Moves the longest-waiting thread, if one exists, from the
+         * wait queue for this condition to the wait queue for the
+         * owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signal() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            Node first = firstWaiter;
+            if (first != null)
+                doSignal(first);
+        }
+
+        /**
+         * Moves all threads from the wait queue for this condition to
+         * the wait queue for the owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signalAll() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            Node first = firstWaiter;
+            if (first != null)
+                doSignalAll(first);
+        }
+
+        /**
+         * Implements uninterruptible condition wait.
+         * <ol>
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * </ol>
+         */
+        public final void awaitUninterruptibly() {
+            Node node = addConditionWaiter();
+            int savedState = fullyRelease(node);
+            boolean interrupted = false;
+            while (!isOnSyncQueue(node)) {
+                LockSupport.park(this);
+                if (Thread.interrupted())
+                    interrupted = true;
+            }
+            if (acquireQueued(node, savedState) || interrupted)
+                selfInterrupt();
+        }
+
+        /*
+         * For interruptible waits, we need to track whether to throw
+         * InterruptedException, if interrupted while blocked on
+         * condition, versus reinterrupt current thread, if
+         * interrupted while blocked waiting to re-acquire.
+         */
+
+        /** Mode meaning to reinterrupt on exit from wait */
+        private static final int REINTERRUPT =  1;
+        /** Mode meaning to throw InterruptedException on exit from wait */
+        private static final int THROW_IE    = -1;
+
+        /**
+         * Checks for interrupt, returning THROW_IE if interrupted
+         * before signalled, REINTERRUPT if after signalled, or
+         * 0 if not interrupted.
+         */
+        private int checkInterruptWhileWaiting(Node node) {
+            return Thread.interrupted() ?
+                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
+                0;
+        }
+
+        /**
+         * Throws InterruptedException, reinterrupts current thread, or
+         * does nothing, depending on mode.
+         */
+        private void reportInterruptAfterWait(int interruptMode)
+            throws InterruptedException {
+            if (interruptMode == THROW_IE)
+                throw new InterruptedException();
+            else if (interruptMode == REINTERRUPT)
+                selfInterrupt();
+        }
+
+        /**
+         * Implements interruptible condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled or interrupted.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final void await() throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            Node node = addConditionWaiter();
+            int savedState = fullyRelease(node);
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                LockSupport.park(this);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null) // clean up if cancelled
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final long awaitNanos(long nanosTimeout)
+                throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            // We don't check for nanosTimeout <= 0L here, to allow
+            // awaitNanos(0) as a way to "yield the lock".
+            final long deadline = System.nanoTime() + nanosTimeout;
+            long initialNanos = nanosTimeout;
+            Node node = addConditionWaiter();
+            int savedState = fullyRelease(node);
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (nanosTimeout <= 0L) {
+                    transferAfterCancelledWait(node);
+                    break;
+                }
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+                nanosTimeout = deadline - System.nanoTime();
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            long remaining = deadline - System.nanoTime(); // avoid overflow
+            return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+        }
+
+        /**
+         * Implements absolute timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean awaitUntil(Date deadline)
+                throws InterruptedException {
+            long abstime = deadline.getTime();
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            Node node = addConditionWaiter();
+            int savedState = fullyRelease(node);
+            boolean timedout = false;
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (System.currentTimeMillis() >= abstime) {
+                    timedout = transferAfterCancelledWait(node);
+                    break;
+                }
+                LockSupport.parkUntil(this, abstime);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            return !timedout;
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean await(long time, TimeUnit unit)
+                throws InterruptedException {
+            long nanosTimeout = unit.toNanos(time);
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            // We don't check for nanosTimeout <= 0L here, to allow
+            // await(0, unit) as a way to "yield the lock".
+            final long deadline = System.nanoTime() + nanosTimeout;
+            Node node = addConditionWaiter();
+            int savedState = fullyRelease(node);
+            boolean timedout = false;
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (nanosTimeout <= 0L) {
+                    timedout = transferAfterCancelledWait(node);
+                    break;
+                }
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+                nanosTimeout = deadline - System.nanoTime();
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            return !timedout;
+        }
+
+        //  support for instrumentation
+
+        /**
+         * Returns true if this condition was created by the given
+         * synchronization object.
+         *
+         * @return {@code true} if owned
+         */
+        final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {
+            return sync == AbstractQueuedSynchronizer.this;
+        }
+
+        /**
+         * Queries whether any threads are waiting on this condition.
+         * Implements {@link AbstractQueuedSynchronizer#hasWaiters(ConditionObject)}.
+         *
+         * @return {@code true} if there are any waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final boolean hasWaiters() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION)
+                    return true;
+            }
+            return false;
+        }
+
+        /**
+         * Returns an estimate of the number of threads waiting on
+         * this condition.
+         * Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength(ConditionObject)}.
+         *
+         * @return the estimated number of waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final int getWaitQueueLength() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            int n = 0;
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION)
+                    ++n;
+            }
+            return n;
+        }
+
+        /**
+         * Returns a collection containing those threads that may be
+         * waiting on this Condition.
+         * Implements {@link AbstractQueuedSynchronizer#getWaitingThreads(ConditionObject)}.
+         *
+         * @return the collection of threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final Collection<Thread> getWaitingThreads() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            ArrayList<Thread> list = new ArrayList<>();
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION) {
+                    Thread t = w.thread;
+                    if (t != null)
+                        list.add(t);
+                }
+            }
+            return list;
+        }
+    }
+
+    /**
+     * Setup to support compareAndSet. We need to natively implement
+     * this here: For the sake of permitting future enhancements, we
+     * cannot explicitly subclass AtomicInteger, which would be
+     * efficient and useful otherwise. So, as the lesser of evils, we
+     * natively implement using hotspot intrinsics API. And while we
+     * are at it, we do the same for other CASable fields (which could
+     * otherwise be done with atomic field updaters).
+     */
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
+    private static final long HEAD;
+    private static final long TAIL;
+
+    static {
+        try {
+            STATE = U.objectFieldOffset
+                (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
+            HEAD = U.objectFieldOffset
+                (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+
+    /**
+     * Initializes head and tail fields on first contention.
+     */
+    private final void initializeSyncQueue() {
+        Node h;
+        if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
+            tail = h;
+    }
+
+    /**
+     * CASes tail field.
+     */
+    private final boolean compareAndSetTail(Node expect, Node update) {
+        return U.compareAndSwapObject(this, TAIL, expect, update);
+    }
+}
diff --git a/java/util/concurrent/locks/Condition.java b/java/util/concurrent/locks/Condition.java
new file mode 100644
index 0000000..79181fd
--- /dev/null
+++ b/java/util/concurrent/locks/Condition.java
@@ -0,0 +1,488 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@code Condition} factors out the {@code Object} monitor
+ * methods ({@link Object#wait() wait}, {@link Object#notify notify}
+ * and {@link Object#notifyAll notifyAll}) into distinct objects to
+ * give the effect of having multiple wait-sets per object, by
+ * combining them with the use of arbitrary {@link Lock} implementations.
+ * Where a {@code Lock} replaces the use of {@code synchronized} methods
+ * and statements, a {@code Condition} replaces the use of the Object
+ * monitor methods.
+ *
+ * <p>Conditions (also known as <em>condition queues</em> or
+ * <em>condition variables</em>) provide a means for one thread to
+ * suspend execution (to &quot;wait&quot;) until notified by another
+ * thread that some state condition may now be true.  Because access
+ * to this shared state information occurs in different threads, it
+ * must be protected, so a lock of some form is associated with the
+ * condition. The key property that waiting for a condition provides
+ * is that it <em>atomically</em> releases the associated lock and
+ * suspends the current thread, just like {@code Object.wait}.
+ *
+ * <p>A {@code Condition} instance is intrinsically bound to a lock.
+ * To obtain a {@code Condition} instance for a particular {@link Lock}
+ * instance use its {@link Lock#newCondition newCondition()} method.
+ *
+ * <p>As an example, suppose we have a bounded buffer which supports
+ * {@code put} and {@code take} methods.  If a
+ * {@code take} is attempted on an empty buffer, then the thread will block
+ * until an item becomes available; if a {@code put} is attempted on a
+ * full buffer, then the thread will block until a space becomes available.
+ * We would like to keep waiting {@code put} threads and {@code take}
+ * threads in separate wait-sets so that we can use the optimization of
+ * only notifying a single thread at a time when items or spaces become
+ * available in the buffer. This can be achieved using two
+ * {@link Condition} instances.
+ * <pre>
+ * class BoundedBuffer {
+ *   <b>final Lock lock = new ReentrantLock();</b>
+ *   final Condition notFull  = <b>lock.newCondition(); </b>
+ *   final Condition notEmpty = <b>lock.newCondition(); </b>
+ *
+ *   final Object[] items = new Object[100];
+ *   int putptr, takeptr, count;
+ *
+ *   public void put(Object x) throws InterruptedException {
+ *     <b>lock.lock();
+ *     try {</b>
+ *       while (count == items.length)
+ *         <b>notFull.await();</b>
+ *       items[putptr] = x;
+ *       if (++putptr == items.length) putptr = 0;
+ *       ++count;
+ *       <b>notEmpty.signal();</b>
+ *     <b>} finally {
+ *       lock.unlock();
+ *     }</b>
+ *   }
+ *
+ *   public Object take() throws InterruptedException {
+ *     <b>lock.lock();
+ *     try {</b>
+ *       while (count == 0)
+ *         <b>notEmpty.await();</b>
+ *       Object x = items[takeptr];
+ *       if (++takeptr == items.length) takeptr = 0;
+ *       --count;
+ *       <b>notFull.signal();</b>
+ *       return x;
+ *     <b>} finally {
+ *       lock.unlock();
+ *     }</b>
+ *   }
+ * }
+ * </pre>
+ *
+ * (The {@link java.util.concurrent.ArrayBlockingQueue} class provides
+ * this functionality, so there is no reason to implement this
+ * sample usage class.)
+ *
+ * <p>A {@code Condition} implementation can provide behavior and semantics
+ * that is
+ * different from that of the {@code Object} monitor methods, such as
+ * guaranteed ordering for notifications, or not requiring a lock to be held
+ * when performing notifications.
+ * If an implementation provides such specialized semantics then the
+ * implementation must document those semantics.
+ *
+ * <p>Note that {@code Condition} instances are just normal objects and can
+ * themselves be used as the target in a {@code synchronized} statement,
+ * and can have their own monitor {@link Object#wait wait} and
+ * {@link Object#notify notify} methods invoked.
+ * Acquiring the monitor lock of a {@code Condition} instance, or using its
+ * monitor methods, has no specified relationship with acquiring the
+ * {@link Lock} associated with that {@code Condition} or the use of its
+ * {@linkplain #await waiting} and {@linkplain #signal signalling} methods.
+ * It is recommended that to avoid confusion you never use {@code Condition}
+ * instances in this way, except perhaps within their own implementation.
+ *
+ * <p>Except where noted, passing a {@code null} value for any parameter
+ * will result in a {@link NullPointerException} being thrown.
+ *
+ * <h3>Implementation Considerations</h3>
+ *
+ * <p>When waiting upon a {@code Condition}, a &quot;<em>spurious
+ * wakeup</em>&quot; is permitted to occur, in
+ * general, as a concession to the underlying platform semantics.
+ * This has little practical impact on most application programs as a
+ * {@code Condition} should always be waited upon in a loop, testing
+ * the state predicate that is being waited for.  An implementation is
+ * free to remove the possibility of spurious wakeups but it is
+ * recommended that applications programmers always assume that they can
+ * occur and so always wait in a loop.
+ *
+ * <p>The three forms of condition waiting
+ * (interruptible, non-interruptible, and timed) may differ in their ease of
+ * implementation on some platforms and in their performance characteristics.
+ * In particular, it may be difficult to provide these features and maintain
+ * specific semantics such as ordering guarantees.
+ * Further, the ability to interrupt the actual suspension of the thread may
+ * not always be feasible to implement on all platforms.
+ *
+ * <p>Consequently, an implementation is not required to define exactly the
+ * same guarantees or semantics for all three forms of waiting, nor is it
+ * required to support interruption of the actual suspension of the thread.
+ *
+ * <p>An implementation is required to
+ * clearly document the semantics and guarantees provided by each of the
+ * waiting methods, and when an implementation does support interruption of
+ * thread suspension then it must obey the interruption semantics as defined
+ * in this interface.
+ *
+ * <p>As interruption generally implies cancellation, and checks for
+ * interruption are often infrequent, an implementation can favor responding
+ * to an interrupt over normal method return. This is true even if it can be
+ * shown that the interrupt occurred after another action that may have
+ * unblocked the thread. An implementation should document this behavior.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Condition {
+
+    /**
+     * Causes the current thread to wait until it is signalled or
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>The lock associated with this {@code Condition} is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of four things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of thread suspension is supported; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * and interruption of thread suspension is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared. It is not specified, in the first
+     * case, whether or not the test for interruption occurs before the lock
+     * is released.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return in response to a signal. In that case the implementation
+     * must ensure that the signal is redirected to another waiting thread, if
+     * there is one.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    void await() throws InterruptedException;
+
+    /**
+     * Causes the current thread to wait until it is signalled.
+     *
+     * <p>The lock associated with this condition is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of three things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     * <p>If the current thread's interrupted status is set when it enters
+     * this method, or it is {@linkplain Thread#interrupt interrupted}
+     * while waiting, it will continue to wait until signalled. When it finally
+     * returns from this method its interrupted status will still
+     * be set.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     */
+    void awaitUninterruptibly();
+
+    /**
+     * Causes the current thread to wait until it is signalled or interrupted,
+     * or the specified waiting time elapses.
+     *
+     * <p>The lock associated with this condition is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of five things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of thread suspension is supported; or
+     * <li>The specified waiting time elapses; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * and interruption of thread suspension is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared. It is not specified, in the first
+     * case, whether or not the test for interruption occurs before the lock
+     * is released.
+     *
+     * <p>The method returns an estimate of the number of nanoseconds
+     * remaining to wait given the supplied {@code nanosTimeout}
+     * value upon return, or a value less than or equal to zero if it
+     * timed out. This value can be used to determine whether and how
+     * long to re-wait in cases where the wait returns but an awaited
+     * condition still does not hold. Typical uses of this method take
+     * the following form:
+     *
+     * <pre> {@code
+     * boolean aMethod(long timeout, TimeUnit unit) {
+     *   long nanos = unit.toNanos(timeout);
+     *   lock.lock();
+     *   try {
+     *     while (!conditionBeingWaitedFor()) {
+     *       if (nanos <= 0L)
+     *         return false;
+     *       nanos = theCondition.awaitNanos(nanos);
+     *     }
+     *     // ...
+     *   } finally {
+     *     lock.unlock();
+     *   }
+     * }}</pre>
+     *
+     * <p>Design note: This method requires a nanosecond argument so
+     * as to avoid truncation errors in reporting remaining times.
+     * Such precision loss would make it difficult for programmers to
+     * ensure that total waiting times are not systematically shorter
+     * than specified when re-waits occur.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return in response to a signal, or over indicating the elapse
+     * of the specified waiting time. In either case the implementation
+     * must ensure that the signal is redirected to another waiting thread, if
+     * there is one.
+     *
+     * @param nanosTimeout the maximum time to wait, in nanoseconds
+     * @return an estimate of the {@code nanosTimeout} value minus
+     *         the time spent waiting upon return from this method.
+     *         A positive value may be used as the argument to a
+     *         subsequent call to this method to finish waiting out
+     *         the desired time.  A value less than or equal to zero
+     *         indicates that no time remains.
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    long awaitNanos(long nanosTimeout) throws InterruptedException;
+
+    /**
+     * Causes the current thread to wait until it is signalled or interrupted,
+     * or the specified waiting time elapses. This method is behaviorally
+     * equivalent to:
+     * <pre> {@code awaitNanos(unit.toNanos(time)) > 0}</pre>
+     *
+     * @param time the maximum time to wait
+     * @param unit the time unit of the {@code time} argument
+     * @return {@code false} if the waiting time detectably elapsed
+     *         before return from the method, else {@code true}
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    boolean await(long time, TimeUnit unit) throws InterruptedException;
+
+    /**
+     * Causes the current thread to wait until it is signalled or interrupted,
+     * or the specified deadline elapses.
+     *
+     * <p>The lock associated with this condition is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of five things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of thread suspension is supported; or
+     * <li>The specified deadline elapses; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * and interruption of thread suspension is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared. It is not specified, in the first
+     * case, whether or not the test for interruption occurs before the lock
+     * is released.
+     *
+     *
+     * <p>The return value indicates whether the deadline has elapsed,
+     * which can be used as follows:
+     * <pre> {@code
+     * boolean aMethod(Date deadline) {
+     *   boolean stillWaiting = true;
+     *   lock.lock();
+     *   try {
+     *     while (!conditionBeingWaitedFor()) {
+     *       if (!stillWaiting)
+     *         return false;
+     *       stillWaiting = theCondition.awaitUntil(deadline);
+     *     }
+     *     // ...
+     *   } finally {
+     *     lock.unlock();
+     *   }
+     * }}</pre>
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return in response to a signal, or over indicating the passing
+     * of the specified deadline. In either case the implementation
+     * must ensure that the signal is redirected to another waiting thread, if
+     * there is one.
+     *
+     * @param deadline the absolute time to wait until
+     * @return {@code false} if the deadline has elapsed upon return, else
+     *         {@code true}
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    boolean awaitUntil(Date deadline) throws InterruptedException;
+
+    /**
+     * Wakes up one waiting thread.
+     *
+     * <p>If any threads are waiting on this condition then one
+     * is selected for waking up. That thread must then re-acquire the
+     * lock before returning from {@code await}.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>An implementation may (and typically does) require that the
+     * current thread hold the lock associated with this {@code
+     * Condition} when this method is called. Implementations must
+     * document this precondition and any actions taken if the lock is
+     * not held. Typically, an exception such as {@link
+     * IllegalMonitorStateException} will be thrown.
+     */
+    void signal();
+
+    /**
+     * Wakes up all waiting threads.
+     *
+     * <p>If any threads are waiting on this condition then they are
+     * all woken up. Each thread must re-acquire the lock before it can
+     * return from {@code await}.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>An implementation may (and typically does) require that the
+     * current thread hold the lock associated with this {@code
+     * Condition} when this method is called. Implementations must
+     * document this precondition and any actions taken if the lock is
+     * not held. Typically, an exception such as {@link
+     * IllegalMonitorStateException} will be thrown.
+     */
+    void signalAll();
+}
diff --git a/java/util/concurrent/locks/Lock.java b/java/util/concurrent/locks/Lock.java
new file mode 100644
index 0000000..33ac44b
--- /dev/null
+++ b/java/util/concurrent/locks/Lock.java
@@ -0,0 +1,359 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@code Lock} implementations provide more extensive locking
+ * operations than can be obtained using {@code synchronized} methods
+ * and statements.  They allow more flexible structuring, may have
+ * quite different properties, and may support multiple associated
+ * {@link Condition} objects.
+ *
+ * <p>A lock is a tool for controlling access to a shared resource by
+ * multiple threads. Commonly, a lock provides exclusive access to a
+ * shared resource: only one thread at a time can acquire the lock and
+ * all access to the shared resource requires that the lock be
+ * acquired first. However, some locks may allow concurrent access to
+ * a shared resource, such as the read lock of a {@link ReadWriteLock}.
+ *
+ * <p>The use of {@code synchronized} methods or statements provides
+ * access to the implicit monitor lock associated with every object, but
+ * forces all lock acquisition and release to occur in a block-structured way:
+ * when multiple locks are acquired they must be released in the opposite
+ * order, and all locks must be released in the same lexical scope in which
+ * they were acquired.
+ *
+ * <p>While the scoping mechanism for {@code synchronized} methods
+ * and statements makes it much easier to program with monitor locks,
+ * and helps avoid many common programming errors involving locks,
+ * there are occasions where you need to work with locks in a more
+ * flexible way. For example, some algorithms for traversing
+ * concurrently accessed data structures require the use of
+ * &quot;hand-over-hand&quot; or &quot;chain locking&quot;: you
+ * acquire the lock of node A, then node B, then release A and acquire
+ * C, then release B and acquire D and so on.  Implementations of the
+ * {@code Lock} interface enable the use of such techniques by
+ * allowing a lock to be acquired and released in different scopes,
+ * and allowing multiple locks to be acquired and released in any
+ * order.
+ *
+ * <p>With this increased flexibility comes additional
+ * responsibility. The absence of block-structured locking removes the
+ * automatic release of locks that occurs with {@code synchronized}
+ * methods and statements. In most cases, the following idiom
+ * should be used:
+ *
+ * <pre> {@code
+ * Lock l = ...;
+ * l.lock();
+ * try {
+ *   // access the resource protected by this lock
+ * } finally {
+ *   l.unlock();
+ * }}</pre>
+ *
+ * When locking and unlocking occur in different scopes, care must be
+ * taken to ensure that all code that is executed while the lock is
+ * held is protected by try-finally or try-catch to ensure that the
+ * lock is released when necessary.
+ *
+ * <p>{@code Lock} implementations provide additional functionality
+ * over the use of {@code synchronized} methods and statements by
+ * providing a non-blocking attempt to acquire a lock ({@link
+ * #tryLock()}), an attempt to acquire the lock that can be
+ * interrupted ({@link #lockInterruptibly}, and an attempt to acquire
+ * the lock that can timeout ({@link #tryLock(long, TimeUnit)}).
+ *
+ * <p>A {@code Lock} class can also provide behavior and semantics
+ * that is quite different from that of the implicit monitor lock,
+ * such as guaranteed ordering, non-reentrant usage, or deadlock
+ * detection. If an implementation provides such specialized semantics
+ * then the implementation must document those semantics.
+ *
+ * <p>Note that {@code Lock} instances are just normal objects and can
+ * themselves be used as the target in a {@code synchronized} statement.
+ * Acquiring the
+ * monitor lock of a {@code Lock} instance has no specified relationship
+ * with invoking any of the {@link #lock} methods of that instance.
+ * It is recommended that to avoid confusion you never use {@code Lock}
+ * instances in this way, except within their own implementation.
+ *
+ * <p>Except where noted, passing a {@code null} value for any
+ * parameter will result in a {@link NullPointerException} being
+ * thrown.
+ *
+ * <h3>Memory Synchronization</h3>
+ *
+ * <p>All {@code Lock} implementations <em>must</em> enforce the same
+ * memory synchronization semantics as provided by the built-in monitor
+ * lock, as described in
+ * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
+ * Chapter 17 of
+ * <cite>The Java&trade; Language Specification</cite></a>:
+ * <ul>
+ * <li>A successful {@code lock} operation has the same memory
+ * synchronization effects as a successful <em>Lock</em> action.
+ * <li>A successful {@code unlock} operation has the same
+ * memory synchronization effects as a successful <em>Unlock</em> action.
+ * </ul>
+ *
+ * Unsuccessful locking and unlocking operations, and reentrant
+ * locking/unlocking operations, do not require any memory
+ * synchronization effects.
+ *
+ * <h3>Implementation Considerations</h3>
+ *
+ * <p>The three forms of lock acquisition (interruptible,
+ * non-interruptible, and timed) may differ in their performance
+ * characteristics, ordering guarantees, or other implementation
+ * qualities.  Further, the ability to interrupt the <em>ongoing</em>
+ * acquisition of a lock may not be available in a given {@code Lock}
+ * class.  Consequently, an implementation is not required to define
+ * exactly the same guarantees or semantics for all three forms of
+ * lock acquisition, nor is it required to support interruption of an
+ * ongoing lock acquisition.  An implementation is required to clearly
+ * document the semantics and guarantees provided by each of the
+ * locking methods. It must also obey the interruption semantics as
+ * defined in this interface, to the extent that interruption of lock
+ * acquisition is supported: which is either totally, or only on
+ * method entry.
+ *
+ * <p>As interruption generally implies cancellation, and checks for
+ * interruption are often infrequent, an implementation can favor responding
+ * to an interrupt over normal method return. This is true even if it can be
+ * shown that the interrupt occurred after another action may have unblocked
+ * the thread. An implementation should document this behavior.
+ *
+ * @see ReentrantLock
+ * @see Condition
+ * @see ReadWriteLock
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Lock {
+
+    /**
+     * Acquires the lock.
+     *
+     * <p>If the lock is not available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until the
+     * lock has been acquired.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>A {@code Lock} implementation may be able to detect erroneous use
+     * of the lock, such as an invocation that would cause deadlock, and
+     * may throw an (unchecked) exception in such circumstances.  The
+     * circumstances and the exception type must be documented by that
+     * {@code Lock} implementation.
+     */
+    void lock();
+
+    /**
+     * Acquires the lock unless the current thread is
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the lock if it is available and returns immediately.
+     *
+     * <p>If the lock is not available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of two things happens:
+     *
+     * <ul>
+     * <li>The lock is acquired by the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of lock acquisition is supported.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while acquiring the
+     * lock, and interruption of lock acquisition is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The ability to interrupt a lock acquisition in some
+     * implementations may not be possible, and if possible may be an
+     * expensive operation.  The programmer should be aware that this
+     * may be the case. An implementation should document when this is
+     * the case.
+     *
+     * <p>An implementation can favor responding to an interrupt over
+     * normal method return.
+     *
+     * <p>A {@code Lock} implementation may be able to detect
+     * erroneous use of the lock, such as an invocation that would
+     * cause deadlock, and may throw an (unchecked) exception in such
+     * circumstances.  The circumstances and the exception type must
+     * be documented by that {@code Lock} implementation.
+     *
+     * @throws InterruptedException if the current thread is
+     *         interrupted while acquiring the lock (and interruption
+     *         of lock acquisition is supported)
+     */
+    void lockInterruptibly() throws InterruptedException;
+
+    /**
+     * Acquires the lock only if it is free at the time of invocation.
+     *
+     * <p>Acquires the lock if it is available and returns immediately
+     * with the value {@code true}.
+     * If the lock is not available then this method will return
+     * immediately with the value {@code false}.
+     *
+     * <p>A typical usage idiom for this method would be:
+     * <pre> {@code
+     * Lock lock = ...;
+     * if (lock.tryLock()) {
+     *   try {
+     *     // manipulate protected state
+     *   } finally {
+     *     lock.unlock();
+     *   }
+     * } else {
+     *   // perform alternative actions
+     * }}</pre>
+     *
+     * This usage ensures that the lock is unlocked if it was acquired, and
+     * doesn't try to unlock if the lock was not acquired.
+     *
+     * @return {@code true} if the lock was acquired and
+     *         {@code false} otherwise
+     */
+    boolean tryLock();
+
+    /**
+     * Acquires the lock if it is free within the given waiting time and the
+     * current thread has not been {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>If the lock is available this method returns immediately
+     * with the value {@code true}.
+     * If the lock is not available then
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     * <ul>
+     * <li>The lock is acquired by the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of lock acquisition is supported; or
+     * <li>The specified waiting time elapses
+     * </ul>
+     *
+     * <p>If the lock is acquired then the value {@code true} is returned.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while acquiring
+     * the lock, and interruption of lock acquisition is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.
+     * If the time is
+     * less than or equal to zero, the method will not wait at all.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The ability to interrupt a lock acquisition in some implementations
+     * may not be possible, and if possible may
+     * be an expensive operation.
+     * The programmer should be aware that this may be the case. An
+     * implementation should document when this is the case.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return, or reporting a timeout.
+     *
+     * <p>A {@code Lock} implementation may be able to detect
+     * erroneous use of the lock, such as an invocation that would cause
+     * deadlock, and may throw an (unchecked) exception in such circumstances.
+     * The circumstances and the exception type must be documented by that
+     * {@code Lock} implementation.
+     *
+     * @param time the maximum time to wait for the lock
+     * @param unit the time unit of the {@code time} argument
+     * @return {@code true} if the lock was acquired and {@code false}
+     *         if the waiting time elapsed before the lock was acquired
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     *         while acquiring the lock (and interruption of lock
+     *         acquisition is supported)
+     */
+    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
+
+    /**
+     * Releases the lock.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>A {@code Lock} implementation will usually impose
+     * restrictions on which thread can release a lock (typically only the
+     * holder of the lock can release it) and may throw
+     * an (unchecked) exception if the restriction is violated.
+     * Any restrictions and the exception
+     * type must be documented by that {@code Lock} implementation.
+     */
+    void unlock();
+
+    /**
+     * Returns a new {@link Condition} instance that is bound to this
+     * {@code Lock} instance.
+     *
+     * <p>Before waiting on the condition the lock must be held by the
+     * current thread.
+     * A call to {@link Condition#await()} will atomically release the lock
+     * before waiting and re-acquire the lock before the wait returns.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The exact operation of the {@link Condition} instance depends on
+     * the {@code Lock} implementation and must be documented by that
+     * implementation.
+     *
+     * @return A new {@link Condition} instance for this {@code Lock} instance
+     * @throws UnsupportedOperationException if this {@code Lock}
+     *         implementation does not support conditions
+     */
+    Condition newCondition();
+}
diff --git a/java/util/concurrent/locks/LockSupport.java b/java/util/concurrent/locks/LockSupport.java
new file mode 100644
index 0000000..4c57596
--- /dev/null
+++ b/java/util/concurrent/locks/LockSupport.java
@@ -0,0 +1,423 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+/**
+ * Basic thread blocking primitives for creating locks and other
+ * synchronization classes.
+ *
+ * <p>This class associates, with each thread that uses it, a permit
+ * (in the sense of the {@link java.util.concurrent.Semaphore
+ * Semaphore} class). A call to {@code park} will return immediately
+ * if the permit is available, consuming it in the process; otherwise
+ * it <em>may</em> block.  A call to {@code unpark} makes the permit
+ * available, if it was not already available. (Unlike with Semaphores
+ * though, permits do not accumulate. There is at most one.)
+ * Reliable usage requires the use of volatile (or atomic) variables
+ * to control when to park or unpark.  Orderings of calls to these
+ * methods are maintained with respect to volatile variable accesses,
+ * but not necessarily non-volatile variable accesses.
+ *
+ * <p>Methods {@code park} and {@code unpark} provide efficient
+ * means of blocking and unblocking threads that do not encounter the
+ * problems that cause the deprecated methods {@code Thread.suspend}
+ * and {@code Thread.resume} to be unusable for such purposes: Races
+ * between one thread invoking {@code park} and another thread trying
+ * to {@code unpark} it will preserve liveness, due to the
+ * permit. Additionally, {@code park} will return if the caller's
+ * thread was interrupted, and timeout versions are supported. The
+ * {@code park} method may also return at any other time, for "no
+ * reason", so in general must be invoked within a loop that rechecks
+ * conditions upon return. In this sense {@code park} serves as an
+ * optimization of a "busy wait" that does not waste as much time
+ * spinning, but must be paired with an {@code unpark} to be
+ * effective.
+ *
+ * <p>The three forms of {@code park} each also support a
+ * {@code blocker} object parameter. This object is recorded while
+ * the thread is blocked to permit monitoring and diagnostic tools to
+ * identify the reasons that threads are blocked. (Such tools may
+ * access blockers using method {@link #getBlocker(Thread)}.)
+ * The use of these forms rather than the original forms without this
+ * parameter is strongly encouraged. The normal argument to supply as
+ * a {@code blocker} within a lock implementation is {@code this}.
+ *
+ * <p>These methods are designed to be used as tools for creating
+ * higher-level synchronization utilities, and are not in themselves
+ * useful for most concurrency control applications.  The {@code park}
+ * method is designed for use only in constructions of the form:
+ *
+ * <pre> {@code
+ * while (!canProceed()) {
+ *   // ensure request to unpark is visible to other threads
+ *   ...
+ *   LockSupport.park(this);
+ * }}</pre>
+ *
+ * where no actions by the thread publishing a request to unpark,
+ * prior to the call to {@code park}, entail locking or blocking.
+ * Because only one permit is associated with each thread, any
+ * intermediary uses of {@code park}, including implicitly via class
+ * loading, could lead to an unresponsive thread (a "lost unpark").
+ *
+ * <p><b>Sample Usage.</b> Here is a sketch of a first-in-first-out
+ * non-reentrant lock class:
+ * <pre> {@code
+ * class FIFOMutex {
+ *   private final AtomicBoolean locked = new AtomicBoolean(false);
+ *   private final Queue<Thread> waiters
+ *     = new ConcurrentLinkedQueue<>();
+ *
+ *   public void lock() {
+ *     boolean wasInterrupted = false;
+ *     // publish current thread for unparkers
+ *     waiters.add(Thread.currentThread());
+ *
+ *     // Block while not first in queue or cannot acquire lock
+ *     while (waiters.peek() != Thread.currentThread() ||
+ *            !locked.compareAndSet(false, true)) {
+ *       LockSupport.park(this);
+ *       // ignore interrupts while waiting
+ *       if (Thread.interrupted())
+ *         wasInterrupted = true;
+ *     }
+ *
+ *     waiters.remove();
+ *     // ensure correct interrupt status on return
+ *     if (wasInterrupted)
+ *       Thread.currentThread().interrupt();
+ *   }
+ *
+ *   public void unlock() {
+ *     locked.set(false);
+ *     LockSupport.unpark(waiters.peek());
+ *   }
+ *
+ *   static {
+ *     // Reduce the risk of "lost unpark" due to classloading
+ *     Class<?> ensureLoaded = LockSupport.class;
+ *   }
+ * }}</pre>
+ */
+public class LockSupport {
+    private LockSupport() {} // Cannot be instantiated.
+
+    private static void setBlocker(Thread t, Object arg) {
+        // Even though volatile, hotspot doesn't need a write barrier here.
+        U.putObject(t, PARKBLOCKER, arg);
+    }
+
+    /**
+     * Makes available the permit for the given thread, if it
+     * was not already available.  If the thread was blocked on
+     * {@code park} then it will unblock.  Otherwise, its next call
+     * to {@code park} is guaranteed not to block. This operation
+     * is not guaranteed to have any effect at all if the given
+     * thread has not been started.
+     *
+     * @param thread the thread to unpark, or {@code null}, in which case
+     *        this operation has no effect
+     */
+    public static void unpark(Thread thread) {
+        if (thread != null)
+            U.unpark(thread);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes unless the
+     * permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call returns
+     * immediately; otherwise
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread upon return.
+     *
+     * @param blocker the synchronization object responsible for this
+     *        thread parking
+     * @since 1.6
+     */
+    public static void park(Object blocker) {
+        Thread t = Thread.currentThread();
+        setBlocker(t, blocker);
+        U.park(false, 0L);
+        setBlocker(t, null);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, for up to
+     * the specified waiting time, unless the permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of four
+     * things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified waiting time elapses; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the elapsed time
+     * upon return.
+     *
+     * @param blocker the synchronization object responsible for this
+     *        thread parking
+     * @param nanos the maximum number of nanoseconds to wait
+     * @since 1.6
+     */
+    public static void parkNanos(Object blocker, long nanos) {
+        if (nanos > 0) {
+            Thread t = Thread.currentThread();
+            setBlocker(t, blocker);
+            U.park(false, nanos);
+            setBlocker(t, null);
+        }
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, until
+     * the specified deadline, unless the permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of four
+     * things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread; or
+     *
+     * <li>The specified deadline passes; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the current time
+     * upon return.
+     *
+     * @param blocker the synchronization object responsible for this
+     *        thread parking
+     * @param deadline the absolute time, in milliseconds from the Epoch,
+     *        to wait until
+     * @since 1.6
+     */
+    public static void parkUntil(Object blocker, long deadline) {
+        Thread t = Thread.currentThread();
+        setBlocker(t, blocker);
+        U.park(true, deadline);
+        setBlocker(t, null);
+    }
+
+    /**
+     * Returns the blocker object supplied to the most recent
+     * invocation of a park method that has not yet unblocked, or null
+     * if not blocked.  The value returned is just a momentary
+     * snapshot -- the thread may have since unblocked or blocked on a
+     * different blocker object.
+     *
+     * @param t the thread
+     * @return the blocker
+     * @throws NullPointerException if argument is null
+     * @since 1.6
+     */
+    public static Object getBlocker(Thread t) {
+        if (t == null)
+            throw new NullPointerException();
+        return U.getObjectVolatile(t, PARKBLOCKER);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes unless the
+     * permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of three
+     * things happens:
+     *
+     * <ul>
+     *
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread upon return.
+     */
+    public static void park() {
+        U.park(false, 0L);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, for up to
+     * the specified waiting time, unless the permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of four
+     * things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified waiting time elapses; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the elapsed time
+     * upon return.
+     *
+     * @param nanos the maximum number of nanoseconds to wait
+     */
+    public static void parkNanos(long nanos) {
+        if (nanos > 0)
+            U.park(false, nanos);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, until
+     * the specified deadline, unless the permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of four
+     * things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified deadline passes; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the current time
+     * upon return.
+     *
+     * @param deadline the absolute time, in milliseconds from the Epoch,
+     *        to wait until
+     */
+    public static void parkUntil(long deadline) {
+        U.park(true, deadline);
+    }
+
+    /**
+     * Returns the pseudo-randomly initialized or updated secondary seed.
+     * Copied from ThreadLocalRandom due to package access restrictions.
+     */
+    static final int nextSecondarySeed() {
+        int r;
+        Thread t = Thread.currentThread();
+        if ((r = U.getInt(t, SECONDARY)) != 0) {
+            r ^= r << 13;   // xorshift
+            r ^= r >>> 17;
+            r ^= r << 5;
+        }
+        else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
+            r = 1; // avoid zero
+        U.putInt(t, SECONDARY, r);
+        return r;
+    }
+
+    // Hotspot implementation via intrinsics API
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long PARKBLOCKER;
+    private static final long SECONDARY;
+    static {
+        try {
+            PARKBLOCKER = U.objectFieldOffset
+                (Thread.class.getDeclaredField("parkBlocker"));
+            SECONDARY = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/locks/ReadWriteLock.java b/java/util/concurrent/locks/ReadWriteLock.java
new file mode 100644
index 0000000..00fb845
--- /dev/null
+++ b/java/util/concurrent/locks/ReadWriteLock.java
@@ -0,0 +1,133 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+/**
+ * A {@code ReadWriteLock} maintains a pair of associated {@link
+ * Lock locks}, one for read-only operations and one for writing.
+ * The {@linkplain #readLock read lock} may be held simultaneously
+ * by multiple reader threads, so long as there are no writers.
+ * The {@linkplain #writeLock write lock} is exclusive.
+ *
+ * <p>All {@code ReadWriteLock} implementations must guarantee that
+ * the memory synchronization effects of {@code writeLock} operations
+ * (as specified in the {@link Lock} interface) also hold with respect
+ * to the associated {@code readLock}. That is, a thread successfully
+ * acquiring the read lock will see all updates made upon previous
+ * release of the write lock.
+ *
+ * <p>A read-write lock allows for a greater level of concurrency in
+ * accessing shared data than that permitted by a mutual exclusion lock.
+ * It exploits the fact that while only a single thread at a time (a
+ * <em>writer</em> thread) can modify the shared data, in many cases any
+ * number of threads can concurrently read the data (hence <em>reader</em>
+ * threads).
+ * In theory, the increase in concurrency permitted by the use of a read-write
+ * lock will lead to performance improvements over the use of a mutual
+ * exclusion lock. In practice this increase in concurrency will only be fully
+ * realized on a multi-processor, and then only if the access patterns for
+ * the shared data are suitable.
+ *
+ * <p>Whether or not a read-write lock will improve performance over the use
+ * of a mutual exclusion lock depends on the frequency that the data is
+ * read compared to being modified, the duration of the read and write
+ * operations, and the contention for the data - that is, the number of
+ * threads that will try to read or write the data at the same time.
+ * For example, a collection that is initially populated with data and
+ * thereafter infrequently modified, while being frequently searched
+ * (such as a directory of some kind) is an ideal candidate for the use of
+ * a read-write lock. However, if updates become frequent then the data
+ * spends most of its time being exclusively locked and there is little, if any
+ * increase in concurrency. Further, if the read operations are too short
+ * the overhead of the read-write lock implementation (which is inherently
+ * more complex than a mutual exclusion lock) can dominate the execution
+ * cost, particularly as many read-write lock implementations still serialize
+ * all threads through a small section of code. Ultimately, only profiling
+ * and measurement will establish whether the use of a read-write lock is
+ * suitable for your application.
+ *
+ *
+ * <p>Although the basic operation of a read-write lock is straight-forward,
+ * there are many policy decisions that an implementation must make, which
+ * may affect the effectiveness of the read-write lock in a given application.
+ * Examples of these policies include:
+ * <ul>
+ * <li>Determining whether to grant the read lock or the write lock, when
+ * both readers and writers are waiting, at the time that a writer releases
+ * the write lock. Writer preference is common, as writes are expected to be
+ * short and infrequent. Reader preference is less common as it can lead to
+ * lengthy delays for a write if the readers are frequent and long-lived as
+ * expected. Fair, or &quot;in-order&quot; implementations are also possible.
+ *
+ * <li>Determining whether readers that request the read lock while a
+ * reader is active and a writer is waiting, are granted the read lock.
+ * Preference to the reader can delay the writer indefinitely, while
+ * preference to the writer can reduce the potential for concurrency.
+ *
+ * <li>Determining whether the locks are reentrant: can a thread with the
+ * write lock reacquire it? Can it acquire a read lock while holding the
+ * write lock? Is the read lock itself reentrant?
+ *
+ * <li>Can the write lock be downgraded to a read lock without allowing
+ * an intervening writer? Can a read lock be upgraded to a write lock,
+ * in preference to other waiting readers or writers?
+ *
+ * </ul>
+ * You should consider all of these things when evaluating the suitability
+ * of a given implementation for your application.
+ *
+ * @see ReentrantReadWriteLock
+ * @see Lock
+ * @see ReentrantLock
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ReadWriteLock {
+    /**
+     * Returns the lock used for reading.
+     *
+     * @return the lock used for reading
+     */
+    Lock readLock();
+
+    /**
+     * Returns the lock used for writing.
+     *
+     * @return the lock used for writing
+     */
+    Lock writeLock();
+}
diff --git a/java/util/concurrent/locks/ReentrantLock.java b/java/util/concurrent/locks/ReentrantLock.java
new file mode 100644
index 0000000..3c1c492
--- /dev/null
+++ b/java/util/concurrent/locks/ReentrantLock.java
@@ -0,0 +1,770 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A reentrant mutual exclusion {@link Lock} with the same basic
+ * behavior and semantics as the implicit monitor lock accessed using
+ * {@code synchronized} methods and statements, but with extended
+ * capabilities.
+ *
+ * <p>A {@code ReentrantLock} is <em>owned</em> by the thread last
+ * successfully locking, but not yet unlocking it. A thread invoking
+ * {@code lock} will return, successfully acquiring the lock, when
+ * the lock is not owned by another thread. The method will return
+ * immediately if the current thread already owns the lock. This can
+ * be checked using methods {@link #isHeldByCurrentThread}, and {@link
+ * #getHoldCount}.
+ *
+ * <p>The constructor for this class accepts an optional
+ * <em>fairness</em> parameter.  When set {@code true}, under
+ * contention, locks favor granting access to the longest-waiting
+ * thread.  Otherwise this lock does not guarantee any particular
+ * access order.  Programs using fair locks accessed by many threads
+ * may display lower overall throughput (i.e., are slower; often much
+ * slower) than those using the default setting, but have smaller
+ * variances in times to obtain locks and guarantee lack of
+ * starvation. Note however, that fairness of locks does not guarantee
+ * fairness of thread scheduling. Thus, one of many threads using a
+ * fair lock may obtain it multiple times in succession while other
+ * active threads are not progressing and not currently holding the
+ * lock.
+ * Also note that the untimed {@link #tryLock()} method does not
+ * honor the fairness setting. It will succeed if the lock
+ * is available even if other threads are waiting.
+ *
+ * <p>It is recommended practice to <em>always</em> immediately
+ * follow a call to {@code lock} with a {@code try} block, most
+ * typically in a before/after construction such as:
+ *
+ * <pre> {@code
+ * class X {
+ *   private final ReentrantLock lock = new ReentrantLock();
+ *   // ...
+ *
+ *   public void m() {
+ *     lock.lock();  // block until condition holds
+ *     try {
+ *       // ... method body
+ *     } finally {
+ *       lock.unlock()
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>In addition to implementing the {@link Lock} interface, this
+ * class defines a number of {@code public} and {@code protected}
+ * methods for inspecting the state of the lock.  Some of these
+ * methods are only useful for instrumentation and monitoring.
+ *
+ * <p>Serialization of this class behaves in the same way as built-in
+ * locks: a deserialized lock is in the unlocked state, regardless of
+ * its state when serialized.
+ *
+ * <p>This lock supports a maximum of 2147483647 recursive locks by
+ * the same thread. Attempts to exceed this limit result in
+ * {@link Error} throws from locking methods.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ReentrantLock implements Lock, java.io.Serializable {
+    private static final long serialVersionUID = 7373984872572414699L;
+    /** Synchronizer providing all implementation mechanics */
+    private final Sync sync;
+
+    /**
+     * Base of synchronization control for this lock. Subclassed
+     * into fair and nonfair versions below. Uses AQS state to
+     * represent the number of holds on the lock.
+     */
+    abstract static class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = -5179523762034025860L;
+
+        /**
+         * Performs {@link Lock#lock}. The main reason for subclassing
+         * is to allow fast path for nonfair version.
+         */
+        abstract void lock();
+
+        /**
+         * Performs non-fair tryLock.  tryAcquire is implemented in
+         * subclasses, but both need nonfair try for trylock method.
+         */
+        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+        // @ReservedStackAccess
+        final boolean nonfairTryAcquire(int acquires) {
+            final Thread current = Thread.currentThread();
+            int c = getState();
+            if (c == 0) {
+                if (compareAndSetState(0, acquires)) {
+                    setExclusiveOwnerThread(current);
+                    return true;
+                }
+            }
+            else if (current == getExclusiveOwnerThread()) {
+                int nextc = c + acquires;
+                if (nextc < 0) // overflow
+                    throw new Error("Maximum lock count exceeded");
+                setState(nextc);
+                return true;
+            }
+            return false;
+        }
+
+        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+        // @ReservedStackAccess
+        protected final boolean tryRelease(int releases) {
+            int c = getState() - releases;
+            if (Thread.currentThread() != getExclusiveOwnerThread())
+                throw new IllegalMonitorStateException();
+            boolean free = false;
+            if (c == 0) {
+                free = true;
+                setExclusiveOwnerThread(null);
+            }
+            setState(c);
+            return free;
+        }
+
+        protected final boolean isHeldExclusively() {
+            // While we must in general read state before owner,
+            // we don't need to do so to check if current thread is owner
+            return getExclusiveOwnerThread() == Thread.currentThread();
+        }
+
+        final ConditionObject newCondition() {
+            return new ConditionObject();
+        }
+
+        // Methods relayed from outer class
+
+        final Thread getOwner() {
+            return getState() == 0 ? null : getExclusiveOwnerThread();
+        }
+
+        final int getHoldCount() {
+            return isHeldExclusively() ? getState() : 0;
+        }
+
+        final boolean isLocked() {
+            return getState() != 0;
+        }
+
+        /**
+         * Reconstitutes the instance from a stream (that is, deserializes it).
+         */
+        private void readObject(java.io.ObjectInputStream s)
+            throws java.io.IOException, ClassNotFoundException {
+            s.defaultReadObject();
+            setState(0); // reset to unlocked state
+        }
+    }
+
+    /**
+     * Sync object for non-fair locks
+     */
+    static final class NonfairSync extends Sync {
+        private static final long serialVersionUID = 7316153563782823691L;
+
+        /**
+         * Performs lock.  Try immediate barge, backing up to normal
+         * acquire on failure.
+         */
+        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+        // @ReservedStackAccess
+        final void lock() {
+            if (compareAndSetState(0, 1))
+                setExclusiveOwnerThread(Thread.currentThread());
+            else
+                acquire(1);
+        }
+
+        protected final boolean tryAcquire(int acquires) {
+            return nonfairTryAcquire(acquires);
+        }
+    }
+
+    /**
+     * Sync object for fair locks
+     */
+    static final class FairSync extends Sync {
+        private static final long serialVersionUID = -3000897897090466540L;
+
+        final void lock() {
+            acquire(1);
+        }
+
+        /**
+         * Fair version of tryAcquire.  Don't grant access unless
+         * recursive call or no waiters or is first.
+         */
+        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+        // @ReservedStackAccess
+        protected final boolean tryAcquire(int acquires) {
+            final Thread current = Thread.currentThread();
+            int c = getState();
+            if (c == 0) {
+                if (!hasQueuedPredecessors() &&
+                    compareAndSetState(0, acquires)) {
+                    setExclusiveOwnerThread(current);
+                    return true;
+                }
+            }
+            else if (current == getExclusiveOwnerThread()) {
+                int nextc = c + acquires;
+                if (nextc < 0)
+                    throw new Error("Maximum lock count exceeded");
+                setState(nextc);
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Creates an instance of {@code ReentrantLock}.
+     * This is equivalent to using {@code ReentrantLock(false)}.
+     */
+    public ReentrantLock() {
+        sync = new NonfairSync();
+    }
+
+    /**
+     * Creates an instance of {@code ReentrantLock} with the
+     * given fairness policy.
+     *
+     * @param fair {@code true} if this lock should use a fair ordering policy
+     */
+    public ReentrantLock(boolean fair) {
+        sync = fair ? new FairSync() : new NonfairSync();
+    }
+
+    /**
+     * Acquires the lock.
+     *
+     * <p>Acquires the lock if it is not held by another thread and returns
+     * immediately, setting the lock hold count to one.
+     *
+     * <p>If the current thread already holds the lock then the hold
+     * count is incremented by one and the method returns immediately.
+     *
+     * <p>If the lock is held by another thread then the
+     * current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until the lock has been acquired,
+     * at which time the lock hold count is set to one.
+     */
+    public void lock() {
+        sync.lock();
+    }
+
+    /**
+     * Acquires the lock unless the current thread is
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the lock if it is not held by another thread and returns
+     * immediately, setting the lock hold count to one.
+     *
+     * <p>If the current thread already holds this lock then the hold count
+     * is incremented by one and the method returns immediately.
+     *
+     * <p>If the lock is held by another thread then the
+     * current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of two things happens:
+     *
+     * <ul>
+     *
+     * <li>The lock is acquired by the current thread; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread.
+     *
+     * </ul>
+     *
+     * <p>If the lock is acquired by the current thread then the lock hold
+     * count is set to one.
+     *
+     * <p>If the current thread:
+     *
+     * <ul>
+     *
+     * <li>has its interrupted status set on entry to this method; or
+     *
+     * <li>is {@linkplain Thread#interrupt interrupted} while acquiring
+     * the lock,
+     *
+     * </ul>
+     *
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>In this implementation, as this method is an explicit
+     * interruption point, preference is given to responding to the
+     * interrupt over normal or reentrant acquisition of the lock.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public void lockInterruptibly() throws InterruptedException {
+        sync.acquireInterruptibly(1);
+    }
+
+    /**
+     * Acquires the lock only if it is not held by another thread at the time
+     * of invocation.
+     *
+     * <p>Acquires the lock if it is not held by another thread and
+     * returns immediately with the value {@code true}, setting the
+     * lock hold count to one. Even when this lock has been set to use a
+     * fair ordering policy, a call to {@code tryLock()} <em>will</em>
+     * immediately acquire the lock if it is available, whether or not
+     * other threads are currently waiting for the lock.
+     * This &quot;barging&quot; behavior can be useful in certain
+     * circumstances, even though it breaks fairness. If you want to honor
+     * the fairness setting for this lock, then use
+     * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) }
+     * which is almost equivalent (it also detects interruption).
+     *
+     * <p>If the current thread already holds this lock then the hold
+     * count is incremented by one and the method returns {@code true}.
+     *
+     * <p>If the lock is held by another thread then this method will return
+     * immediately with the value {@code false}.
+     *
+     * @return {@code true} if the lock was free and was acquired by the
+     *         current thread, or the lock was already held by the current
+     *         thread; and {@code false} otherwise
+     */
+    public boolean tryLock() {
+        return sync.nonfairTryAcquire(1);
+    }
+
+    /**
+     * Acquires the lock if it is not held by another thread within the given
+     * waiting time and the current thread has not been
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the lock if it is not held by another thread and returns
+     * immediately with the value {@code true}, setting the lock hold count
+     * to one. If this lock has been set to use a fair ordering policy then
+     * an available lock <em>will not</em> be acquired if any other threads
+     * are waiting for the lock. This is in contrast to the {@link #tryLock()}
+     * method. If you want a timed {@code tryLock} that does permit barging on
+     * a fair lock then combine the timed and un-timed forms together:
+     *
+     * <pre> {@code
+     * if (lock.tryLock() ||
+     *     lock.tryLock(timeout, unit)) {
+     *   ...
+     * }}</pre>
+     *
+     * <p>If the current thread
+     * already holds this lock then the hold count is incremented by one and
+     * the method returns {@code true}.
+     *
+     * <p>If the lock is held by another thread then the
+     * current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     *
+     * <ul>
+     *
+     * <li>The lock is acquired by the current thread; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified waiting time elapses
+     *
+     * </ul>
+     *
+     * <p>If the lock is acquired then the value {@code true} is returned and
+     * the lock hold count is set to one.
+     *
+     * <p>If the current thread:
+     *
+     * <ul>
+     *
+     * <li>has its interrupted status set on entry to this method; or
+     *
+     * <li>is {@linkplain Thread#interrupt interrupted} while
+     * acquiring the lock,
+     *
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.
+     *
+     * <p>In this implementation, as this method is an explicit
+     * interruption point, preference is given to responding to the
+     * interrupt over normal or reentrant acquisition of the lock, and
+     * over reporting the elapse of the waiting time.
+     *
+     * @param timeout the time to wait for the lock
+     * @param unit the time unit of the timeout argument
+     * @return {@code true} if the lock was free and was acquired by the
+     *         current thread, or the lock was already held by the current
+     *         thread; and {@code false} if the waiting time elapsed before
+     *         the lock could be acquired
+     * @throws InterruptedException if the current thread is interrupted
+     * @throws NullPointerException if the time unit is null
+     */
+    public boolean tryLock(long timeout, TimeUnit unit)
+            throws InterruptedException {
+        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+    }
+
+    /**
+     * Attempts to release this lock.
+     *
+     * <p>If the current thread is the holder of this lock then the hold
+     * count is decremented.  If the hold count is now zero then the lock
+     * is released.  If the current thread is not the holder of this
+     * lock then {@link IllegalMonitorStateException} is thrown.
+     *
+     * @throws IllegalMonitorStateException if the current thread does not
+     *         hold this lock
+     */
+    public void unlock() {
+        sync.release(1);
+    }
+
+    /**
+     * Returns a {@link Condition} instance for use with this
+     * {@link Lock} instance.
+     *
+     * <p>The returned {@link Condition} instance supports the same
+     * usages as do the {@link Object} monitor methods ({@link
+     * Object#wait() wait}, {@link Object#notify notify}, and {@link
+     * Object#notifyAll notifyAll}) when used with the built-in
+     * monitor lock.
+     *
+     * <ul>
+     *
+     * <li>If this lock is not held when any of the {@link Condition}
+     * {@linkplain Condition#await() waiting} or {@linkplain
+     * Condition#signal signalling} methods are called, then an {@link
+     * IllegalMonitorStateException} is thrown.
+     *
+     * <li>When the condition {@linkplain Condition#await() waiting}
+     * methods are called the lock is released and, before they
+     * return, the lock is reacquired and the lock hold count restored
+     * to what it was when the method was called.
+     *
+     * <li>If a thread is {@linkplain Thread#interrupt interrupted}
+     * while waiting then the wait will terminate, an {@link
+     * InterruptedException} will be thrown, and the thread's
+     * interrupted status will be cleared.
+     *
+     * <li>Waiting threads are signalled in FIFO order.
+     *
+     * <li>The ordering of lock reacquisition for threads returning
+     * from waiting methods is the same as for threads initially
+     * acquiring the lock, which is in the default case not specified,
+     * but for <em>fair</em> locks favors those threads that have been
+     * waiting the longest.
+     *
+     * </ul>
+     *
+     * @return the Condition object
+     */
+    public Condition newCondition() {
+        return sync.newCondition();
+    }
+
+    /**
+     * Queries the number of holds on this lock by the current thread.
+     *
+     * <p>A thread has a hold on a lock for each lock action that is not
+     * matched by an unlock action.
+     *
+     * <p>The hold count information is typically only used for testing and
+     * debugging purposes. For example, if a certain section of code should
+     * not be entered with the lock already held then we can assert that
+     * fact:
+     *
+     * <pre> {@code
+     * class X {
+     *   ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *   public void m() {
+     *     assert lock.getHoldCount() == 0;
+     *     lock.lock();
+     *     try {
+     *       // ... method body
+     *     } finally {
+     *       lock.unlock();
+     *     }
+     *   }
+     * }}</pre>
+     *
+     * @return the number of holds on this lock by the current thread,
+     *         or zero if this lock is not held by the current thread
+     */
+    public int getHoldCount() {
+        return sync.getHoldCount();
+    }
+
+    /**
+     * Queries if this lock is held by the current thread.
+     *
+     * <p>Analogous to the {@link Thread#holdsLock(Object)} method for
+     * built-in monitor locks, this method is typically used for
+     * debugging and testing. For example, a method that should only be
+     * called while a lock is held can assert that this is the case:
+     *
+     * <pre> {@code
+     * class X {
+     *   ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *
+     *   public void m() {
+     *       assert lock.isHeldByCurrentThread();
+     *       // ... method body
+     *   }
+     * }}</pre>
+     *
+     * <p>It can also be used to ensure that a reentrant lock is used
+     * in a non-reentrant manner, for example:
+     *
+     * <pre> {@code
+     * class X {
+     *   ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *
+     *   public void m() {
+     *       assert !lock.isHeldByCurrentThread();
+     *       lock.lock();
+     *       try {
+     *           // ... method body
+     *       } finally {
+     *           lock.unlock();
+     *       }
+     *   }
+     * }}</pre>
+     *
+     * @return {@code true} if current thread holds this lock and
+     *         {@code false} otherwise
+     */
+    public boolean isHeldByCurrentThread() {
+        return sync.isHeldExclusively();
+    }
+
+    /**
+     * Queries if this lock is held by any thread. This method is
+     * designed for use in monitoring of the system state,
+     * not for synchronization control.
+     *
+     * @return {@code true} if any thread holds this lock and
+     *         {@code false} otherwise
+     */
+    public boolean isLocked() {
+        return sync.isLocked();
+    }
+
+    /**
+     * Returns {@code true} if this lock has fairness set true.
+     *
+     * @return {@code true} if this lock has fairness set true
+     */
+    public final boolean isFair() {
+        return sync instanceof FairSync;
+    }
+
+    /**
+     * Returns the thread that currently owns this lock, or
+     * {@code null} if not owned. When this method is called by a
+     * thread that is not the owner, the return value reflects a
+     * best-effort approximation of current lock status. For example,
+     * the owner may be momentarily {@code null} even if there are
+     * threads trying to acquire the lock but have not yet done so.
+     * This method is designed to facilitate construction of
+     * subclasses that provide more extensive lock monitoring
+     * facilities.
+     *
+     * @return the owner, or {@code null} if not owned
+     */
+    protected Thread getOwner() {
+        return sync.getOwner();
+    }
+
+    /**
+     * Queries whether any threads are waiting to acquire this lock. Note that
+     * because cancellations may occur at any time, a {@code true}
+     * return does not guarantee that any other thread will ever
+     * acquire this lock.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @return {@code true} if there may be other threads waiting to
+     *         acquire the lock
+     */
+    public final boolean hasQueuedThreads() {
+        return sync.hasQueuedThreads();
+    }
+
+    /**
+     * Queries whether the given thread is waiting to acquire this
+     * lock. Note that because cancellations may occur at any time, a
+     * {@code true} return does not guarantee that this thread
+     * will ever acquire this lock.  This method is designed primarily for use
+     * in monitoring of the system state.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is queued waiting for this lock
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean hasQueuedThread(Thread thread) {
+        return sync.isQueued(thread);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting to acquire
+     * this lock.  The value is only an estimate because the number of
+     * threads may change dynamically while this method traverses
+     * internal data structures.  This method is designed for use in
+     * monitoring system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting for this lock
+     */
+    public final int getQueueLength() {
+        return sync.getQueueLength();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire this lock.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedThreads() {
+        return sync.getQueuedThreads();
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with this lock. Note that because timeouts and
+     * interrupts may occur at any time, a {@code true} return does
+     * not guarantee that a future {@code signal} will awaken any
+     * threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public boolean hasWaiters(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with this lock. Note that because
+     * timeouts and interrupts may occur at any time, the estimate
+     * serves only as an upper bound on the actual number of waiters.
+     * This method is designed for use in monitoring of the system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public int getWaitQueueLength(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with this lock.
+     * Because the actual set of threads may change dynamically while
+     * constructing this result, the returned collection is only a
+     * best-effort estimate. The elements of the returned collection
+     * are in no particular order.  This method is designed to
+     * facilitate construction of subclasses that provide more
+     * extensive condition monitoring facilities.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    protected Collection<Thread> getWaitingThreads(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a string identifying this lock, as well as its lock state.
+     * The state, in brackets, includes either the String {@code "Unlocked"}
+     * or the String {@code "Locked by"} followed by the
+     * {@linkplain Thread#getName name} of the owning thread.
+     *
+     * @return a string identifying this lock, as well as its lock state
+     */
+    public String toString() {
+        Thread o = sync.getOwner();
+        return super.toString() + ((o == null) ?
+                                   "[Unlocked]" :
+                                   "[Locked by thread " + o.getName() + "]");
+    }
+}
diff --git a/java/util/concurrent/locks/ReentrantReadWriteLock.java b/java/util/concurrent/locks/ReentrantReadWriteLock.java
new file mode 100644
index 0000000..9d98f37
--- /dev/null
+++ b/java/util/concurrent/locks/ReentrantReadWriteLock.java
@@ -0,0 +1,1515 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An implementation of {@link ReadWriteLock} supporting similar
+ * semantics to {@link ReentrantLock}.
+ * <p>This class has the following properties:
+ *
+ * <ul>
+ * <li><b>Acquisition order</b>
+ *
+ * <p>This class does not impose a reader or writer preference
+ * ordering for lock access.  However, it does support an optional
+ * <em>fairness</em> policy.
+ *
+ * <dl>
+ * <dt><b><i>Non-fair mode (default)</i></b>
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * When constructed as non-fair (the default), the order of entry
+ * to the read and write lock is unspecified, subject to reentrancy
+ * constraints.  A nonfair lock that is continuously contended may
+ * indefinitely postpone one or more reader or writer threads, but
+ * will normally have higher throughput than a fair lock.
+ *
+ * <dt><b><i>Fair mode</i></b>
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * When constructed as fair, threads contend for entry using an
+ * approximately arrival-order policy. When the currently held lock
+ * is released, either the longest-waiting single writer thread will
+ * be assigned the write lock, or if there is a group of reader threads
+ * waiting longer than all waiting writer threads, that group will be
+ * assigned the read lock.
+ *
+ * <p>A thread that tries to acquire a fair read lock (non-reentrantly)
+ * will block if either the write lock is held, or there is a waiting
+ * writer thread. The thread will not acquire the read lock until
+ * after the oldest currently waiting writer thread has acquired and
+ * released the write lock. Of course, if a waiting writer abandons
+ * its wait, leaving one or more reader threads as the longest waiters
+ * in the queue with the write lock free, then those readers will be
+ * assigned the read lock.
+ *
+ * <p>A thread that tries to acquire a fair write lock (non-reentrantly)
+ * will block unless both the read lock and write lock are free (which
+ * implies there are no waiting threads).  (Note that the non-blocking
+ * {@link ReadLock#tryLock()} and {@link WriteLock#tryLock()} methods
+ * do not honor this fair setting and will immediately acquire the lock
+ * if it is possible, regardless of waiting threads.)
+ * </dl>
+ *
+ * <li><b>Reentrancy</b>
+ *
+ * <p>This lock allows both readers and writers to reacquire read or
+ * write locks in the style of a {@link ReentrantLock}. Non-reentrant
+ * readers are not allowed until all write locks held by the writing
+ * thread have been released.
+ *
+ * <p>Additionally, a writer can acquire the read lock, but not
+ * vice-versa.  Among other applications, reentrancy can be useful
+ * when write locks are held during calls or callbacks to methods that
+ * perform reads under read locks.  If a reader tries to acquire the
+ * write lock it will never succeed.
+ *
+ * <li><b>Lock downgrading</b>
+ * <p>Reentrancy also allows downgrading from the write lock to a read lock,
+ * by acquiring the write lock, then the read lock and then releasing the
+ * write lock. However, upgrading from a read lock to the write lock is
+ * <b>not</b> possible.
+ *
+ * <li><b>Interruption of lock acquisition</b>
+ * <p>The read lock and write lock both support interruption during lock
+ * acquisition.
+ *
+ * <li><b>{@link Condition} support</b>
+ * <p>The write lock provides a {@link Condition} implementation that
+ * behaves in the same way, with respect to the write lock, as the
+ * {@link Condition} implementation provided by
+ * {@link ReentrantLock#newCondition} does for {@link ReentrantLock}.
+ * This {@link Condition} can, of course, only be used with the write lock.
+ *
+ * <p>The read lock does not support a {@link Condition} and
+ * {@code readLock().newCondition()} throws
+ * {@code UnsupportedOperationException}.
+ *
+ * <li><b>Instrumentation</b>
+ * <p>This class supports methods to determine whether locks
+ * are held or contended. These methods are designed for monitoring
+ * system state, not for synchronization control.
+ * </ul>
+ *
+ * <p>Serialization of this class behaves in the same way as built-in
+ * locks: a deserialized lock is in the unlocked state, regardless of
+ * its state when serialized.
+ *
+ * <p><b>Sample usages</b>. Here is a code sketch showing how to perform
+ * lock downgrading after updating a cache (exception handling is
+ * particularly tricky when handling multiple locks in a non-nested
+ * fashion):
+ *
+ * <pre> {@code
+ * class CachedData {
+ *   Object data;
+ *   volatile boolean cacheValid;
+ *   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ *
+ *   void processCachedData() {
+ *     rwl.readLock().lock();
+ *     if (!cacheValid) {
+ *       // Must release read lock before acquiring write lock
+ *       rwl.readLock().unlock();
+ *       rwl.writeLock().lock();
+ *       try {
+ *         // Recheck state because another thread might have
+ *         // acquired write lock and changed state before we did.
+ *         if (!cacheValid) {
+ *           data = ...
+ *           cacheValid = true;
+ *         }
+ *         // Downgrade by acquiring read lock before releasing write lock
+ *         rwl.readLock().lock();
+ *       } finally {
+ *         rwl.writeLock().unlock(); // Unlock write, still hold read
+ *       }
+ *     }
+ *
+ *     try {
+ *       use(data);
+ *     } finally {
+ *       rwl.readLock().unlock();
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * ReentrantReadWriteLocks can be used to improve concurrency in some
+ * uses of some kinds of Collections. This is typically worthwhile
+ * only when the collections are expected to be large, accessed by
+ * more reader threads than writer threads, and entail operations with
+ * overhead that outweighs synchronization overhead. For example, here
+ * is a class using a TreeMap that is expected to be large and
+ * concurrently accessed.
+ *
+ * <pre> {@code
+ * class RWDictionary {
+ *   private final Map<String, Data> m = new TreeMap<>();
+ *   private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ *   private final Lock r = rwl.readLock();
+ *   private final Lock w = rwl.writeLock();
+ *
+ *   public Data get(String key) {
+ *     r.lock();
+ *     try { return m.get(key); }
+ *     finally { r.unlock(); }
+ *   }
+ *   public List<String> allKeys() {
+ *     r.lock();
+ *     try { return new ArrayList<>(m.keySet()); }
+ *     finally { r.unlock(); }
+ *   }
+ *   public Data put(String key, Data value) {
+ *     w.lock();
+ *     try { return m.put(key, value); }
+ *     finally { w.unlock(); }
+ *   }
+ *   public void clear() {
+ *     w.lock();
+ *     try { m.clear(); }
+ *     finally { w.unlock(); }
+ *   }
+ * }}</pre>
+ *
+ * <h3>Implementation Notes</h3>
+ *
+ * <p>This lock supports a maximum of 65535 recursive write locks
+ * and 65535 read locks. Attempts to exceed these limits result in
+ * {@link Error} throws from locking methods.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ReentrantReadWriteLock
+        implements ReadWriteLock, java.io.Serializable {
+    private static final long serialVersionUID = -6992448646407690164L;
+    /** Inner class providing readlock */
+    private final ReentrantReadWriteLock.ReadLock readerLock;
+    /** Inner class providing writelock */
+    private final ReentrantReadWriteLock.WriteLock writerLock;
+    /** Performs all synchronization mechanics */
+    final Sync sync;
+
+    /**
+     * Creates a new {@code ReentrantReadWriteLock} with
+     * default (nonfair) ordering properties.
+     */
+    public ReentrantReadWriteLock() {
+        this(false);
+    }
+
+    /**
+     * Creates a new {@code ReentrantReadWriteLock} with
+     * the given fairness policy.
+     *
+     * @param fair {@code true} if this lock should use a fair ordering policy
+     */
+    public ReentrantReadWriteLock(boolean fair) {
+        sync = fair ? new FairSync() : new NonfairSync();
+        readerLock = new ReadLock(this);
+        writerLock = new WriteLock(this);
+    }
+
+    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
+    public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }
+
+    /**
+     * Synchronization implementation for ReentrantReadWriteLock.
+     * Subclassed into fair and nonfair versions.
+     */
+    abstract static class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = 6317671515068378041L;
+
+        /*
+         * Read vs write count extraction constants and functions.
+         * Lock state is logically divided into two unsigned shorts:
+         * The lower one representing the exclusive (writer) lock hold count,
+         * and the upper the shared (reader) hold count.
+         */
+
+        static final int SHARED_SHIFT   = 16;
+        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
+        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
+        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
+
+        /** Returns the number of shared holds represented in count. */
+        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
+        /** Returns the number of exclusive holds represented in count. */
+        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
+
+        /**
+         * A counter for per-thread read hold counts.
+         * Maintained as a ThreadLocal; cached in cachedHoldCounter.
+         */
+        static final class HoldCounter {
+            int count;          // initially 0
+            // Use id, not reference, to avoid garbage retention
+            final long tid = getThreadId(Thread.currentThread());
+        }
+
+        /**
+         * ThreadLocal subclass. Easiest to explicitly define for sake
+         * of deserialization mechanics.
+         */
+        static final class ThreadLocalHoldCounter
+            extends ThreadLocal<HoldCounter> {
+            public HoldCounter initialValue() {
+                return new HoldCounter();
+            }
+        }
+
+        /**
+         * The number of reentrant read locks held by current thread.
+         * Initialized only in constructor and readObject.
+         * Removed whenever a thread's read hold count drops to 0.
+         */
+        private transient ThreadLocalHoldCounter readHolds;
+
+        /**
+         * The hold count of the last thread to successfully acquire
+         * readLock. This saves ThreadLocal lookup in the common case
+         * where the next thread to release is the last one to
+         * acquire. This is non-volatile since it is just used
+         * as a heuristic, and would be great for threads to cache.
+         *
+         * <p>Can outlive the Thread for which it is caching the read
+         * hold count, but avoids garbage retention by not retaining a
+         * reference to the Thread.
+         *
+         * <p>Accessed via a benign data race; relies on the memory
+         * model's final field and out-of-thin-air guarantees.
+         */
+        private transient HoldCounter cachedHoldCounter;
+
+        /**
+         * firstReader is the first thread to have acquired the read lock.
+         * firstReaderHoldCount is firstReader's hold count.
+         *
+         * <p>More precisely, firstReader is the unique thread that last
+         * changed the shared count from 0 to 1, and has not released the
+         * read lock since then; null if there is no such thread.
+         *
+         * <p>Cannot cause garbage retention unless the thread terminated
+         * without relinquishing its read locks, since tryReleaseShared
+         * sets it to null.
+         *
+         * <p>Accessed via a benign data race; relies on the memory
+         * model's out-of-thin-air guarantees for references.
+         *
+         * <p>This allows tracking of read holds for uncontended read
+         * locks to be very cheap.
+         */
+        private transient Thread firstReader;
+        private transient int firstReaderHoldCount;
+
+        Sync() {
+            readHolds = new ThreadLocalHoldCounter();
+            setState(getState()); // ensures visibility of readHolds
+        }
+
+        /*
+         * Acquires and releases use the same code for fair and
+         * nonfair locks, but differ in whether/how they allow barging
+         * when queues are non-empty.
+         */
+
+        /**
+         * Returns true if the current thread, when trying to acquire
+         * the read lock, and otherwise eligible to do so, should block
+         * because of policy for overtaking other waiting threads.
+         */
+        abstract boolean readerShouldBlock();
+
+        /**
+         * Returns true if the current thread, when trying to acquire
+         * the write lock, and otherwise eligible to do so, should block
+         * because of policy for overtaking other waiting threads.
+         */
+        abstract boolean writerShouldBlock();
+
+        /*
+         * Note that tryRelease and tryAcquire can be called by
+         * Conditions. So it is possible that their arguments contain
+         * both read and write holds that are all released during a
+         * condition wait and re-established in tryAcquire.
+         */
+
+        protected final boolean tryRelease(int releases) {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            int nextc = getState() - releases;
+            boolean free = exclusiveCount(nextc) == 0;
+            if (free)
+                setExclusiveOwnerThread(null);
+            setState(nextc);
+            return free;
+        }
+
+        protected final boolean tryAcquire(int acquires) {
+            /*
+             * Walkthrough:
+             * 1. If read count nonzero or write count nonzero
+             *    and owner is a different thread, fail.
+             * 2. If count would saturate, fail. (This can only
+             *    happen if count is already nonzero.)
+             * 3. Otherwise, this thread is eligible for lock if
+             *    it is either a reentrant acquire or
+             *    queue policy allows it. If so, update state
+             *    and set owner.
+             */
+            Thread current = Thread.currentThread();
+            int c = getState();
+            int w = exclusiveCount(c);
+            if (c != 0) {
+                // (Note: if c != 0 and w == 0 then shared count != 0)
+                if (w == 0 || current != getExclusiveOwnerThread())
+                    return false;
+                if (w + exclusiveCount(acquires) > MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+                // Reentrant acquire
+                setState(c + acquires);
+                return true;
+            }
+            if (writerShouldBlock() ||
+                !compareAndSetState(c, c + acquires))
+                return false;
+            setExclusiveOwnerThread(current);
+            return true;
+        }
+
+        protected final boolean tryReleaseShared(int unused) {
+            Thread current = Thread.currentThread();
+            if (firstReader == current) {
+                // assert firstReaderHoldCount > 0;
+                if (firstReaderHoldCount == 1)
+                    firstReader = null;
+                else
+                    firstReaderHoldCount--;
+            } else {
+                HoldCounter rh = cachedHoldCounter;
+                if (rh == null || rh.tid != getThreadId(current))
+                    rh = readHolds.get();
+                int count = rh.count;
+                if (count <= 1) {
+                    readHolds.remove();
+                    if (count <= 0)
+                        throw unmatchedUnlockException();
+                }
+                --rh.count;
+            }
+            for (;;) {
+                int c = getState();
+                int nextc = c - SHARED_UNIT;
+                if (compareAndSetState(c, nextc))
+                    // Releasing the read lock has no effect on readers,
+                    // but it may allow waiting writers to proceed if
+                    // both read and write locks are now free.
+                    return nextc == 0;
+            }
+        }
+
+        private IllegalMonitorStateException unmatchedUnlockException() {
+            return new IllegalMonitorStateException(
+                "attempt to unlock read lock, not locked by current thread");
+        }
+
+        protected final int tryAcquireShared(int unused) {
+            /*
+             * Walkthrough:
+             * 1. If write lock held by another thread, fail.
+             * 2. Otherwise, this thread is eligible for
+             *    lock wrt state, so ask if it should block
+             *    because of queue policy. If not, try
+             *    to grant by CASing state and updating count.
+             *    Note that step does not check for reentrant
+             *    acquires, which is postponed to full version
+             *    to avoid having to check hold count in
+             *    the more typical non-reentrant case.
+             * 3. If step 2 fails either because thread
+             *    apparently not eligible or CAS fails or count
+             *    saturated, chain to version with full retry loop.
+             */
+            Thread current = Thread.currentThread();
+            int c = getState();
+            if (exclusiveCount(c) != 0 &&
+                getExclusiveOwnerThread() != current)
+                return -1;
+            int r = sharedCount(c);
+            if (!readerShouldBlock() &&
+                r < MAX_COUNT &&
+                compareAndSetState(c, c + SHARED_UNIT)) {
+                if (r == 0) {
+                    firstReader = current;
+                    firstReaderHoldCount = 1;
+                } else if (firstReader == current) {
+                    firstReaderHoldCount++;
+                } else {
+                    HoldCounter rh = cachedHoldCounter;
+                    if (rh == null || rh.tid != getThreadId(current))
+                        cachedHoldCounter = rh = readHolds.get();
+                    else if (rh.count == 0)
+                        readHolds.set(rh);
+                    rh.count++;
+                }
+                return 1;
+            }
+            return fullTryAcquireShared(current);
+        }
+
+        /**
+         * Full version of acquire for reads, that handles CAS misses
+         * and reentrant reads not dealt with in tryAcquireShared.
+         */
+        final int fullTryAcquireShared(Thread current) {
+            /*
+             * This code is in part redundant with that in
+             * tryAcquireShared but is simpler overall by not
+             * complicating tryAcquireShared with interactions between
+             * retries and lazily reading hold counts.
+             */
+            HoldCounter rh = null;
+            for (;;) {
+                int c = getState();
+                if (exclusiveCount(c) != 0) {
+                    if (getExclusiveOwnerThread() != current)
+                        return -1;
+                    // else we hold the exclusive lock; blocking here
+                    // would cause deadlock.
+                } else if (readerShouldBlock()) {
+                    // Make sure we're not acquiring read lock reentrantly
+                    if (firstReader == current) {
+                        // assert firstReaderHoldCount > 0;
+                    } else {
+                        if (rh == null) {
+                            rh = cachedHoldCounter;
+                            if (rh == null || rh.tid != getThreadId(current)) {
+                                rh = readHolds.get();
+                                if (rh.count == 0)
+                                    readHolds.remove();
+                            }
+                        }
+                        if (rh.count == 0)
+                            return -1;
+                    }
+                }
+                if (sharedCount(c) == MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+                if (compareAndSetState(c, c + SHARED_UNIT)) {
+                    if (sharedCount(c) == 0) {
+                        firstReader = current;
+                        firstReaderHoldCount = 1;
+                    } else if (firstReader == current) {
+                        firstReaderHoldCount++;
+                    } else {
+                        if (rh == null)
+                            rh = cachedHoldCounter;
+                        if (rh == null || rh.tid != getThreadId(current))
+                            rh = readHolds.get();
+                        else if (rh.count == 0)
+                            readHolds.set(rh);
+                        rh.count++;
+                        cachedHoldCounter = rh; // cache for release
+                    }
+                    return 1;
+                }
+            }
+        }
+
+        /**
+         * Performs tryLock for write, enabling barging in both modes.
+         * This is identical in effect to tryAcquire except for lack
+         * of calls to writerShouldBlock.
+         */
+        final boolean tryWriteLock() {
+            Thread current = Thread.currentThread();
+            int c = getState();
+            if (c != 0) {
+                int w = exclusiveCount(c);
+                if (w == 0 || current != getExclusiveOwnerThread())
+                    return false;
+                if (w == MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+            }
+            if (!compareAndSetState(c, c + 1))
+                return false;
+            setExclusiveOwnerThread(current);
+            return true;
+        }
+
+        /**
+         * Performs tryLock for read, enabling barging in both modes.
+         * This is identical in effect to tryAcquireShared except for
+         * lack of calls to readerShouldBlock.
+         */
+        final boolean tryReadLock() {
+            Thread current = Thread.currentThread();
+            for (;;) {
+                int c = getState();
+                if (exclusiveCount(c) != 0 &&
+                    getExclusiveOwnerThread() != current)
+                    return false;
+                int r = sharedCount(c);
+                if (r == MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+                if (compareAndSetState(c, c + SHARED_UNIT)) {
+                    if (r == 0) {
+                        firstReader = current;
+                        firstReaderHoldCount = 1;
+                    } else if (firstReader == current) {
+                        firstReaderHoldCount++;
+                    } else {
+                        HoldCounter rh = cachedHoldCounter;
+                        if (rh == null || rh.tid != getThreadId(current))
+                            cachedHoldCounter = rh = readHolds.get();
+                        else if (rh.count == 0)
+                            readHolds.set(rh);
+                        rh.count++;
+                    }
+                    return true;
+                }
+            }
+        }
+
+        protected final boolean isHeldExclusively() {
+            // While we must in general read state before owner,
+            // we don't need to do so to check if current thread is owner
+            return getExclusiveOwnerThread() == Thread.currentThread();
+        }
+
+        // Methods relayed to outer class
+
+        final ConditionObject newCondition() {
+            return new ConditionObject();
+        }
+
+        final Thread getOwner() {
+            // Must read state before owner to ensure memory consistency
+            return ((exclusiveCount(getState()) == 0) ?
+                    null :
+                    getExclusiveOwnerThread());
+        }
+
+        final int getReadLockCount() {
+            return sharedCount(getState());
+        }
+
+        final boolean isWriteLocked() {
+            return exclusiveCount(getState()) != 0;
+        }
+
+        final int getWriteHoldCount() {
+            return isHeldExclusively() ? exclusiveCount(getState()) : 0;
+        }
+
+        final int getReadHoldCount() {
+            if (getReadLockCount() == 0)
+                return 0;
+
+            Thread current = Thread.currentThread();
+            if (firstReader == current)
+                return firstReaderHoldCount;
+
+            HoldCounter rh = cachedHoldCounter;
+            if (rh != null && rh.tid == getThreadId(current))
+                return rh.count;
+
+            int count = readHolds.get().count;
+            if (count == 0) readHolds.remove();
+            return count;
+        }
+
+        /**
+         * Reconstitutes the instance from a stream (that is, deserializes it).
+         */
+        private void readObject(java.io.ObjectInputStream s)
+            throws java.io.IOException, ClassNotFoundException {
+            s.defaultReadObject();
+            readHolds = new ThreadLocalHoldCounter();
+            setState(0); // reset to unlocked state
+        }
+
+        final int getCount() { return getState(); }
+    }
+
+    /**
+     * Nonfair version of Sync
+     */
+    static final class NonfairSync extends Sync {
+        private static final long serialVersionUID = -8159625535654395037L;
+        final boolean writerShouldBlock() {
+            return false; // writers can always barge
+        }
+        final boolean readerShouldBlock() {
+            /* As a heuristic to avoid indefinite writer starvation,
+             * block if the thread that momentarily appears to be head
+             * of queue, if one exists, is a waiting writer.  This is
+             * only a probabilistic effect since a new reader will not
+             * block if there is a waiting writer behind other enabled
+             * readers that have not yet drained from the queue.
+             */
+            return apparentlyFirstQueuedIsExclusive();
+        }
+    }
+
+    /**
+     * Fair version of Sync
+     */
+    static final class FairSync extends Sync {
+        private static final long serialVersionUID = -2274990926593161451L;
+        final boolean writerShouldBlock() {
+            return hasQueuedPredecessors();
+        }
+        final boolean readerShouldBlock() {
+            return hasQueuedPredecessors();
+        }
+    }
+
+    /**
+     * The lock returned by method {@link ReentrantReadWriteLock#readLock}.
+     */
+    public static class ReadLock implements Lock, java.io.Serializable {
+        private static final long serialVersionUID = -5992448646407690164L;
+        private final Sync sync;
+
+        /**
+         * Constructor for use by subclasses.
+         *
+         * @param lock the outer lock object
+         * @throws NullPointerException if the lock is null
+         */
+        protected ReadLock(ReentrantReadWriteLock lock) {
+            sync = lock.sync;
+        }
+
+        /**
+         * Acquires the read lock.
+         *
+         * <p>Acquires the read lock if the write lock is not held by
+         * another thread and returns immediately.
+         *
+         * <p>If the write lock is held by another thread then
+         * the current thread becomes disabled for thread scheduling
+         * purposes and lies dormant until the read lock has been acquired.
+         */
+        public void lock() {
+            sync.acquireShared(1);
+        }
+
+        /**
+         * Acquires the read lock unless the current thread is
+         * {@linkplain Thread#interrupt interrupted}.
+         *
+         * <p>Acquires the read lock if the write lock is not held
+         * by another thread and returns immediately.
+         *
+         * <p>If the write lock is held by another thread then the
+         * current thread becomes disabled for thread scheduling
+         * purposes and lies dormant until one of two things happens:
+         *
+         * <ul>
+         *
+         * <li>The read lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread.
+         *
+         * </ul>
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method; or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the read lock,
+         *
+         * </ul>
+         *
+         * then {@link InterruptedException} is thrown and the current
+         * thread's interrupted status is cleared.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock.
+         *
+         * @throws InterruptedException if the current thread is interrupted
+         */
+        public void lockInterruptibly() throws InterruptedException {
+            sync.acquireSharedInterruptibly(1);
+        }
+
+        /**
+         * Acquires the read lock only if the write lock is not held by
+         * another thread at the time of invocation.
+         *
+         * <p>Acquires the read lock if the write lock is not held by
+         * another thread and returns immediately with the value
+         * {@code true}. Even when this lock has been set to use a
+         * fair ordering policy, a call to {@code tryLock()}
+         * <em>will</em> immediately acquire the read lock if it is
+         * available, whether or not other threads are currently
+         * waiting for the read lock.  This &quot;barging&quot; behavior
+         * can be useful in certain circumstances, even though it
+         * breaks fairness. If you want to honor the fairness setting
+         * for this lock, then use {@link #tryLock(long, TimeUnit)
+         * tryLock(0, TimeUnit.SECONDS) } which is almost equivalent
+         * (it also detects interruption).
+         *
+         * <p>If the write lock is held by another thread then
+         * this method will return immediately with the value
+         * {@code false}.
+         *
+         * @return {@code true} if the read lock was acquired
+         */
+        public boolean tryLock() {
+            return sync.tryReadLock();
+        }
+
+        /**
+         * Acquires the read lock if the write lock is not held by
+         * another thread within the given waiting time and the
+         * current thread has not been {@linkplain Thread#interrupt
+         * interrupted}.
+         *
+         * <p>Acquires the read lock if the write lock is not held by
+         * another thread and returns immediately with the value
+         * {@code true}. If this lock has been set to use a fair
+         * ordering policy then an available lock <em>will not</em> be
+         * acquired if any other threads are waiting for the
+         * lock. This is in contrast to the {@link #tryLock()}
+         * method. If you want a timed {@code tryLock} that does
+         * permit barging on a fair lock then combine the timed and
+         * un-timed forms together:
+         *
+         * <pre> {@code
+         * if (lock.tryLock() ||
+         *     lock.tryLock(timeout, unit)) {
+         *   ...
+         * }}</pre>
+         *
+         * <p>If the write lock is held by another thread then the
+         * current thread becomes disabled for thread scheduling
+         * purposes and lies dormant until one of three things happens:
+         *
+         * <ul>
+         *
+         * <li>The read lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread; or
+         *
+         * <li>The specified waiting time elapses.
+         *
+         * </ul>
+         *
+         * <p>If the read lock is acquired then the value {@code true} is
+         * returned.
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method; or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the read lock,
+         *
+         * </ul> then {@link InterruptedException} is thrown and the
+         * current thread's interrupted status is cleared.
+         *
+         * <p>If the specified waiting time elapses then the value
+         * {@code false} is returned.  If the time is less than or
+         * equal to zero, the method will not wait at all.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock, and over reporting the elapse of the waiting time.
+         *
+         * @param timeout the time to wait for the read lock
+         * @param unit the time unit of the timeout argument
+         * @return {@code true} if the read lock was acquired
+         * @throws InterruptedException if the current thread is interrupted
+         * @throws NullPointerException if the time unit is null
+         */
+        public boolean tryLock(long timeout, TimeUnit unit)
+                throws InterruptedException {
+            return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
+        }
+
+        /**
+         * Attempts to release this lock.
+         *
+         * <p>If the number of readers is now zero then the lock
+         * is made available for write lock attempts. If the current
+         * thread does not hold this lock then {@link
+         * IllegalMonitorStateException} is thrown.
+         *
+         * @throws IllegalMonitorStateException if the current thread
+         * does not hold this lock
+         */
+        public void unlock() {
+            sync.releaseShared(1);
+        }
+
+        /**
+         * Throws {@code UnsupportedOperationException} because
+         * {@code ReadLocks} do not support conditions.
+         *
+         * @throws UnsupportedOperationException always
+         */
+        public Condition newCondition() {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Returns a string identifying this lock, as well as its lock state.
+         * The state, in brackets, includes the String {@code "Read locks ="}
+         * followed by the number of held read locks.
+         *
+         * @return a string identifying this lock, as well as its lock state
+         */
+        public String toString() {
+            int r = sync.getReadLockCount();
+            return super.toString() +
+                "[Read locks = " + r + "]";
+        }
+    }
+
+    /**
+     * The lock returned by method {@link ReentrantReadWriteLock#writeLock}.
+     */
+    public static class WriteLock implements Lock, java.io.Serializable {
+        private static final long serialVersionUID = -4992448646407690164L;
+        private final Sync sync;
+
+        /**
+         * Constructor for use by subclasses.
+         *
+         * @param lock the outer lock object
+         * @throws NullPointerException if the lock is null
+         */
+        protected WriteLock(ReentrantReadWriteLock lock) {
+            sync = lock.sync;
+        }
+
+        /**
+         * Acquires the write lock.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately, setting the write lock hold count to
+         * one.
+         *
+         * <p>If the current thread already holds the write lock then the
+         * hold count is incremented by one and the method returns
+         * immediately.
+         *
+         * <p>If the lock is held by another thread then the current
+         * thread becomes disabled for thread scheduling purposes and
+         * lies dormant until the write lock has been acquired, at which
+         * time the write lock hold count is set to one.
+         */
+        public void lock() {
+            sync.acquire(1);
+        }
+
+        /**
+         * Acquires the write lock unless the current thread is
+         * {@linkplain Thread#interrupt interrupted}.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately, setting the write lock hold count to
+         * one.
+         *
+         * <p>If the current thread already holds this lock then the
+         * hold count is incremented by one and the method returns
+         * immediately.
+         *
+         * <p>If the lock is held by another thread then the current
+         * thread becomes disabled for thread scheduling purposes and
+         * lies dormant until one of two things happens:
+         *
+         * <ul>
+         *
+         * <li>The write lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread.
+         *
+         * </ul>
+         *
+         * <p>If the write lock is acquired by the current thread then the
+         * lock hold count is set to one.
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method;
+         * or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the write lock,
+         *
+         * </ul>
+         *
+         * then {@link InterruptedException} is thrown and the current
+         * thread's interrupted status is cleared.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock.
+         *
+         * @throws InterruptedException if the current thread is interrupted
+         */
+        public void lockInterruptibly() throws InterruptedException {
+            sync.acquireInterruptibly(1);
+        }
+
+        /**
+         * Acquires the write lock only if it is not held by another thread
+         * at the time of invocation.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately with the value {@code true},
+         * setting the write lock hold count to one. Even when this lock has
+         * been set to use a fair ordering policy, a call to
+         * {@code tryLock()} <em>will</em> immediately acquire the
+         * lock if it is available, whether or not other threads are
+         * currently waiting for the write lock.  This &quot;barging&quot;
+         * behavior can be useful in certain circumstances, even
+         * though it breaks fairness. If you want to honor the
+         * fairness setting for this lock, then use {@link
+         * #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) }
+         * which is almost equivalent (it also detects interruption).
+         *
+         * <p>If the current thread already holds this lock then the
+         * hold count is incremented by one and the method returns
+         * {@code true}.
+         *
+         * <p>If the lock is held by another thread then this method
+         * will return immediately with the value {@code false}.
+         *
+         * @return {@code true} if the lock was free and was acquired
+         * by the current thread, or the write lock was already held
+         * by the current thread; and {@code false} otherwise.
+         */
+        public boolean tryLock() {
+            return sync.tryWriteLock();
+        }
+
+        /**
+         * Acquires the write lock if it is not held by another thread
+         * within the given waiting time and the current thread has
+         * not been {@linkplain Thread#interrupt interrupted}.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately with the value {@code true},
+         * setting the write lock hold count to one. If this lock has been
+         * set to use a fair ordering policy then an available lock
+         * <em>will not</em> be acquired if any other threads are
+         * waiting for the write lock. This is in contrast to the {@link
+         * #tryLock()} method. If you want a timed {@code tryLock}
+         * that does permit barging on a fair lock then combine the
+         * timed and un-timed forms together:
+         *
+         * <pre> {@code
+         * if (lock.tryLock() ||
+         *     lock.tryLock(timeout, unit)) {
+         *   ...
+         * }}</pre>
+         *
+         * <p>If the current thread already holds this lock then the
+         * hold count is incremented by one and the method returns
+         * {@code true}.
+         *
+         * <p>If the lock is held by another thread then the current
+         * thread becomes disabled for thread scheduling purposes and
+         * lies dormant until one of three things happens:
+         *
+         * <ul>
+         *
+         * <li>The write lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread; or
+         *
+         * <li>The specified waiting time elapses
+         *
+         * </ul>
+         *
+         * <p>If the write lock is acquired then the value {@code true} is
+         * returned and the write lock hold count is set to one.
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method;
+         * or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the write lock,
+         *
+         * </ul>
+         *
+         * then {@link InterruptedException} is thrown and the current
+         * thread's interrupted status is cleared.
+         *
+         * <p>If the specified waiting time elapses then the value
+         * {@code false} is returned.  If the time is less than or
+         * equal to zero, the method will not wait at all.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock, and over reporting the elapse of the waiting time.
+         *
+         * @param timeout the time to wait for the write lock
+         * @param unit the time unit of the timeout argument
+         *
+         * @return {@code true} if the lock was free and was acquired
+         * by the current thread, or the write lock was already held by the
+         * current thread; and {@code false} if the waiting time
+         * elapsed before the lock could be acquired.
+         *
+         * @throws InterruptedException if the current thread is interrupted
+         * @throws NullPointerException if the time unit is null
+         */
+        public boolean tryLock(long timeout, TimeUnit unit)
+                throws InterruptedException {
+            return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+        }
+
+        /**
+         * Attempts to release this lock.
+         *
+         * <p>If the current thread is the holder of this lock then
+         * the hold count is decremented. If the hold count is now
+         * zero then the lock is released.  If the current thread is
+         * not the holder of this lock then {@link
+         * IllegalMonitorStateException} is thrown.
+         *
+         * @throws IllegalMonitorStateException if the current thread does not
+         * hold this lock
+         */
+        public void unlock() {
+            sync.release(1);
+        }
+
+        /**
+         * Returns a {@link Condition} instance for use with this
+         * {@link Lock} instance.
+         * <p>The returned {@link Condition} instance supports the same
+         * usages as do the {@link Object} monitor methods ({@link
+         * Object#wait() wait}, {@link Object#notify notify}, and {@link
+         * Object#notifyAll notifyAll}) when used with the built-in
+         * monitor lock.
+         *
+         * <ul>
+         *
+         * <li>If this write lock is not held when any {@link
+         * Condition} method is called then an {@link
+         * IllegalMonitorStateException} is thrown.  (Read locks are
+         * held independently of write locks, so are not checked or
+         * affected. However it is essentially always an error to
+         * invoke a condition waiting method when the current thread
+         * has also acquired read locks, since other threads that
+         * could unblock it will not be able to acquire the write
+         * lock.)
+         *
+         * <li>When the condition {@linkplain Condition#await() waiting}
+         * methods are called the write lock is released and, before
+         * they return, the write lock is reacquired and the lock hold
+         * count restored to what it was when the method was called.
+         *
+         * <li>If a thread is {@linkplain Thread#interrupt interrupted} while
+         * waiting then the wait will terminate, an {@link
+         * InterruptedException} will be thrown, and the thread's
+         * interrupted status will be cleared.
+         *
+         * <li>Waiting threads are signalled in FIFO order.
+         *
+         * <li>The ordering of lock reacquisition for threads returning
+         * from waiting methods is the same as for threads initially
+         * acquiring the lock, which is in the default case not specified,
+         * but for <em>fair</em> locks favors those threads that have been
+         * waiting the longest.
+         *
+         * </ul>
+         *
+         * @return the Condition object
+         */
+        public Condition newCondition() {
+            return sync.newCondition();
+        }
+
+        /**
+         * Returns a string identifying this lock, as well as its lock
+         * state.  The state, in brackets includes either the String
+         * {@code "Unlocked"} or the String {@code "Locked by"}
+         * followed by the {@linkplain Thread#getName name} of the owning thread.
+         *
+         * @return a string identifying this lock, as well as its lock state
+         */
+        public String toString() {
+            Thread o = sync.getOwner();
+            return super.toString() + ((o == null) ?
+                                       "[Unlocked]" :
+                                       "[Locked by thread " + o.getName() + "]");
+        }
+
+        /**
+         * Queries if this write lock is held by the current thread.
+         * Identical in effect to {@link
+         * ReentrantReadWriteLock#isWriteLockedByCurrentThread}.
+         *
+         * @return {@code true} if the current thread holds this lock and
+         *         {@code false} otherwise
+         * @since 1.6
+         */
+        public boolean isHeldByCurrentThread() {
+            return sync.isHeldExclusively();
+        }
+
+        /**
+         * Queries the number of holds on this write lock by the current
+         * thread.  A thread has a hold on a lock for each lock action
+         * that is not matched by an unlock action.  Identical in effect
+         * to {@link ReentrantReadWriteLock#getWriteHoldCount}.
+         *
+         * @return the number of holds on this lock by the current thread,
+         *         or zero if this lock is not held by the current thread
+         * @since 1.6
+         */
+        public int getHoldCount() {
+            return sync.getWriteHoldCount();
+        }
+    }
+
+    // Instrumentation and status
+
+    /**
+     * Returns {@code true} if this lock has fairness set true.
+     *
+     * @return {@code true} if this lock has fairness set true
+     */
+    public final boolean isFair() {
+        return sync instanceof FairSync;
+    }
+
+    /**
+     * Returns the thread that currently owns the write lock, or
+     * {@code null} if not owned. When this method is called by a
+     * thread that is not the owner, the return value reflects a
+     * best-effort approximation of current lock status. For example,
+     * the owner may be momentarily {@code null} even if there are
+     * threads trying to acquire the lock but have not yet done so.
+     * This method is designed to facilitate construction of
+     * subclasses that provide more extensive lock monitoring
+     * facilities.
+     *
+     * @return the owner, or {@code null} if not owned
+     */
+    protected Thread getOwner() {
+        return sync.getOwner();
+    }
+
+    /**
+     * Queries the number of read locks held for this lock. This
+     * method is designed for use in monitoring system state, not for
+     * synchronization control.
+     * @return the number of read locks held
+     */
+    public int getReadLockCount() {
+        return sync.getReadLockCount();
+    }
+
+    /**
+     * Queries if the write lock is held by any thread. This method is
+     * designed for use in monitoring system state, not for
+     * synchronization control.
+     *
+     * @return {@code true} if any thread holds the write lock and
+     *         {@code false} otherwise
+     */
+    public boolean isWriteLocked() {
+        return sync.isWriteLocked();
+    }
+
+    /**
+     * Queries if the write lock is held by the current thread.
+     *
+     * @return {@code true} if the current thread holds the write lock and
+     *         {@code false} otherwise
+     */
+    public boolean isWriteLockedByCurrentThread() {
+        return sync.isHeldExclusively();
+    }
+
+    /**
+     * Queries the number of reentrant write holds on this lock by the
+     * current thread.  A writer thread has a hold on a lock for
+     * each lock action that is not matched by an unlock action.
+     *
+     * @return the number of holds on the write lock by the current thread,
+     *         or zero if the write lock is not held by the current thread
+     */
+    public int getWriteHoldCount() {
+        return sync.getWriteHoldCount();
+    }
+
+    /**
+     * Queries the number of reentrant read holds on this lock by the
+     * current thread.  A reader thread has a hold on a lock for
+     * each lock action that is not matched by an unlock action.
+     *
+     * @return the number of holds on the read lock by the current thread,
+     *         or zero if the read lock is not held by the current thread
+     * @since 1.6
+     */
+    public int getReadHoldCount() {
+        return sync.getReadHoldCount();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire the write lock.  Because the actual set of threads may
+     * change dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive lock monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedWriterThreads() {
+        return sync.getExclusiveQueuedThreads();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire the read lock.  Because the actual set of threads may
+     * change dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive lock monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedReaderThreads() {
+        return sync.getSharedQueuedThreads();
+    }
+
+    /**
+     * Queries whether any threads are waiting to acquire the read or
+     * write lock. Note that because cancellations may occur at any
+     * time, a {@code true} return does not guarantee that any other
+     * thread will ever acquire a lock.  This method is designed
+     * primarily for use in monitoring of the system state.
+     *
+     * @return {@code true} if there may be other threads waiting to
+     *         acquire the lock
+     */
+    public final boolean hasQueuedThreads() {
+        return sync.hasQueuedThreads();
+    }
+
+    /**
+     * Queries whether the given thread is waiting to acquire either
+     * the read or write lock. Note that because cancellations may
+     * occur at any time, a {@code true} return does not guarantee
+     * that this thread will ever acquire a lock.  This method is
+     * designed primarily for use in monitoring of the system state.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is queued waiting for this lock
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean hasQueuedThread(Thread thread) {
+        return sync.isQueued(thread);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting to acquire
+     * either the read or write lock.  The value is only an estimate
+     * because the number of threads may change dynamically while this
+     * method traverses internal data structures.  This method is
+     * designed for use in monitoring system state, not for
+     * synchronization control.
+     *
+     * @return the estimated number of threads waiting for this lock
+     */
+    public final int getQueueLength() {
+        return sync.getQueueLength();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire either the read or write lock.  Because the actual set
+     * of threads may change dynamically while constructing this
+     * result, the returned collection is only a best-effort estimate.
+     * The elements of the returned collection are in no particular
+     * order.  This method is designed to facilitate construction of
+     * subclasses that provide more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedThreads() {
+        return sync.getQueuedThreads();
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with the write lock. Note that because timeouts and
+     * interrupts may occur at any time, a {@code true} return does
+     * not guarantee that a future {@code signal} will awaken any
+     * threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public boolean hasWaiters(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with the write lock. Note that because
+     * timeouts and interrupts may occur at any time, the estimate
+     * serves only as an upper bound on the actual number of waiters.
+     * This method is designed for use in monitoring of the system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public int getWaitQueueLength(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with the write lock.
+     * Because the actual set of threads may change dynamically while
+     * constructing this result, the returned collection is only a
+     * best-effort estimate. The elements of the returned collection
+     * are in no particular order.  This method is designed to
+     * facilitate construction of subclasses that provide more
+     * extensive condition monitoring facilities.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    protected Collection<Thread> getWaitingThreads(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a string identifying this lock, as well as its lock state.
+     * The state, in brackets, includes the String {@code "Write locks ="}
+     * followed by the number of reentrantly held write locks, and the
+     * String {@code "Read locks ="} followed by the number of held
+     * read locks.
+     *
+     * @return a string identifying this lock, as well as its lock state
+     */
+    public String toString() {
+        int c = sync.getCount();
+        int w = Sync.exclusiveCount(c);
+        int r = Sync.sharedCount(c);
+
+        return super.toString() +
+            "[Write locks = " + w + ", Read locks = " + r + "]";
+    }
+
+    /**
+     * Returns the thread id for the given thread.  We must access
+     * this directly rather than via method Thread.getId() because
+     * getId() is not final, and has been known to be overridden in
+     * ways that do not preserve unique mappings.
+     */
+    static final long getThreadId(Thread thread) {
+        return U.getLongVolatile(thread, TID);
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long TID;
+    static {
+        try {
+            TID = U.objectFieldOffset
+                (Thread.class.getDeclaredField("tid"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/locks/StampedLock.java b/java/util/concurrent/locks/StampedLock.java
new file mode 100644
index 0000000..d689599
--- /dev/null
+++ b/java/util/concurrent/locks/StampedLock.java
@@ -0,0 +1,1432 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A capability-based lock with three modes for controlling read/write
+ * access.  The state of a StampedLock consists of a version and mode.
+ * Lock acquisition methods return a stamp that represents and
+ * controls access with respect to a lock state; "try" versions of
+ * these methods may instead return the special value zero to
+ * represent failure to acquire access. Lock release and conversion
+ * methods require stamps as arguments, and fail if they do not match
+ * the state of the lock. The three modes are:
+ *
+ * <ul>
+ *
+ *  <li><b>Writing.</b> Method {@link #writeLock} possibly blocks
+ *   waiting for exclusive access, returning a stamp that can be used
+ *   in method {@link #unlockWrite} to release the lock. Untimed and
+ *   timed versions of {@code tryWriteLock} are also provided. When
+ *   the lock is held in write mode, no read locks may be obtained,
+ *   and all optimistic read validations will fail.
+ *
+ *  <li><b>Reading.</b> Method {@link #readLock} possibly blocks
+ *   waiting for non-exclusive access, returning a stamp that can be
+ *   used in method {@link #unlockRead} to release the lock. Untimed
+ *   and timed versions of {@code tryReadLock} are also provided.
+ *
+ *  <li><b>Optimistic Reading.</b> Method {@link #tryOptimisticRead}
+ *   returns a non-zero stamp only if the lock is not currently held
+ *   in write mode. Method {@link #validate} returns true if the lock
+ *   has not been acquired in write mode since obtaining a given
+ *   stamp.  This mode can be thought of as an extremely weak version
+ *   of a read-lock, that can be broken by a writer at any time.  The
+ *   use of optimistic mode for short read-only code segments often
+ *   reduces contention and improves throughput.  However, its use is
+ *   inherently fragile.  Optimistic read sections should only read
+ *   fields and hold them in local variables for later use after
+ *   validation. Fields read while in optimistic mode may be wildly
+ *   inconsistent, so usage applies only when you are familiar enough
+ *   with data representations to check consistency and/or repeatedly
+ *   invoke method {@code validate()}.  For example, such steps are
+ *   typically required when first reading an object or array
+ *   reference, and then accessing one of its fields, elements or
+ *   methods.
+ *
+ * </ul>
+ *
+ * <p>This class also supports methods that conditionally provide
+ * conversions across the three modes. For example, method {@link
+ * #tryConvertToWriteLock} attempts to "upgrade" a mode, returning
+ * a valid write stamp if (1) already in writing mode (2) in reading
+ * mode and there are no other readers or (3) in optimistic mode and
+ * the lock is available. The forms of these methods are designed to
+ * help reduce some of the code bloat that otherwise occurs in
+ * retry-based designs.
+ *
+ * <p>StampedLocks are designed for use as internal utilities in the
+ * development of thread-safe components. Their use relies on
+ * knowledge of the internal properties of the data, objects, and
+ * methods they are protecting.  They are not reentrant, so locked
+ * bodies should not call other unknown methods that may try to
+ * re-acquire locks (although you may pass a stamp to other methods
+ * that can use or convert it).  The use of read lock modes relies on
+ * the associated code sections being side-effect-free.  Unvalidated
+ * optimistic read sections cannot call methods that are not known to
+ * tolerate potential inconsistencies.  Stamps use finite
+ * representations, and are not cryptographically secure (i.e., a
+ * valid stamp may be guessable). Stamp values may recycle after (no
+ * sooner than) one year of continuous operation. A stamp held without
+ * use or validation for longer than this period may fail to validate
+ * correctly.  StampedLocks are serializable, but always deserialize
+ * into initial unlocked state, so they are not useful for remote
+ * locking.
+ *
+ * <p>The scheduling policy of StampedLock does not consistently
+ * prefer readers over writers or vice versa.  All "try" methods are
+ * best-effort and do not necessarily conform to any scheduling or
+ * fairness policy. A zero return from any "try" method for acquiring
+ * or converting locks does not carry any information about the state
+ * of the lock; a subsequent invocation may succeed.
+ *
+ * <p>Because it supports coordinated usage across multiple lock
+ * modes, this class does not directly implement the {@link Lock} or
+ * {@link ReadWriteLock} interfaces. However, a StampedLock may be
+ * viewed {@link #asReadLock()}, {@link #asWriteLock()}, or {@link
+ * #asReadWriteLock()} in applications requiring only the associated
+ * set of functionality.
+ *
+ * <p><b>Sample Usage.</b> The following illustrates some usage idioms
+ * in a class that maintains simple two-dimensional points. The sample
+ * code illustrates some try/catch conventions even though they are
+ * not strictly needed here because no exceptions can occur in their
+ * bodies.<br>
+ *
+ * <pre> {@code
+ * class Point {
+ *   private double x, y;
+ *   private final StampedLock sl = new StampedLock();
+ *
+ *   void move(double deltaX, double deltaY) { // an exclusively locked method
+ *     long stamp = sl.writeLock();
+ *     try {
+ *       x += deltaX;
+ *       y += deltaY;
+ *     } finally {
+ *       sl.unlockWrite(stamp);
+ *     }
+ *   }
+ *
+ *   double distanceFromOrigin() { // A read-only method
+ *     long stamp = sl.tryOptimisticRead();
+ *     double currentX = x, currentY = y;
+ *     if (!sl.validate(stamp)) {
+ *        stamp = sl.readLock();
+ *        try {
+ *          currentX = x;
+ *          currentY = y;
+ *        } finally {
+ *           sl.unlockRead(stamp);
+ *        }
+ *     }
+ *     return Math.sqrt(currentX * currentX + currentY * currentY);
+ *   }
+ *
+ *   void moveIfAtOrigin(double newX, double newY) { // upgrade
+ *     // Could instead start with optimistic, not read mode
+ *     long stamp = sl.readLock();
+ *     try {
+ *       while (x == 0.0 && y == 0.0) {
+ *         long ws = sl.tryConvertToWriteLock(stamp);
+ *         if (ws != 0L) {
+ *           stamp = ws;
+ *           x = newX;
+ *           y = newY;
+ *           break;
+ *         }
+ *         else {
+ *           sl.unlockRead(stamp);
+ *           stamp = sl.writeLock();
+ *         }
+ *       }
+ *     } finally {
+ *       sl.unlock(stamp);
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class StampedLock implements java.io.Serializable {
+    /*
+     * Algorithmic notes:
+     *
+     * The design employs elements of Sequence locks
+     * (as used in linux kernels; see Lameter's
+     * http://www.lameter.com/gelato2005.pdf
+     * and elsewhere; see
+     * Boehm's http://www.hpl.hp.com/techreports/2012/HPL-2012-68.html)
+     * and Ordered RW locks (see Shirako et al
+     * http://dl.acm.org/citation.cfm?id=2312015)
+     *
+     * Conceptually, the primary state of the lock includes a sequence
+     * number that is odd when write-locked and even otherwise.
+     * However, this is offset by a reader count that is non-zero when
+     * read-locked.  The read count is ignored when validating
+     * "optimistic" seqlock-reader-style stamps.  Because we must use
+     * a small finite number of bits (currently 7) for readers, a
+     * supplementary reader overflow word is used when the number of
+     * readers exceeds the count field. We do this by treating the max
+     * reader count value (RBITS) as a spinlock protecting overflow
+     * updates.
+     *
+     * Waiters use a modified form of CLH lock used in
+     * AbstractQueuedSynchronizer (see its internal documentation for
+     * a fuller account), where each node is tagged (field mode) as
+     * either a reader or writer. Sets of waiting readers are grouped
+     * (linked) under a common node (field cowait) so act as a single
+     * node with respect to most CLH mechanics.  By virtue of the
+     * queue structure, wait nodes need not actually carry sequence
+     * numbers; we know each is greater than its predecessor.  This
+     * simplifies the scheduling policy to a mainly-FIFO scheme that
+     * incorporates elements of Phase-Fair locks (see Brandenburg &
+     * Anderson, especially http://www.cs.unc.edu/~bbb/diss/).  In
+     * particular, we use the phase-fair anti-barging rule: If an
+     * incoming reader arrives while read lock is held but there is a
+     * queued writer, this incoming reader is queued.  (This rule is
+     * responsible for some of the complexity of method acquireRead,
+     * but without it, the lock becomes highly unfair.) Method release
+     * does not (and sometimes cannot) itself wake up cowaiters. This
+     * is done by the primary thread, but helped by any other threads
+     * with nothing better to do in methods acquireRead and
+     * acquireWrite.
+     *
+     * These rules apply to threads actually queued. All tryLock forms
+     * opportunistically try to acquire locks regardless of preference
+     * rules, and so may "barge" their way in.  Randomized spinning is
+     * used in the acquire methods to reduce (increasingly expensive)
+     * context switching while also avoiding sustained memory
+     * thrashing among many threads.  We limit spins to the head of
+     * queue. A thread spin-waits up to SPINS times (where each
+     * iteration decreases spin count with 50% probability) before
+     * blocking. If, upon wakening it fails to obtain lock, and is
+     * still (or becomes) the first waiting thread (which indicates
+     * that some other thread barged and obtained lock), it escalates
+     * spins (up to MAX_HEAD_SPINS) to reduce the likelihood of
+     * continually losing to barging threads.
+     *
+     * Nearly all of these mechanics are carried out in methods
+     * acquireWrite and acquireRead, that, as typical of such code,
+     * sprawl out because actions and retries rely on consistent sets
+     * of locally cached reads.
+     *
+     * As noted in Boehm's paper (above), sequence validation (mainly
+     * method validate()) requires stricter ordering rules than apply
+     * to normal volatile reads (of "state").  To force orderings of
+     * reads before a validation and the validation itself in those
+     * cases where this is not already forced, we use
+     * Unsafe.loadFence.
+     *
+     * The memory layout keeps lock state and queue pointers together
+     * (normally on the same cache line). This usually works well for
+     * read-mostly loads. In most other cases, the natural tendency of
+     * adaptive-spin CLH locks to reduce memory contention lessens
+     * motivation to further spread out contended locations, but might
+     * be subject to future improvements.
+     */
+
+    private static final long serialVersionUID = -6001602636862214147L;
+
+    /** Number of processors, for spin control */
+    private static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /** Maximum number of retries before enqueuing on acquisition */
+    private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;
+
+    /** Maximum number of retries before blocking at head on acquisition */
+    private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0;
+
+    /** Maximum number of retries before re-blocking */
+    private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0;
+
+    /** The period for yielding when waiting for overflow spinlock */
+    private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
+
+    /** The number of bits to use for reader count before overflowing */
+    private static final int LG_READERS = 7;
+
+    // Values for lock state and stamp operations
+    private static final long RUNIT = 1L;
+    private static final long WBIT  = 1L << LG_READERS;
+    private static final long RBITS = WBIT - 1L;
+    private static final long RFULL = RBITS - 1L;
+    private static final long ABITS = RBITS | WBIT;
+    private static final long SBITS = ~RBITS; // note overlap with ABITS
+
+    // Initial value for lock state; avoid failure value zero
+    private static final long ORIGIN = WBIT << 1;
+
+    // Special value from cancelled acquire methods so caller can throw IE
+    private static final long INTERRUPTED = 1L;
+
+    // Values for node status; order matters
+    private static final int WAITING   = -1;
+    private static final int CANCELLED =  1;
+
+    // Modes for nodes (int not boolean to allow arithmetic)
+    private static final int RMODE = 0;
+    private static final int WMODE = 1;
+
+    /** Wait nodes */
+    static final class WNode {
+        volatile WNode prev;
+        volatile WNode next;
+        volatile WNode cowait;    // list of linked readers
+        volatile Thread thread;   // non-null while possibly parked
+        volatile int status;      // 0, WAITING, or CANCELLED
+        final int mode;           // RMODE or WMODE
+        WNode(int m, WNode p) { mode = m; prev = p; }
+    }
+
+    /** Head of CLH queue */
+    private transient volatile WNode whead;
+    /** Tail (last) of CLH queue */
+    private transient volatile WNode wtail;
+
+    // views
+    transient ReadLockView readLockView;
+    transient WriteLockView writeLockView;
+    transient ReadWriteLockView readWriteLockView;
+
+    /** Lock sequence/state */
+    private transient volatile long state;
+    /** extra reader count when state read count saturated */
+    private transient int readerOverflow;
+
+    /**
+     * Creates a new lock, initially in unlocked state.
+     */
+    public StampedLock() {
+        state = ORIGIN;
+    }
+
+    /**
+     * Exclusively acquires the lock, blocking if necessary
+     * until available.
+     *
+     * @return a stamp that can be used to unlock or convert mode
+     */
+    public long writeLock() {
+        long s, next;  // bypass acquireWrite in fully unlocked case only
+        return ((((s = state) & ABITS) == 0L &&
+                 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
+                next : acquireWrite(false, 0L));
+    }
+
+    /**
+     * Exclusively acquires the lock if it is immediately available.
+     *
+     * @return a stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     */
+    public long tryWriteLock() {
+        long s, next;
+        return ((((s = state) & ABITS) == 0L &&
+                 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
+                next : 0L);
+    }
+
+    /**
+     * Exclusively acquires the lock if it is available within the
+     * given time and the current thread has not been interrupted.
+     * Behavior under timeout and interruption matches that specified
+     * for method {@link Lock#tryLock(long,TimeUnit)}.
+     *
+     * @param time the maximum time to wait for the lock
+     * @param unit the time unit of the {@code time} argument
+     * @return a stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long tryWriteLock(long time, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(time);
+        if (!Thread.interrupted()) {
+            long next, deadline;
+            if ((next = tryWriteLock()) != 0L)
+                return next;
+            if (nanos <= 0L)
+                return 0L;
+            if ((deadline = System.nanoTime() + nanos) == 0L)
+                deadline = 1L;
+            if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
+                return next;
+        }
+        throw new InterruptedException();
+    }
+
+    /**
+     * Exclusively acquires the lock, blocking if necessary
+     * until available or the current thread is interrupted.
+     * Behavior under interruption matches that specified
+     * for method {@link Lock#lockInterruptibly()}.
+     *
+     * @return a stamp that can be used to unlock or convert mode
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long writeLockInterruptibly() throws InterruptedException {
+        long next;
+        if (!Thread.interrupted() &&
+            (next = acquireWrite(true, 0L)) != INTERRUPTED)
+            return next;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Non-exclusively acquires the lock, blocking if necessary
+     * until available.
+     *
+     * @return a stamp that can be used to unlock or convert mode
+     */
+    public long readLock() {
+        long s = state, next;  // bypass acquireRead on common uncontended case
+        return ((whead == wtail && (s & ABITS) < RFULL &&
+                 U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
+                next : acquireRead(false, 0L));
+    }
+
+    /**
+     * Non-exclusively acquires the lock if it is immediately available.
+     *
+     * @return a stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     */
+    public long tryReadLock() {
+        for (;;) {
+            long s, m, next;
+            if ((m = (s = state) & ABITS) == WBIT)
+                return 0L;
+            else if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
+                    return next;
+            }
+            else if ((next = tryIncReaderOverflow(s)) != 0L)
+                return next;
+        }
+    }
+
+    /**
+     * Non-exclusively acquires the lock if it is available within the
+     * given time and the current thread has not been interrupted.
+     * Behavior under timeout and interruption matches that specified
+     * for method {@link Lock#tryLock(long,TimeUnit)}.
+     *
+     * @param time the maximum time to wait for the lock
+     * @param unit the time unit of the {@code time} argument
+     * @return a stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long tryReadLock(long time, TimeUnit unit)
+        throws InterruptedException {
+        long s, m, next, deadline;
+        long nanos = unit.toNanos(time);
+        if (!Thread.interrupted()) {
+            if ((m = (s = state) & ABITS) != WBIT) {
+                if (m < RFULL) {
+                    if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
+                        return next;
+                }
+                else if ((next = tryIncReaderOverflow(s)) != 0L)
+                    return next;
+            }
+            if (nanos <= 0L)
+                return 0L;
+            if ((deadline = System.nanoTime() + nanos) == 0L)
+                deadline = 1L;
+            if ((next = acquireRead(true, deadline)) != INTERRUPTED)
+                return next;
+        }
+        throw new InterruptedException();
+    }
+
+    /**
+     * Non-exclusively acquires the lock, blocking if necessary
+     * until available or the current thread is interrupted.
+     * Behavior under interruption matches that specified
+     * for method {@link Lock#lockInterruptibly()}.
+     *
+     * @return a stamp that can be used to unlock or convert mode
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long readLockInterruptibly() throws InterruptedException {
+        long next;
+        if (!Thread.interrupted() &&
+            (next = acquireRead(true, 0L)) != INTERRUPTED)
+            return next;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Returns a stamp that can later be validated, or zero
+     * if exclusively locked.
+     *
+     * @return a stamp, or zero if exclusively locked
+     */
+    public long tryOptimisticRead() {
+        long s;
+        return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
+    }
+
+    /**
+     * Returns true if the lock has not been exclusively acquired
+     * since issuance of the given stamp. Always returns false if the
+     * stamp is zero. Always returns true if the stamp represents a
+     * currently held lock. Invoking this method with a value not
+     * obtained from {@link #tryOptimisticRead} or a locking method
+     * for this lock has no defined effect or result.
+     *
+     * @param stamp a stamp
+     * @return {@code true} if the lock has not been exclusively acquired
+     * since issuance of the given stamp; else false
+     */
+    public boolean validate(long stamp) {
+        U.loadFence();
+        return (stamp & SBITS) == (state & SBITS);
+    }
+
+    /**
+     * If the lock state matches the given stamp, releases the
+     * exclusive lock.
+     *
+     * @param stamp a stamp returned by a write-lock operation
+     * @throws IllegalMonitorStateException if the stamp does
+     * not match the current state of this lock
+     */
+    public void unlockWrite(long stamp) {
+        WNode h;
+        if (state != stamp || (stamp & WBIT) == 0L)
+            throw new IllegalMonitorStateException();
+        U.putLongVolatile(this, STATE, (stamp += WBIT) == 0L ? ORIGIN : stamp);
+        if ((h = whead) != null && h.status != 0)
+            release(h);
+    }
+
+    /**
+     * If the lock state matches the given stamp, releases the
+     * non-exclusive lock.
+     *
+     * @param stamp a stamp returned by a read-lock operation
+     * @throws IllegalMonitorStateException if the stamp does
+     * not match the current state of this lock
+     */
+    public void unlockRead(long stamp) {
+        long s, m; WNode h;
+        for (;;) {
+            if (((s = state) & SBITS) != (stamp & SBITS) ||
+                (stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT)
+                throw new IllegalMonitorStateException();
+            if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
+                    if (m == RUNIT && (h = whead) != null && h.status != 0)
+                        release(h);
+                    break;
+                }
+            }
+            else if (tryDecReaderOverflow(s) != 0L)
+                break;
+        }
+    }
+
+    /**
+     * If the lock state matches the given stamp, releases the
+     * corresponding mode of the lock.
+     *
+     * @param stamp a stamp returned by a lock operation
+     * @throws IllegalMonitorStateException if the stamp does
+     * not match the current state of this lock
+     */
+    public void unlock(long stamp) {
+        long a = stamp & ABITS, m, s; WNode h;
+        while (((s = state) & SBITS) == (stamp & SBITS)) {
+            if ((m = s & ABITS) == 0L)
+                break;
+            else if (m == WBIT) {
+                if (a != m)
+                    break;
+                U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
+                if ((h = whead) != null && h.status != 0)
+                    release(h);
+                return;
+            }
+            else if (a == 0L || a >= WBIT)
+                break;
+            else if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
+                    if (m == RUNIT && (h = whead) != null && h.status != 0)
+                        release(h);
+                    return;
+                }
+            }
+            else if (tryDecReaderOverflow(s) != 0L)
+                return;
+        }
+        throw new IllegalMonitorStateException();
+    }
+
+    /**
+     * If the lock state matches the given stamp, atomically performs one of
+     * the following actions. If the stamp represents holding a write
+     * lock, returns it.  Or, if a read lock, if the write lock is
+     * available, releases the read lock and returns a write stamp.
+     * Or, if an optimistic read, returns a write stamp only if
+     * immediately available. This method returns zero in all other
+     * cases.
+     *
+     * @param stamp a stamp
+     * @return a valid write stamp, or zero on failure
+     */
+    public long tryConvertToWriteLock(long stamp) {
+        long a = stamp & ABITS, m, s, next;
+        while (((s = state) & SBITS) == (stamp & SBITS)) {
+            if ((m = s & ABITS) == 0L) {
+                if (a != 0L)
+                    break;
+                if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
+                    return next;
+            }
+            else if (m == WBIT) {
+                if (a != m)
+                    break;
+                return stamp;
+            }
+            else if (m == RUNIT && a != 0L) {
+                if (U.compareAndSwapLong(this, STATE, s,
+                                         next = s - RUNIT + WBIT))
+                    return next;
+            }
+            else
+                break;
+        }
+        return 0L;
+    }
+
+    /**
+     * If the lock state matches the given stamp, atomically performs one of
+     * the following actions. If the stamp represents holding a write
+     * lock, releases it and obtains a read lock.  Or, if a read lock,
+     * returns it. Or, if an optimistic read, acquires a read lock and
+     * returns a read stamp only if immediately available. This method
+     * returns zero in all other cases.
+     *
+     * @param stamp a stamp
+     * @return a valid read stamp, or zero on failure
+     */
+    public long tryConvertToReadLock(long stamp) {
+        long a = stamp & ABITS, m, s, next; WNode h;
+        while (((s = state) & SBITS) == (stamp & SBITS)) {
+            if ((m = s & ABITS) == 0L) {
+                if (a != 0L)
+                    break;
+                else if (m < RFULL) {
+                    if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
+                        return next;
+                }
+                else if ((next = tryIncReaderOverflow(s)) != 0L)
+                    return next;
+            }
+            else if (m == WBIT) {
+                if (a != m)
+                    break;
+                U.putLongVolatile(this, STATE, next = s + (WBIT + RUNIT));
+                if ((h = whead) != null && h.status != 0)
+                    release(h);
+                return next;
+            }
+            else if (a != 0L && a < WBIT)
+                return stamp;
+            else
+                break;
+        }
+        return 0L;
+    }
+
+    /**
+     * If the lock state matches the given stamp then, atomically, if the stamp
+     * represents holding a lock, releases it and returns an
+     * observation stamp.  Or, if an optimistic read, returns it if
+     * validated. This method returns zero in all other cases, and so
+     * may be useful as a form of "tryUnlock".
+     *
+     * @param stamp a stamp
+     * @return a valid optimistic read stamp, or zero on failure
+     */
+    public long tryConvertToOptimisticRead(long stamp) {
+        long a = stamp & ABITS, m, s, next; WNode h;
+        U.loadFence();
+        for (;;) {
+            if (((s = state) & SBITS) != (stamp & SBITS))
+                break;
+            if ((m = s & ABITS) == 0L) {
+                if (a != 0L)
+                    break;
+                return s;
+            }
+            else if (m == WBIT) {
+                if (a != m)
+                    break;
+                U.putLongVolatile(this, STATE,
+                                  next = (s += WBIT) == 0L ? ORIGIN : s);
+                if ((h = whead) != null && h.status != 0)
+                    release(h);
+                return next;
+            }
+            else if (a == 0L || a >= WBIT)
+                break;
+            else if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) {
+                    if (m == RUNIT && (h = whead) != null && h.status != 0)
+                        release(h);
+                    return next & SBITS;
+                }
+            }
+            else if ((next = tryDecReaderOverflow(s)) != 0L)
+                return next & SBITS;
+        }
+        return 0L;
+    }
+
+    /**
+     * Releases the write lock if it is held, without requiring a
+     * stamp value. This method may be useful for recovery after
+     * errors.
+     *
+     * @return {@code true} if the lock was held, else false
+     */
+    public boolean tryUnlockWrite() {
+        long s; WNode h;
+        if (((s = state) & WBIT) != 0L) {
+            U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
+            if ((h = whead) != null && h.status != 0)
+                release(h);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Releases one hold of the read lock if it is held, without
+     * requiring a stamp value. This method may be useful for recovery
+     * after errors.
+     *
+     * @return {@code true} if the read lock was held, else false
+     */
+    public boolean tryUnlockRead() {
+        long s, m; WNode h;
+        while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
+            if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
+                    if (m == RUNIT && (h = whead) != null && h.status != 0)
+                        release(h);
+                    return true;
+                }
+            }
+            else if (tryDecReaderOverflow(s) != 0L)
+                return true;
+        }
+        return false;
+    }
+
+    // status monitoring methods
+
+    /**
+     * Returns combined state-held and overflow read count for given
+     * state s.
+     */
+    private int getReadLockCount(long s) {
+        long readers;
+        if ((readers = s & RBITS) >= RFULL)
+            readers = RFULL + readerOverflow;
+        return (int) readers;
+    }
+
+    /**
+     * Returns {@code true} if the lock is currently held exclusively.
+     *
+     * @return {@code true} if the lock is currently held exclusively
+     */
+    public boolean isWriteLocked() {
+        return (state & WBIT) != 0L;
+    }
+
+    /**
+     * Returns {@code true} if the lock is currently held non-exclusively.
+     *
+     * @return {@code true} if the lock is currently held non-exclusively
+     */
+    public boolean isReadLocked() {
+        return (state & RBITS) != 0L;
+    }
+
+    /**
+     * Queries the number of read locks held for this lock. This
+     * method is designed for use in monitoring system state, not for
+     * synchronization control.
+     * @return the number of read locks held
+     */
+    public int getReadLockCount() {
+        return getReadLockCount(state);
+    }
+
+    /**
+     * Returns a string identifying this lock, as well as its lock
+     * state.  The state, in brackets, includes the String {@code
+     * "Unlocked"} or the String {@code "Write-locked"} or the String
+     * {@code "Read-locks:"} followed by the current number of
+     * read-locks held.
+     *
+     * @return a string identifying this lock, as well as its lock state
+     */
+    public String toString() {
+        long s = state;
+        return super.toString() +
+            ((s & ABITS) == 0L ? "[Unlocked]" :
+             (s & WBIT) != 0L ? "[Write-locked]" :
+             "[Read-locks:" + getReadLockCount(s) + "]");
+    }
+
+    // views
+
+    /**
+     * Returns a plain {@link Lock} view of this StampedLock in which
+     * the {@link Lock#lock} method is mapped to {@link #readLock},
+     * and similarly for other methods. The returned Lock does not
+     * support a {@link Condition}; method {@link
+     * Lock#newCondition()} throws {@code
+     * UnsupportedOperationException}.
+     *
+     * @return the lock
+     */
+    public Lock asReadLock() {
+        ReadLockView v;
+        return ((v = readLockView) != null ? v :
+                (readLockView = new ReadLockView()));
+    }
+
+    /**
+     * Returns a plain {@link Lock} view of this StampedLock in which
+     * the {@link Lock#lock} method is mapped to {@link #writeLock},
+     * and similarly for other methods. The returned Lock does not
+     * support a {@link Condition}; method {@link
+     * Lock#newCondition()} throws {@code
+     * UnsupportedOperationException}.
+     *
+     * @return the lock
+     */
+    public Lock asWriteLock() {
+        WriteLockView v;
+        return ((v = writeLockView) != null ? v :
+                (writeLockView = new WriteLockView()));
+    }
+
+    /**
+     * Returns a {@link ReadWriteLock} view of this StampedLock in
+     * which the {@link ReadWriteLock#readLock()} method is mapped to
+     * {@link #asReadLock()}, and {@link ReadWriteLock#writeLock()} to
+     * {@link #asWriteLock()}.
+     *
+     * @return the lock
+     */
+    public ReadWriteLock asReadWriteLock() {
+        ReadWriteLockView v;
+        return ((v = readWriteLockView) != null ? v :
+                (readWriteLockView = new ReadWriteLockView()));
+    }
+
+    // view classes
+
+    final class ReadLockView implements Lock {
+        public void lock() { readLock(); }
+        public void lockInterruptibly() throws InterruptedException {
+            readLockInterruptibly();
+        }
+        public boolean tryLock() { return tryReadLock() != 0L; }
+        public boolean tryLock(long time, TimeUnit unit)
+            throws InterruptedException {
+            return tryReadLock(time, unit) != 0L;
+        }
+        public void unlock() { unstampedUnlockRead(); }
+        public Condition newCondition() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    final class WriteLockView implements Lock {
+        public void lock() { writeLock(); }
+        public void lockInterruptibly() throws InterruptedException {
+            writeLockInterruptibly();
+        }
+        public boolean tryLock() { return tryWriteLock() != 0L; }
+        public boolean tryLock(long time, TimeUnit unit)
+            throws InterruptedException {
+            return tryWriteLock(time, unit) != 0L;
+        }
+        public void unlock() { unstampedUnlockWrite(); }
+        public Condition newCondition() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    final class ReadWriteLockView implements ReadWriteLock {
+        public Lock readLock() { return asReadLock(); }
+        public Lock writeLock() { return asWriteLock(); }
+    }
+
+    // Unlock methods without stamp argument checks for view classes.
+    // Needed because view-class lock methods throw away stamps.
+
+    final void unstampedUnlockWrite() {
+        WNode h; long s;
+        if (((s = state) & WBIT) == 0L)
+            throw new IllegalMonitorStateException();
+        U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
+        if ((h = whead) != null && h.status != 0)
+            release(h);
+    }
+
+    final void unstampedUnlockRead() {
+        for (;;) {
+            long s, m; WNode h;
+            if ((m = (s = state) & ABITS) == 0L || m >= WBIT)
+                throw new IllegalMonitorStateException();
+            else if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
+                    if (m == RUNIT && (h = whead) != null && h.status != 0)
+                        release(h);
+                    break;
+                }
+            }
+            else if (tryDecReaderOverflow(s) != 0L)
+                break;
+        }
+    }
+
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        U.putLongVolatile(this, STATE, ORIGIN); // reset to unlocked state
+    }
+
+    // internals
+
+    /**
+     * Tries to increment readerOverflow by first setting state
+     * access bits value to RBITS, indicating hold of spinlock,
+     * then updating, then releasing.
+     *
+     * @param s a reader overflow stamp: (s & ABITS) >= RFULL
+     * @return new stamp on success, else zero
+     */
+    private long tryIncReaderOverflow(long s) {
+        // assert (s & ABITS) >= RFULL;
+        if ((s & ABITS) == RFULL) {
+            if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
+                ++readerOverflow;
+                U.putLongVolatile(this, STATE, s);
+                return s;
+            }
+        }
+        else if ((LockSupport.nextSecondarySeed() &
+                  OVERFLOW_YIELD_RATE) == 0)
+            Thread.yield();
+        return 0L;
+    }
+
+    /**
+     * Tries to decrement readerOverflow.
+     *
+     * @param s a reader overflow stamp: (s & ABITS) >= RFULL
+     * @return new stamp on success, else zero
+     */
+    private long tryDecReaderOverflow(long s) {
+        // assert (s & ABITS) >= RFULL;
+        if ((s & ABITS) == RFULL) {
+            if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
+                int r; long next;
+                if ((r = readerOverflow) > 0) {
+                    readerOverflow = r - 1;
+                    next = s;
+                }
+                else
+                    next = s - RUNIT;
+                U.putLongVolatile(this, STATE, next);
+                return next;
+            }
+        }
+        else if ((LockSupport.nextSecondarySeed() &
+                  OVERFLOW_YIELD_RATE) == 0)
+            Thread.yield();
+        return 0L;
+    }
+
+    /**
+     * Wakes up the successor of h (normally whead). This is normally
+     * just h.next, but may require traversal from wtail if next
+     * pointers are lagging. This may fail to wake up an acquiring
+     * thread when one or more have been cancelled, but the cancel
+     * methods themselves provide extra safeguards to ensure liveness.
+     */
+    private void release(WNode h) {
+        if (h != null) {
+            WNode q; Thread w;
+            U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
+            if ((q = h.next) == null || q.status == CANCELLED) {
+                for (WNode t = wtail; t != null && t != h; t = t.prev)
+                    if (t.status <= 0)
+                        q = t;
+            }
+            if (q != null && (w = q.thread) != null)
+                U.unpark(w);
+        }
+    }
+
+    /**
+     * See above for explanation.
+     *
+     * @param interruptible true if should check interrupts and if so
+     * return INTERRUPTED
+     * @param deadline if nonzero, the System.nanoTime value to timeout
+     * at (and return zero)
+     * @return next state, or INTERRUPTED
+     */
+    private long acquireWrite(boolean interruptible, long deadline) {
+        WNode node = null, p;
+        for (int spins = -1;;) { // spin while enqueuing
+            long m, s, ns;
+            if ((m = (s = state) & ABITS) == 0L) {
+                if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
+                    return ns;
+            }
+            else if (spins < 0)
+                spins = (m == WBIT && wtail == whead) ? SPINS : 0;
+            else if (spins > 0) {
+                if (LockSupport.nextSecondarySeed() >= 0)
+                    --spins;
+            }
+            else if ((p = wtail) == null) { // initialize queue
+                WNode hd = new WNode(WMODE, null);
+                if (U.compareAndSwapObject(this, WHEAD, null, hd))
+                    wtail = hd;
+            }
+            else if (node == null)
+                node = new WNode(WMODE, p);
+            else if (node.prev != p)
+                node.prev = p;
+            else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
+                p.next = node;
+                break;
+            }
+        }
+
+        boolean wasInterrupted = false;
+        for (int spins = -1;;) {
+            WNode h, np, pp; int ps;
+            if ((h = whead) == p) {
+                if (spins < 0)
+                    spins = HEAD_SPINS;
+                else if (spins < MAX_HEAD_SPINS)
+                    spins <<= 1;
+                for (int k = spins;;) { // spin at head
+                    long s, ns;
+                    if (((s = state) & ABITS) == 0L) {
+                        if (U.compareAndSwapLong(this, STATE, s,
+                                                 ns = s + WBIT)) {
+                            whead = node;
+                            node.prev = null;
+                            if (wasInterrupted)
+                                Thread.currentThread().interrupt();
+                            return ns;
+                        }
+                    }
+                    else if (LockSupport.nextSecondarySeed() >= 0 &&
+                             --k <= 0)
+                        break;
+                }
+            }
+            else if (h != null) { // help release stale waiters
+                WNode c; Thread w;
+                while ((c = h.cowait) != null) {
+                    if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
+                        (w = c.thread) != null)
+                        U.unpark(w);
+                }
+            }
+            if (whead == h) {
+                if ((np = node.prev) != p) {
+                    if (np != null)
+                        (p = np).next = node;   // stale
+                }
+                else if ((ps = p.status) == 0)
+                    U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
+                else if (ps == CANCELLED) {
+                    if ((pp = p.prev) != null) {
+                        node.prev = pp;
+                        pp.next = node;
+                    }
+                }
+                else {
+                    long time; // 0 argument to park means no timeout
+                    if (deadline == 0L)
+                        time = 0L;
+                    else if ((time = deadline - System.nanoTime()) <= 0L)
+                        return cancelWaiter(node, node, false);
+                    Thread wt = Thread.currentThread();
+                    U.putObject(wt, PARKBLOCKER, this);
+                    node.thread = wt;
+                    if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
+                        whead == h && node.prev == p)
+                        U.park(false, time);  // emulate LockSupport.park
+                    node.thread = null;
+                    U.putObject(wt, PARKBLOCKER, null);
+                    if (Thread.interrupted()) {
+                        if (interruptible)
+                            return cancelWaiter(node, node, true);
+                        wasInterrupted = true;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * See above for explanation.
+     *
+     * @param interruptible true if should check interrupts and if so
+     * return INTERRUPTED
+     * @param deadline if nonzero, the System.nanoTime value to timeout
+     * at (and return zero)
+     * @return next state, or INTERRUPTED
+     */
+    private long acquireRead(boolean interruptible, long deadline) {
+        boolean wasInterrupted = false;
+        WNode node = null, p;
+        for (int spins = -1;;) {
+            WNode h;
+            if ((h = whead) == (p = wtail)) {
+                for (long m, s, ns;;) {
+                    if ((m = (s = state) & ABITS) < RFULL ?
+                        U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
+                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
+                        if (wasInterrupted)
+                            Thread.currentThread().interrupt();
+                        return ns;
+                    }
+                    else if (m >= WBIT) {
+                        if (spins > 0) {
+                            if (LockSupport.nextSecondarySeed() >= 0)
+                                --spins;
+                        }
+                        else {
+                            if (spins == 0) {
+                                WNode nh = whead, np = wtail;
+                                if ((nh == h && np == p) || (h = nh) != (p = np))
+                                    break;
+                            }
+                            spins = SPINS;
+                        }
+                    }
+                }
+            }
+            if (p == null) { // initialize queue
+                WNode hd = new WNode(WMODE, null);
+                if (U.compareAndSwapObject(this, WHEAD, null, hd))
+                    wtail = hd;
+            }
+            else if (node == null)
+                node = new WNode(RMODE, p);
+            else if (h == p || p.mode != RMODE) {
+                if (node.prev != p)
+                    node.prev = p;
+                else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
+                    p.next = node;
+                    break;
+                }
+            }
+            else if (!U.compareAndSwapObject(p, WCOWAIT,
+                                             node.cowait = p.cowait, node))
+                node.cowait = null;
+            else {
+                for (;;) {
+                    WNode pp, c; Thread w;
+                    if ((h = whead) != null && (c = h.cowait) != null &&
+                        U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
+                        (w = c.thread) != null) // help release
+                        U.unpark(w);
+                    if (h == (pp = p.prev) || h == p || pp == null) {
+                        long m, s, ns;
+                        do {
+                            if ((m = (s = state) & ABITS) < RFULL ?
+                                U.compareAndSwapLong(this, STATE, s,
+                                                     ns = s + RUNIT) :
+                                (m < WBIT &&
+                                 (ns = tryIncReaderOverflow(s)) != 0L)) {
+                                if (wasInterrupted)
+                                    Thread.currentThread().interrupt();
+                                return ns;
+                            }
+                        } while (m < WBIT);
+                    }
+                    if (whead == h && p.prev == pp) {
+                        long time;
+                        if (pp == null || h == p || p.status > 0) {
+                            node = null; // throw away
+                            break;
+                        }
+                        if (deadline == 0L)
+                            time = 0L;
+                        else if ((time = deadline - System.nanoTime()) <= 0L) {
+                            if (wasInterrupted)
+                                Thread.currentThread().interrupt();
+                            return cancelWaiter(node, p, false);
+                        }
+                        Thread wt = Thread.currentThread();
+                        U.putObject(wt, PARKBLOCKER, this);
+                        node.thread = wt;
+                        if ((h != pp || (state & ABITS) == WBIT) &&
+                            whead == h && p.prev == pp)
+                            U.park(false, time);
+                        node.thread = null;
+                        U.putObject(wt, PARKBLOCKER, null);
+                        if (Thread.interrupted()) {
+                            if (interruptible)
+                                return cancelWaiter(node, p, true);
+                            wasInterrupted = true;
+                        }
+                    }
+                }
+            }
+        }
+
+        for (int spins = -1;;) {
+            WNode h, np, pp; int ps;
+            if ((h = whead) == p) {
+                if (spins < 0)
+                    spins = HEAD_SPINS;
+                else if (spins < MAX_HEAD_SPINS)
+                    spins <<= 1;
+                for (int k = spins;;) { // spin at head
+                    long m, s, ns;
+                    if ((m = (s = state) & ABITS) < RFULL ?
+                        U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
+                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
+                        WNode c; Thread w;
+                        whead = node;
+                        node.prev = null;
+                        while ((c = node.cowait) != null) {
+                            if (U.compareAndSwapObject(node, WCOWAIT,
+                                                       c, c.cowait) &&
+                                (w = c.thread) != null)
+                                U.unpark(w);
+                        }
+                        if (wasInterrupted)
+                            Thread.currentThread().interrupt();
+                        return ns;
+                    }
+                    else if (m >= WBIT &&
+                             LockSupport.nextSecondarySeed() >= 0 && --k <= 0)
+                        break;
+                }
+            }
+            else if (h != null) {
+                WNode c; Thread w;
+                while ((c = h.cowait) != null) {
+                    if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
+                        (w = c.thread) != null)
+                        U.unpark(w);
+                }
+            }
+            if (whead == h) {
+                if ((np = node.prev) != p) {
+                    if (np != null)
+                        (p = np).next = node;   // stale
+                }
+                else if ((ps = p.status) == 0)
+                    U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
+                else if (ps == CANCELLED) {
+                    if ((pp = p.prev) != null) {
+                        node.prev = pp;
+                        pp.next = node;
+                    }
+                }
+                else {
+                    long time;
+                    if (deadline == 0L)
+                        time = 0L;
+                    else if ((time = deadline - System.nanoTime()) <= 0L)
+                        return cancelWaiter(node, node, false);
+                    Thread wt = Thread.currentThread();
+                    U.putObject(wt, PARKBLOCKER, this);
+                    node.thread = wt;
+                    if (p.status < 0 &&
+                        (p != h || (state & ABITS) == WBIT) &&
+                        whead == h && node.prev == p)
+                        U.park(false, time);
+                    node.thread = null;
+                    U.putObject(wt, PARKBLOCKER, null);
+                    if (Thread.interrupted()) {
+                        if (interruptible)
+                            return cancelWaiter(node, node, true);
+                        wasInterrupted = true;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * If node non-null, forces cancel status and unsplices it from
+     * queue if possible and wakes up any cowaiters (of the node, or
+     * group, as applicable), and in any case helps release current
+     * first waiter if lock is free. (Calling with null arguments
+     * serves as a conditional form of release, which is not currently
+     * needed but may be needed under possible future cancellation
+     * policies). This is a variant of cancellation methods in
+     * AbstractQueuedSynchronizer (see its detailed explanation in AQS
+     * internal documentation).
+     *
+     * @param node if nonnull, the waiter
+     * @param group either node or the group node is cowaiting with
+     * @param interrupted if already interrupted
+     * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
+     */
+    private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
+        if (node != null && group != null) {
+            Thread w;
+            node.status = CANCELLED;
+            // unsplice cancelled nodes from group
+            for (WNode p = group, q; (q = p.cowait) != null;) {
+                if (q.status == CANCELLED) {
+                    U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
+                    p = group; // restart
+                }
+                else
+                    p = q;
+            }
+            if (group == node) {
+                for (WNode r = group.cowait; r != null; r = r.cowait) {
+                    if ((w = r.thread) != null)
+                        U.unpark(w);       // wake up uncancelled co-waiters
+                }
+                for (WNode pred = node.prev; pred != null; ) { // unsplice
+                    WNode succ, pp;        // find valid successor
+                    while ((succ = node.next) == null ||
+                           succ.status == CANCELLED) {
+                        WNode q = null;    // find successor the slow way
+                        for (WNode t = wtail; t != null && t != node; t = t.prev)
+                            if (t.status != CANCELLED)
+                                q = t;     // don't link if succ cancelled
+                        if (succ == q ||   // ensure accurate successor
+                            U.compareAndSwapObject(node, WNEXT,
+                                                   succ, succ = q)) {
+                            if (succ == null && node == wtail)
+                                U.compareAndSwapObject(this, WTAIL, node, pred);
+                            break;
+                        }
+                    }
+                    if (pred.next == node) // unsplice pred link
+                        U.compareAndSwapObject(pred, WNEXT, node, succ);
+                    if (succ != null && (w = succ.thread) != null) {
+                        succ.thread = null;
+                        U.unpark(w);       // wake up succ to observe new pred
+                    }
+                    if (pred.status != CANCELLED || (pp = pred.prev) == null)
+                        break;
+                    node.prev = pp;        // repeat if new pred wrong/cancelled
+                    U.compareAndSwapObject(pp, WNEXT, pred, succ);
+                    pred = pp;
+                }
+            }
+        }
+        WNode h; // Possibly release first waiter
+        while ((h = whead) != null) {
+            long s; WNode q; // similar to release() but check eligibility
+            if ((q = h.next) == null || q.status == CANCELLED) {
+                for (WNode t = wtail; t != null && t != h; t = t.prev)
+                    if (t.status <= 0)
+                        q = t;
+            }
+            if (h == whead) {
+                if (q != null && h.status == 0 &&
+                    ((s = state) & ABITS) != WBIT && // waiter is eligible
+                    (s == 0L || q.mode == RMODE))
+                    release(h);
+                break;
+            }
+        }
+        return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
+    private static final long WHEAD;
+    private static final long WTAIL;
+    private static final long WNEXT;
+    private static final long WSTATUS;
+    private static final long WCOWAIT;
+    private static final long PARKBLOCKER;
+
+    static {
+        try {
+            STATE = U.objectFieldOffset
+                (StampedLock.class.getDeclaredField("state"));
+            WHEAD = U.objectFieldOffset
+                (StampedLock.class.getDeclaredField("whead"));
+            WTAIL = U.objectFieldOffset
+                (StampedLock.class.getDeclaredField("wtail"));
+
+            WSTATUS = U.objectFieldOffset
+                (WNode.class.getDeclaredField("status"));
+            WNEXT = U.objectFieldOffset
+                (WNode.class.getDeclaredField("next"));
+            WCOWAIT = U.objectFieldOffset
+                (WNode.class.getDeclaredField("cowait"));
+
+            PARKBLOCKER = U.objectFieldOffset
+                (Thread.class.getDeclaredField("parkBlocker"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/locks/package-info.java b/java/util/concurrent/locks/package-info.java
new file mode 100644
index 0000000..97dfcc9
--- /dev/null
+++ b/java/util/concurrent/locks/package-info.java
@@ -0,0 +1,79 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Interfaces and classes providing a framework for locking and waiting
+ * for conditions that is distinct from built-in synchronization and
+ * monitors.  The framework permits much greater flexibility in the use of
+ * locks and conditions, at the expense of more awkward syntax.
+ *
+ * <p>The {@link java.util.concurrent.locks.Lock} interface supports
+ * locking disciplines that differ in semantics (reentrant, fair, etc),
+ * and that can be used in non-block-structured contexts including
+ * hand-over-hand and lock reordering algorithms.  The main implementation
+ * is {@link java.util.concurrent.locks.ReentrantLock}.
+ *
+ * <p>The {@link java.util.concurrent.locks.ReadWriteLock} interface
+ * similarly defines locks that may be shared among readers but are
+ * exclusive to writers.  Only a single implementation, {@link
+ * java.util.concurrent.locks.ReentrantReadWriteLock}, is provided, since
+ * it covers most standard usage contexts.  But programmers may create
+ * their own implementations to cover nonstandard requirements.
+ *
+ * <p>The {@link java.util.concurrent.locks.Condition} interface
+ * describes condition variables that may be associated with Locks.
+ * These are similar in usage to the implicit monitors accessed using
+ * {@code Object.wait}, but offer extended capabilities.
+ * In particular, multiple {@code Condition} objects may be associated
+ * with a single {@code Lock}.  To avoid compatibility issues, the
+ * names of {@code Condition} methods are different from the
+ * corresponding {@code Object} versions.
+ *
+ * <p>The {@link java.util.concurrent.locks.AbstractQueuedSynchronizer}
+ * class serves as a useful superclass for defining locks and other
+ * synchronizers that rely on queuing blocked threads.  The {@link
+ * java.util.concurrent.locks.AbstractQueuedLongSynchronizer} class
+ * provides the same functionality but extends support to 64 bits of
+ * synchronization state.  Both extend class {@link
+ * java.util.concurrent.locks.AbstractOwnableSynchronizer}, a simple
+ * class that helps record the thread currently holding exclusive
+ * synchronization.  The {@link java.util.concurrent.locks.LockSupport}
+ * class provides lower-level blocking and unblocking support that is
+ * useful for those developers implementing their own customized lock
+ * classes.
+ *
+ * @since 1.5
+ */
+package java.util.concurrent.locks;
diff --git a/java/util/concurrent/package-info.java b/java/util/concurrent/package-info.java
new file mode 100644
index 0000000..387068d
--- /dev/null
+++ b/java/util/concurrent/package-info.java
@@ -0,0 +1,308 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Utility classes commonly useful in concurrent programming.  This
+ * package includes a few small standardized extensible frameworks, as
+ * well as some classes that provide useful functionality and are
+ * otherwise tedious or difficult to implement.  Here are brief
+ * descriptions of the main components.  See also the
+ * {@link java.util.concurrent.locks} and
+ * {@link java.util.concurrent.atomic} packages.
+ *
+ * <h2>Executors</h2>
+ *
+ * <b>Interfaces.</b>
+ *
+ * {@link java.util.concurrent.Executor} is a simple standardized
+ * interface for defining custom thread-like subsystems, including
+ * thread pools, asynchronous I/O, and lightweight task frameworks.
+ * Depending on which concrete Executor class is being used, tasks may
+ * execute in a newly created thread, an existing task-execution thread,
+ * or the thread calling {@link java.util.concurrent.Executor#execute
+ * execute}, and may execute sequentially or concurrently.
+ *
+ * {@link java.util.concurrent.ExecutorService} provides a more
+ * complete asynchronous task execution framework.  An
+ * ExecutorService manages queuing and scheduling of tasks,
+ * and allows controlled shutdown.
+ *
+ * The {@link java.util.concurrent.ScheduledExecutorService}
+ * subinterface and associated interfaces add support for
+ * delayed and periodic task execution.  ExecutorServices
+ * provide methods arranging asynchronous execution of any
+ * function expressed as {@link java.util.concurrent.Callable},
+ * the result-bearing analog of {@link java.lang.Runnable}.
+ *
+ * A {@link java.util.concurrent.Future} returns the results of
+ * a function, allows determination of whether execution has
+ * completed, and provides a means to cancel execution.
+ *
+ * A {@link java.util.concurrent.RunnableFuture} is a {@code Future}
+ * that possesses a {@code run} method that upon execution,
+ * sets its results.
+ *
+ * <p>
+ *
+ * <b>Implementations.</b>
+ *
+ * Classes {@link java.util.concurrent.ThreadPoolExecutor} and
+ * {@link java.util.concurrent.ScheduledThreadPoolExecutor}
+ * provide tunable, flexible thread pools.
+ *
+ * The {@link java.util.concurrent.Executors} class provides
+ * factory methods for the most common kinds and configurations
+ * of Executors, as well as a few utility methods for using
+ * them.  Other utilities based on {@code Executors} include the
+ * concrete class {@link java.util.concurrent.FutureTask}
+ * providing a common extensible implementation of Futures, and
+ * {@link java.util.concurrent.ExecutorCompletionService}, that
+ * assists in coordinating the processing of groups of
+ * asynchronous tasks.
+ *
+ * <p>Class {@link java.util.concurrent.ForkJoinPool} provides an
+ * Executor primarily designed for processing instances of {@link
+ * java.util.concurrent.ForkJoinTask} and its subclasses.  These
+ * classes employ a work-stealing scheduler that attains high
+ * throughput for tasks conforming to restrictions that often hold in
+ * computation-intensive parallel processing.
+ *
+ * <h2>Queues</h2>
+ *
+ * The {@link java.util.concurrent.ConcurrentLinkedQueue} class
+ * supplies an efficient scalable thread-safe non-blocking FIFO queue.
+ * The {@link java.util.concurrent.ConcurrentLinkedDeque} class is
+ * similar, but additionally supports the {@link java.util.Deque}
+ * interface.
+ *
+ * <p>Five implementations in {@code java.util.concurrent} support
+ * the extended {@link java.util.concurrent.BlockingQueue}
+ * interface, that defines blocking versions of put and take:
+ * {@link java.util.concurrent.LinkedBlockingQueue},
+ * {@link java.util.concurrent.ArrayBlockingQueue},
+ * {@link java.util.concurrent.SynchronousQueue},
+ * {@link java.util.concurrent.PriorityBlockingQueue}, and
+ * {@link java.util.concurrent.DelayQueue}.
+ * The different classes cover the most common usage contexts
+ * for producer-consumer, messaging, parallel tasking, and
+ * related concurrent designs.
+ *
+ * <p>Extended interface {@link java.util.concurrent.TransferQueue},
+ * and implementation {@link java.util.concurrent.LinkedTransferQueue}
+ * introduce a synchronous {@code transfer} method (along with related
+ * features) in which a producer may optionally block awaiting its
+ * consumer.
+ *
+ * <p>The {@link java.util.concurrent.BlockingDeque} interface
+ * extends {@code BlockingQueue} to support both FIFO and LIFO
+ * (stack-based) operations.
+ * Class {@link java.util.concurrent.LinkedBlockingDeque}
+ * provides an implementation.
+ *
+ * <h2>Timing</h2>
+ *
+ * The {@link java.util.concurrent.TimeUnit} class provides
+ * multiple granularities (including nanoseconds) for
+ * specifying and controlling time-out based operations.  Most
+ * classes in the package contain operations based on time-outs
+ * in addition to indefinite waits.  In all cases that
+ * time-outs are used, the time-out specifies the minimum time
+ * that the method should wait before indicating that it
+ * timed-out.  Implementations make a &quot;best effort&quot;
+ * to detect time-outs as soon as possible after they occur.
+ * However, an indefinite amount of time may elapse between a
+ * time-out being detected and a thread actually executing
+ * again after that time-out.  All methods that accept timeout
+ * parameters treat values less than or equal to zero to mean
+ * not to wait at all.  To wait "forever", you can use a value
+ * of {@code Long.MAX_VALUE}.
+ *
+ * <h2>Synchronizers</h2>
+ *
+ * Five classes aid common special-purpose synchronization idioms.
+ * <ul>
+ *
+ * <li>{@link java.util.concurrent.Semaphore} is a classic concurrency tool.
+ *
+ * <li>{@link java.util.concurrent.CountDownLatch} is a very simple yet
+ * very common utility for blocking until a given number of signals,
+ * events, or conditions hold.
+ *
+ * <li>A {@link java.util.concurrent.CyclicBarrier} is a resettable
+ * multiway synchronization point useful in some styles of parallel
+ * programming.
+ *
+ * <li>A {@link java.util.concurrent.Phaser} provides
+ * a more flexible form of barrier that may be used to control phased
+ * computation among multiple threads.
+ *
+ * <li>An {@link java.util.concurrent.Exchanger} allows two threads to
+ * exchange objects at a rendezvous point, and is useful in several
+ * pipeline designs.
+ *
+ * </ul>
+ *
+ * <h2>Concurrent Collections</h2>
+ *
+ * Besides Queues, this package supplies Collection implementations
+ * designed for use in multithreaded contexts:
+ * {@link java.util.concurrent.ConcurrentHashMap},
+ * {@link java.util.concurrent.ConcurrentSkipListMap},
+ * {@link java.util.concurrent.ConcurrentSkipListSet},
+ * {@link java.util.concurrent.CopyOnWriteArrayList}, and
+ * {@link java.util.concurrent.CopyOnWriteArraySet}.
+ * When many threads are expected to access a given collection, a
+ * {@code ConcurrentHashMap} is normally preferable to a synchronized
+ * {@code HashMap}, and a {@code ConcurrentSkipListMap} is normally
+ * preferable to a synchronized {@code TreeMap}.
+ * A {@code CopyOnWriteArrayList} is preferable to a synchronized
+ * {@code ArrayList} when the expected number of reads and traversals
+ * greatly outnumber the number of updates to a list.
+ *
+ * <p>The "Concurrent" prefix used with some classes in this package
+ * is a shorthand indicating several differences from similar
+ * "synchronized" classes.  For example {@code java.util.Hashtable} and
+ * {@code Collections.synchronizedMap(new HashMap())} are
+ * synchronized.  But {@link
+ * java.util.concurrent.ConcurrentHashMap} is "concurrent".  A
+ * concurrent collection is thread-safe, but not governed by a
+ * single exclusion lock.  In the particular case of
+ * ConcurrentHashMap, it safely permits any number of
+ * concurrent reads as well as a tunable number of concurrent
+ * writes.  "Synchronized" classes can be useful when you need
+ * to prevent all access to a collection via a single lock, at
+ * the expense of poorer scalability.  In other cases in which
+ * multiple threads are expected to access a common collection,
+ * "concurrent" versions are normally preferable.  And
+ * unsynchronized collections are preferable when either
+ * collections are unshared, or are accessible only when
+ * holding other locks.
+ *
+ * <p id="Weakly">Most concurrent Collection implementations
+ * (including most Queues) also differ from the usual {@code java.util}
+ * conventions in that their {@linkplain java.util.Iterator Iterators}
+ * and {@linkplain java.util.Spliterator Spliterators} provide
+ * <em>weakly consistent</em> rather than fast-fail traversal:
+ * <ul>
+ * <li>they may proceed concurrently with other operations
+ * <li>they will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}
+ * <li>they are guaranteed to traverse elements as they existed upon
+ * construction exactly once, and may (but are not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ * </ul>
+ *
+ * <h2 id="MemoryVisibility">Memory Consistency Properties</h2>
+ *
+ * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.5">
+ * Chapter 17 of
+ * <cite>The Java&trade; Language Specification</cite></a> defines the
+ * <i>happens-before</i> relation on memory operations such as reads and
+ * writes of shared variables.  The results of a write by one thread are
+ * guaranteed to be visible to a read by another thread only if the write
+ * operation <i>happens-before</i> the read operation.  The
+ * {@code synchronized} and {@code volatile} constructs, as well as the
+ * {@code Thread.start()} and {@code Thread.join()} methods, can form
+ * <i>happens-before</i> relationships.  In particular:
+ *
+ * <ul>
+ *   <li>Each action in a thread <i>happens-before</i> every action in that
+ *   thread that comes later in the program's order.
+ *
+ *   <li>An unlock ({@code synchronized} block or method exit) of a
+ *   monitor <i>happens-before</i> every subsequent lock ({@code synchronized}
+ *   block or method entry) of that same monitor.  And because
+ *   the <i>happens-before</i> relation is transitive, all actions
+ *   of a thread prior to unlocking <i>happen-before</i> all actions
+ *   subsequent to any thread locking that monitor.
+ *
+ *   <li>A write to a {@code volatile} field <i>happens-before</i> every
+ *   subsequent read of that same field.  Writes and reads of
+ *   {@code volatile} fields have similar memory consistency effects
+ *   as entering and exiting monitors, but do <em>not</em> entail
+ *   mutual exclusion locking.
+ *
+ *   <li>A call to {@code start} on a thread <i>happens-before</i> any
+ *   action in the started thread.
+ *
+ *   <li>All actions in a thread <i>happen-before</i> any other thread
+ *   successfully returns from a {@code join} on that thread.
+ *
+ * </ul>
+ *
+ *
+ * The methods of all classes in {@code java.util.concurrent} and its
+ * subpackages extend these guarantees to higher-level
+ * synchronization.  In particular:
+ *
+ * <ul>
+ *
+ *   <li>Actions in a thread prior to placing an object into any concurrent
+ *   collection <i>happen-before</i> actions subsequent to the access or
+ *   removal of that element from the collection in another thread.
+ *
+ *   <li>Actions in a thread prior to the submission of a {@code Runnable}
+ *   to an {@code Executor} <i>happen-before</i> its execution begins.
+ *   Similarly for {@code Callables} submitted to an {@code ExecutorService}.
+ *
+ *   <li>Actions taken by the asynchronous computation represented by a
+ *   {@code Future} <i>happen-before</i> actions subsequent to the
+ *   retrieval of the result via {@code Future.get()} in another thread.
+ *
+ *   <li>Actions prior to "releasing" synchronizer methods such as
+ *   {@code Lock.unlock}, {@code Semaphore.release}, and
+ *   {@code CountDownLatch.countDown} <i>happen-before</i> actions
+ *   subsequent to a successful "acquiring" method such as
+ *   {@code Lock.lock}, {@code Semaphore.acquire},
+ *   {@code Condition.await}, and {@code CountDownLatch.await} on the
+ *   same synchronizer object in another thread.
+ *
+ *   <li>For each pair of threads that successfully exchange objects via
+ *   an {@code Exchanger}, actions prior to the {@code exchange()}
+ *   in each thread <i>happen-before</i> those subsequent to the
+ *   corresponding {@code exchange()} in another thread.
+ *
+ *   <li>Actions prior to calling {@code CyclicBarrier.await} and
+ *   {@code Phaser.awaitAdvance} (as well as its variants)
+ *   <i>happen-before</i> actions performed by the barrier action, and
+ *   actions performed by the barrier action <i>happen-before</i> actions
+ *   subsequent to a successful return from the corresponding {@code await}
+ *   in other threads.
+ *
+ * </ul>
+ *
+ * @since 1.5
+ */
+package java.util.concurrent;
diff --git a/java/util/function/BiConsumer.java b/java/util/function/BiConsumer.java
new file mode 100644
index 0000000..61690e6
--- /dev/null
+++ b/java/util/function/BiConsumer.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts two input arguments and returns no
+ * result.  This is the two-arity specialization of {@link Consumer}.
+ * Unlike most other functional interfaces, {@code BiConsumer} is expected
+ * to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the operation
+ * @param <U> the type of the second argument to the operation
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BiConsumer<T, U> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param u the second input argument
+     */
+    void accept(T t, U u);
+
+    /**
+     * Returns a composed {@code BiConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code BiConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
+        Objects.requireNonNull(after);
+
+        return (l, r) -> {
+            accept(l, r);
+            after.accept(l, r);
+        };
+    }
+}
diff --git a/java/util/function/BiFunction.java b/java/util/function/BiFunction.java
new file mode 100644
index 0000000..ef75901
--- /dev/null
+++ b/java/util/function/BiFunction.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a function that accepts two arguments and produces a result.
+ * This is the two-arity specialization of {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BiFunction<T, U, R> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    R apply(T t, U u);
+
+    /**
+     * Returns a composed function that first applies this function to
+     * its input, and then applies the {@code after} function to the result.
+     * If evaluation of either function throws an exception, it is relayed to
+     * the caller of the composed function.
+     *
+     * @param <V> the type of output of the {@code after} function, and of the
+     *           composed function
+     * @param after the function to apply after this function is applied
+     * @return a composed function that first applies this function and then
+     * applies the {@code after} function
+     * @throws NullPointerException if after is null
+     */
+    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
+        Objects.requireNonNull(after);
+        return (T t, U u) -> after.apply(apply(t, u));
+    }
+}
diff --git a/java/util/function/BiPredicate.java b/java/util/function/BiPredicate.java
new file mode 100644
index 0000000..a0f19b8
--- /dev/null
+++ b/java/util/function/BiPredicate.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of two arguments.  This is
+ * the two-arity specialization of {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the predicate
+ * @param <U> the type of the second argument the predicate
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BiPredicate<T, U> {
+
+    /**
+     * Evaluates this predicate on the given arguments.
+     *
+     * @param t the first input argument
+     * @param u the second input argument
+     * @return {@code true} if the input arguments match the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(T t, U u);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> other) {
+        Objects.requireNonNull(other);
+        return (T t, U u) -> test(t, u) && other.test(t, u);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default BiPredicate<T, U> negate() {
+        return (T t, U u) -> !test(t, u);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> other) {
+        Objects.requireNonNull(other);
+        return (T t, U u) -> test(t, u) || other.test(t, u);
+    }
+}
diff --git a/java/util/function/BinaryOperator.java b/java/util/function/BinaryOperator.java
new file mode 100644
index 0000000..a015058
--- /dev/null
+++ b/java/util/function/BinaryOperator.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+import java.util.Comparator;
+
+/**
+ * Represents an operation upon two operands of the same type, producing a result
+ * of the same type as the operands.  This is a specialization of
+ * {@link BiFunction} for the case where the operands and the result are all of
+ * the same type.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object, Object)}.
+ *
+ * @param <T> the type of the operands and result of the operator
+ *
+ * @see BiFunction
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BinaryOperator<T> extends BiFunction<T,T,T> {
+    /**
+     * Returns a {@link BinaryOperator} which returns the lesser of two elements
+     * according to the specified {@code Comparator}.
+     *
+     * @param <T> the type of the input arguments of the comparator
+     * @param comparator a {@code Comparator} for comparing the two values
+     * @return a {@code BinaryOperator} which returns the lesser of its operands,
+     *         according to the supplied {@code Comparator}
+     * @throws NullPointerException if the argument is null
+     */
+    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
+        Objects.requireNonNull(comparator);
+        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
+    }
+
+    /**
+     * Returns a {@link BinaryOperator} which returns the greater of two elements
+     * according to the specified {@code Comparator}.
+     *
+     * @param <T> the type of the input arguments of the comparator
+     * @param comparator a {@code Comparator} for comparing the two values
+     * @return a {@code BinaryOperator} which returns the greater of its operands,
+     *         according to the supplied {@code Comparator}
+     * @throws NullPointerException if the argument is null
+     */
+    public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
+        Objects.requireNonNull(comparator);
+        return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
+    }
+}
diff --git a/java/util/function/BooleanSupplier.java b/java/util/function/BooleanSupplier.java
new file mode 100644
index 0000000..2faff30
--- /dev/null
+++ b/java/util/function/BooleanSupplier.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+
+/**
+ * Represents a supplier of {@code boolean}-valued results.  This is the
+ * {@code boolean}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a new or distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsBoolean()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BooleanSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    boolean getAsBoolean();
+}
diff --git a/java/util/function/Consumer.java b/java/util/function/Consumer.java
new file mode 100644
index 0000000..a2481fe
--- /dev/null
+++ b/java/util/function/Consumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single input argument and returns no
+ * result. Unlike most other functional interfaces, {@code Consumer} is expected
+ * to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object)}.
+ *
+ * @param <T> the type of the input to the operation
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Consumer<T> {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param t the input argument
+     */
+    void accept(T t);
+
+    /**
+     * Returns a composed {@code Consumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code Consumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default Consumer<T> andThen(Consumer<? super T> after) {
+        Objects.requireNonNull(after);
+        return (T t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/java/util/function/DoubleBinaryOperator.java b/java/util/function/DoubleBinaryOperator.java
new file mode 100644
index 0000000..839433d
--- /dev/null
+++ b/java/util/function/DoubleBinaryOperator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation upon two {@code double}-valued operands and producing a
+ * {@code double}-valued result.   This is the primitive type specialization of
+ * {@link BinaryOperator} for {@code double}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(double, double)}.
+ *
+ * @see BinaryOperator
+ * @see DoubleUnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleBinaryOperator {
+    /**
+     * Applies this operator to the given operands.
+     *
+     * @param left the first operand
+     * @param right the second operand
+     * @return the operator result
+     */
+    double applyAsDouble(double left, double right);
+}
diff --git a/java/util/function/DoubleConsumer.java b/java/util/function/DoubleConsumer.java
new file mode 100644
index 0000000..046360c
--- /dev/null
+++ b/java/util/function/DoubleConsumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single {@code double}-valued argument and
+ * returns no result.  This is the primitive type specialization of
+ * {@link Consumer} for {@code double}.  Unlike most other functional interfaces,
+ * {@code DoubleConsumer} is expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(double)}.
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleConsumer {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param value the input argument
+     */
+    void accept(double value);
+
+    /**
+     * Returns a composed {@code DoubleConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code DoubleConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default DoubleConsumer andThen(DoubleConsumer after) {
+        Objects.requireNonNull(after);
+        return (double t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/java/util/function/DoubleFunction.java b/java/util/function/DoubleFunction.java
new file mode 100644
index 0000000..a8bb57d
--- /dev/null
+++ b/java/util/function/DoubleFunction.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a double-valued argument and produces a
+ * result.  This is the {@code double}-consuming primitive specialization for
+ * {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(double)}.
+ *
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleFunction<R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    R apply(double value);
+}
diff --git a/java/util/function/DoublePredicate.java b/java/util/function/DoublePredicate.java
new file mode 100644
index 0000000..1df1762
--- /dev/null
+++ b/java/util/function/DoublePredicate.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one {@code double}-valued
+ * argument. This is the {@code double}-consuming primitive type specialization
+ * of {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(double)}.
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoublePredicate {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param value the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(double value);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default DoublePredicate and(DoublePredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) && other.test(value);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default DoublePredicate negate() {
+        return (value) -> !test(value);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default DoublePredicate or(DoublePredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) || other.test(value);
+    }
+}
diff --git a/java/util/function/DoubleSupplier.java b/java/util/function/DoubleSupplier.java
new file mode 100644
index 0000000..5169011
--- /dev/null
+++ b/java/util/function/DoubleSupplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of {@code double}-valued results.  This is the
+ * {@code double}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsDouble()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    double getAsDouble();
+}
diff --git a/java/util/function/DoubleToIntFunction.java b/java/util/function/DoubleToIntFunction.java
new file mode 100644
index 0000000..a23f033
--- /dev/null
+++ b/java/util/function/DoubleToIntFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a double-valued argument and produces an
+ * int-valued result.  This is the {@code double}-to-{@code int} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(double)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleToIntFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    int applyAsInt(double value);
+}
diff --git a/java/util/function/DoubleToLongFunction.java b/java/util/function/DoubleToLongFunction.java
new file mode 100644
index 0000000..436369c
--- /dev/null
+++ b/java/util/function/DoubleToLongFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a double-valued argument and produces a
+ * long-valued result.  This is the {@code double}-to-{@code long} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(double)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleToLongFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    long applyAsLong(double value);
+}
diff --git a/java/util/function/DoubleUnaryOperator.java b/java/util/function/DoubleUnaryOperator.java
new file mode 100644
index 0000000..2f134c9
--- /dev/null
+++ b/java/util/function/DoubleUnaryOperator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation on a single {@code double}-valued operand that produces
+ * a {@code double}-valued result.  This is the primitive type specialization of
+ * {@link UnaryOperator} for {@code double}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(double)}.
+ *
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleUnaryOperator {
+
+    /**
+     * Applies this operator to the given operand.
+     *
+     * @param operand the operand
+     * @return the operator result
+     */
+    double applyAsDouble(double operand);
+
+    /**
+     * Returns a composed operator that first applies the {@code before}
+     * operator to its input, and then applies this operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param before the operator to apply before this operator is applied
+     * @return a composed operator that first applies the {@code before}
+     * operator and then applies this operator
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(DoubleUnaryOperator)
+     */
+    default DoubleUnaryOperator compose(DoubleUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (double v) -> applyAsDouble(before.applyAsDouble(v));
+    }
+
+    /**
+     * Returns a composed operator that first applies this operator to
+     * its input, and then applies the {@code after} operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param after the operator to apply after this operator is applied
+     * @return a composed operator that first applies this operator and then
+     * applies the {@code after} operator
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(DoubleUnaryOperator)
+     */
+    default DoubleUnaryOperator andThen(DoubleUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (double t) -> after.applyAsDouble(applyAsDouble(t));
+    }
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @return a unary operator that always returns its input argument
+     */
+    static DoubleUnaryOperator identity() {
+        return t -> t;
+    }
+}
diff --git a/java/util/function/Function.java b/java/util/function/Function.java
new file mode 100644
index 0000000..7bcbfd0
--- /dev/null
+++ b/java/util/function/Function.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a function that accepts one argument and produces a result.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ * @param <R> the type of the result of the function
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Function<T, R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param t the function argument
+     * @return the function result
+     */
+    R apply(T t);
+
+    /**
+     * Returns a composed function that first applies the {@code before}
+     * function to its input, and then applies this function to the result.
+     * If evaluation of either function throws an exception, it is relayed to
+     * the caller of the composed function.
+     *
+     * @param <V> the type of input to the {@code before} function, and to the
+     *           composed function
+     * @param before the function to apply before this function is applied
+     * @return a composed function that first applies the {@code before}
+     * function and then applies this function
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(Function)
+     */
+    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
+        Objects.requireNonNull(before);
+        return (V v) -> apply(before.apply(v));
+    }
+
+    /**
+     * Returns a composed function that first applies this function to
+     * its input, and then applies the {@code after} function to the result.
+     * If evaluation of either function throws an exception, it is relayed to
+     * the caller of the composed function.
+     *
+     * @param <V> the type of output of the {@code after} function, and of the
+     *           composed function
+     * @param after the function to apply after this function is applied
+     * @return a composed function that first applies this function and then
+     * applies the {@code after} function
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(Function)
+     */
+    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
+        Objects.requireNonNull(after);
+        return (T t) -> after.apply(apply(t));
+    }
+
+    /**
+     * Returns a function that always returns its input argument.
+     *
+     * @param <T> the type of the input and output objects to the function
+     * @return a function that always returns its input argument
+     */
+    static <T> Function<T, T> identity() {
+        return t -> t;
+    }
+}
diff --git a/java/util/function/IntBinaryOperator.java b/java/util/function/IntBinaryOperator.java
new file mode 100644
index 0000000..21bb946
--- /dev/null
+++ b/java/util/function/IntBinaryOperator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation upon two {@code int}-valued operands and producing an
+ * {@code int}-valued result.   This is the primitive type specialization of
+ * {@link BinaryOperator} for {@code int}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(int, int)}.
+ *
+ * @see BinaryOperator
+ * @see IntUnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntBinaryOperator {
+
+    /**
+     * Applies this operator to the given operands.
+     *
+     * @param left the first operand
+     * @param right the second operand
+     * @return the operator result
+     */
+    int applyAsInt(int left, int right);
+}
diff --git a/java/util/function/IntConsumer.java b/java/util/function/IntConsumer.java
new file mode 100644
index 0000000..d8daf73
--- /dev/null
+++ b/java/util/function/IntConsumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single {@code int}-valued argument and
+ * returns no result.  This is the primitive type specialization of
+ * {@link Consumer} for {@code int}.  Unlike most other functional interfaces,
+ * {@code IntConsumer} is expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(int)}.
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntConsumer {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param value the input argument
+     */
+    void accept(int value);
+
+    /**
+     * Returns a composed {@code IntConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code IntConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default IntConsumer andThen(IntConsumer after) {
+        Objects.requireNonNull(after);
+        return (int t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/java/util/function/IntFunction.java b/java/util/function/IntFunction.java
new file mode 100644
index 0000000..de10df4
--- /dev/null
+++ b/java/util/function/IntFunction.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts an int-valued argument and produces a
+ * result.  This is the {@code int}-consuming primitive specialization for
+ * {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(int)}.
+ *
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntFunction<R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    R apply(int value);
+}
diff --git a/java/util/function/IntPredicate.java b/java/util/function/IntPredicate.java
new file mode 100644
index 0000000..5a9bd46
--- /dev/null
+++ b/java/util/function/IntPredicate.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one {@code int}-valued
+ * argument. This is the {@code int}-consuming primitive type specialization of
+ * {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(int)}.
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntPredicate {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param value the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(int value);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default IntPredicate and(IntPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) && other.test(value);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default IntPredicate negate() {
+        return (value) -> !test(value);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default IntPredicate or(IntPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) || other.test(value);
+    }
+}
diff --git a/java/util/function/IntSupplier.java b/java/util/function/IntSupplier.java
new file mode 100644
index 0000000..89489c5
--- /dev/null
+++ b/java/util/function/IntSupplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of {@code int}-valued results.  This is the
+ * {@code int}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsInt()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    int getAsInt();
+}
diff --git a/java/util/function/IntToDoubleFunction.java b/java/util/function/IntToDoubleFunction.java
new file mode 100644
index 0000000..5012154
--- /dev/null
+++ b/java/util/function/IntToDoubleFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts an int-valued argument and produces a
+ * double-valued result.  This is the {@code int}-to-{@code double} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(int)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntToDoubleFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    double applyAsDouble(int value);
+}
diff --git a/java/util/function/IntToLongFunction.java b/java/util/function/IntToLongFunction.java
new file mode 100644
index 0000000..6c52faa
--- /dev/null
+++ b/java/util/function/IntToLongFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts an int-valued argument and produces a
+ * long-valued result.  This is the {@code int}-to-{@code long} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(int)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntToLongFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    long applyAsLong(int value);
+}
diff --git a/java/util/function/IntUnaryOperator.java b/java/util/function/IntUnaryOperator.java
new file mode 100644
index 0000000..300fc14
--- /dev/null
+++ b/java/util/function/IntUnaryOperator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation on a single {@code int}-valued operand that produces
+ * an {@code int}-valued result.  This is the primitive type specialization of
+ * {@link UnaryOperator} for {@code int}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(int)}.
+ *
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntUnaryOperator {
+
+    /**
+     * Applies this operator to the given operand.
+     *
+     * @param operand the operand
+     * @return the operator result
+     */
+    int applyAsInt(int operand);
+
+    /**
+     * Returns a composed operator that first applies the {@code before}
+     * operator to its input, and then applies this operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param before the operator to apply before this operator is applied
+     * @return a composed operator that first applies the {@code before}
+     * operator and then applies this operator
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(IntUnaryOperator)
+     */
+    default IntUnaryOperator compose(IntUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (int v) -> applyAsInt(before.applyAsInt(v));
+    }
+
+    /**
+     * Returns a composed operator that first applies this operator to
+     * its input, and then applies the {@code after} operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param after the operator to apply after this operator is applied
+     * @return a composed operator that first applies this operator and then
+     * applies the {@code after} operator
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(IntUnaryOperator)
+     */
+    default IntUnaryOperator andThen(IntUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (int t) -> after.applyAsInt(applyAsInt(t));
+    }
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @return a unary operator that always returns its input argument
+     */
+    static IntUnaryOperator identity() {
+        return t -> t;
+    }
+}
diff --git a/java/util/function/LongBinaryOperator.java b/java/util/function/LongBinaryOperator.java
new file mode 100644
index 0000000..287481e
--- /dev/null
+++ b/java/util/function/LongBinaryOperator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation upon two {@code long}-valued operands and producing a
+ * {@code long}-valued result.   This is the primitive type specialization of
+ * {@link BinaryOperator} for {@code long}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(long, long)}.
+ *
+ * @see BinaryOperator
+ * @see LongUnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongBinaryOperator {
+
+    /**
+     * Applies this operator to the given operands.
+     *
+     * @param left the first operand
+     * @param right the second operand
+     * @return the operator result
+     */
+    long applyAsLong(long left, long right);
+}
diff --git a/java/util/function/LongConsumer.java b/java/util/function/LongConsumer.java
new file mode 100644
index 0000000..b59d030
--- /dev/null
+++ b/java/util/function/LongConsumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single {@code long}-valued argument and
+ * returns no result.  This is the primitive type specialization of
+ * {@link Consumer} for {@code long}.  Unlike most other functional interfaces,
+ * {@code LongConsumer} is expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(long)}.
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongConsumer {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param value the input argument
+     */
+    void accept(long value);
+
+    /**
+     * Returns a composed {@code LongConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code LongConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default LongConsumer andThen(LongConsumer after) {
+        Objects.requireNonNull(after);
+        return (long t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/java/util/function/LongFunction.java b/java/util/function/LongFunction.java
new file mode 100644
index 0000000..2030c04
--- /dev/null
+++ b/java/util/function/LongFunction.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a long-valued argument and produces a
+ * result.  This is the {@code long}-consuming primitive specialization for
+ * {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(long)}.
+ *
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongFunction<R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    R apply(long value);
+}
diff --git a/java/util/function/LongPredicate.java b/java/util/function/LongPredicate.java
new file mode 100644
index 0000000..5afdd41
--- /dev/null
+++ b/java/util/function/LongPredicate.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one {@code long}-valued
+ * argument. This is the {@code long}-consuming primitive type specialization of
+ * {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(long)}.
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongPredicate {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param value the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(long value);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default LongPredicate and(LongPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) && other.test(value);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default LongPredicate negate() {
+        return (value) -> !test(value);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default LongPredicate or(LongPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) || other.test(value);
+    }
+}
diff --git a/java/util/function/LongSupplier.java b/java/util/function/LongSupplier.java
new file mode 100644
index 0000000..513d906
--- /dev/null
+++ b/java/util/function/LongSupplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of {@code long}-valued results.  This is the
+ * {@code long}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsLong()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    long getAsLong();
+}
diff --git a/java/util/function/LongToDoubleFunction.java b/java/util/function/LongToDoubleFunction.java
new file mode 100644
index 0000000..9d0831f
--- /dev/null
+++ b/java/util/function/LongToDoubleFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a long-valued argument and produces a
+ * double-valued result.  This is the {@code long}-to-{@code double} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(long)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongToDoubleFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    double applyAsDouble(long value);
+}
diff --git a/java/util/function/LongToIntFunction.java b/java/util/function/LongToIntFunction.java
new file mode 100644
index 0000000..d1d6c34
--- /dev/null
+++ b/java/util/function/LongToIntFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a long-valued argument and produces an
+ * int-valued result.  This is the {@code long}-to-{@code int} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(long)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongToIntFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    int applyAsInt(long value);
+}
diff --git a/java/util/function/LongUnaryOperator.java b/java/util/function/LongUnaryOperator.java
new file mode 100644
index 0000000..e2bbddd
--- /dev/null
+++ b/java/util/function/LongUnaryOperator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation on a single {@code long}-valued operand that produces
+ * a {@code long}-valued result.  This is the primitive type specialization of
+ * {@link UnaryOperator} for {@code long}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(long)}.
+ *
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongUnaryOperator {
+
+    /**
+     * Applies this operator to the given operand.
+     *
+     * @param operand the operand
+     * @return the operator result
+     */
+    long applyAsLong(long operand);
+
+    /**
+     * Returns a composed operator that first applies the {@code before}
+     * operator to its input, and then applies this operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param before the operator to apply before this operator is applied
+     * @return a composed operator that first applies the {@code before}
+     * operator and then applies this operator
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(LongUnaryOperator)
+     */
+    default LongUnaryOperator compose(LongUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (long v) -> applyAsLong(before.applyAsLong(v));
+    }
+
+    /**
+     * Returns a composed operator that first applies this operator to
+     * its input, and then applies the {@code after} operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param after the operator to apply after this operator is applied
+     * @return a composed operator that first applies this operator and then
+     * applies the {@code after} operator
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(LongUnaryOperator)
+     */
+    default LongUnaryOperator andThen(LongUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (long t) -> after.applyAsLong(applyAsLong(t));
+    }
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @return a unary operator that always returns its input argument
+     */
+    static LongUnaryOperator identity() {
+        return t -> t;
+    }
+}
diff --git a/java/util/function/ObjDoubleConsumer.java b/java/util/function/ObjDoubleConsumer.java
new file mode 100644
index 0000000..d551fc7
--- /dev/null
+++ b/java/util/function/ObjDoubleConsumer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation that accepts an object-valued and a
+ * {@code double}-valued argument, and returns no result.  This is the
+ * {@code (reference, double)} specialization of {@link BiConsumer}.
+ * Unlike most other functional interfaces, {@code ObjDoubleConsumer} is
+ * expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, double)}.
+ *
+ * @param <T> the type of the object argument to the operation
+ *
+ * @see BiConsumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ObjDoubleConsumer<T> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param value the second input argument
+     */
+    void accept(T t, double value);
+}
diff --git a/java/util/function/ObjIntConsumer.java b/java/util/function/ObjIntConsumer.java
new file mode 100644
index 0000000..2eb32d6
--- /dev/null
+++ b/java/util/function/ObjIntConsumer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation that accepts an object-valued and a
+ * {@code int}-valued argument, and returns no result.  This is the
+ * {@code (reference, int)} specialization of {@link BiConsumer}.
+ * Unlike most other functional interfaces, {@code ObjIntConsumer} is
+ * expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, int)}.
+ *
+ * @param <T> the type of the object argument to the operation
+ *
+ * @see BiConsumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ObjIntConsumer<T> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param value the second input argument
+     */
+    void accept(T t, int value);
+}
diff --git a/java/util/function/ObjLongConsumer.java b/java/util/function/ObjLongConsumer.java
new file mode 100644
index 0000000..f40eea2
--- /dev/null
+++ b/java/util/function/ObjLongConsumer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation that accepts an object-valued and a
+ * {@code long}-valued argument, and returns no result.  This is the
+ * {@code (reference, long)} specialization of {@link BiConsumer}.
+ * Unlike most other functional interfaces, {@code ObjLongConsumer} is
+ * expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, long)}.
+ *
+ * @param <T> the type of the object argument to the operation
+ *
+ * @see BiConsumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ObjLongConsumer<T> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param value the second input argument
+     */
+    void accept(T t, long value);
+}
diff --git a/java/util/function/Predicate.java b/java/util/function/Predicate.java
new file mode 100644
index 0000000..e2f448b
--- /dev/null
+++ b/java/util/function/Predicate.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one argument.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(Object)}.
+ *
+ * @param <T> the type of the input to the predicate
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Predicate<T> {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param t the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(T t);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default Predicate<T> and(Predicate<? super T> other) {
+        Objects.requireNonNull(other);
+        return (t) -> test(t) && other.test(t);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default Predicate<T> negate() {
+        return (t) -> !test(t);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default Predicate<T> or(Predicate<? super T> other) {
+        Objects.requireNonNull(other);
+        return (t) -> test(t) || other.test(t);
+    }
+
+    /**
+     * Returns a predicate that tests if two arguments are equal according
+     * to {@link Objects#equals(Object, Object)}.
+     *
+     * @param <T> the type of arguments to the predicate
+     * @param targetRef the object reference with which to compare for equality,
+     *               which may be {@code null}
+     * @return a predicate that tests if two arguments are equal according
+     * to {@link Objects#equals(Object, Object)}
+     */
+    static <T> Predicate<T> isEqual(Object targetRef) {
+        return (null == targetRef)
+                ? Objects::isNull
+                : object -> targetRef.equals(object);
+    }
+}
diff --git a/java/util/function/Supplier.java b/java/util/function/Supplier.java
new file mode 100644
index 0000000..b87777e
--- /dev/null
+++ b/java/util/function/Supplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of results.
+ *
+ * <p>There is no requirement that a new or distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #get()}.
+ *
+ * @param <T> the type of results supplied by this supplier
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Supplier<T> {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    T get();
+}
diff --git a/java/util/function/ToDoubleBiFunction.java b/java/util/function/ToDoubleBiFunction.java
new file mode 100644
index 0000000..d0efcee
--- /dev/null
+++ b/java/util/function/ToDoubleBiFunction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts two arguments and produces a double-valued
+ * result.  This is the {@code double}-producing primitive specialization for
+ * {@link BiFunction}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ *
+ * @see BiFunction
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToDoubleBiFunction<T, U> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    double applyAsDouble(T t, U u);
+}
diff --git a/java/util/function/ToDoubleFunction.java b/java/util/function/ToDoubleFunction.java
new file mode 100644
index 0000000..29bf988
--- /dev/null
+++ b/java/util/function/ToDoubleFunction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that produces a double-valued result.  This is the
+ * {@code double}-producing primitive specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToDoubleFunction<T> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    double applyAsDouble(T value);
+}
diff --git a/java/util/function/ToIntBiFunction.java b/java/util/function/ToIntBiFunction.java
new file mode 100644
index 0000000..0e28d26
--- /dev/null
+++ b/java/util/function/ToIntBiFunction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts two arguments and produces an int-valued
+ * result.  This is the {@code int}-producing primitive specialization for
+ * {@link BiFunction}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ *
+ * @see BiFunction
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToIntBiFunction<T, U> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    int applyAsInt(T t, U u);
+}
diff --git a/java/util/function/ToIntFunction.java b/java/util/function/ToIntFunction.java
new file mode 100644
index 0000000..5768242
--- /dev/null
+++ b/java/util/function/ToIntFunction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that produces an int-valued result.  This is the
+ * {@code int}-producing primitive specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToIntFunction<T> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    int applyAsInt(T value);
+}
diff --git a/java/util/function/ToLongBiFunction.java b/java/util/function/ToLongBiFunction.java
new file mode 100644
index 0000000..8b5ed7e
--- /dev/null
+++ b/java/util/function/ToLongBiFunction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts two arguments and produces a long-valued
+ * result.  This is the {@code long}-producing primitive specialization for
+ * {@link BiFunction}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ *
+ * @see BiFunction
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToLongBiFunction<T, U> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    long applyAsLong(T t, U u);
+}
diff --git a/java/util/function/ToLongFunction.java b/java/util/function/ToLongFunction.java
new file mode 100644
index 0000000..eefb617
--- /dev/null
+++ b/java/util/function/ToLongFunction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that produces a long-valued result.  This is the
+ * {@code long}-producing primitive specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToLongFunction<T> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    long applyAsLong(T value);
+}
diff --git a/java/util/function/UnaryOperator.java b/java/util/function/UnaryOperator.java
new file mode 100644
index 0000000..c4aa749
--- /dev/null
+++ b/java/util/function/UnaryOperator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation on a single operand that produces a result of the
+ * same type as its operand.  This is a specialization of {@code Function} for
+ * the case where the operand and result are of the same type.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object)}.
+ *
+ * @param <T> the type of the operand and result of the operator
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface UnaryOperator<T> extends Function<T, T> {
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @param <T> the type of the input and output of the operator
+     * @return a unary operator that always returns its input argument
+     */
+    static <T> UnaryOperator<T> identity() {
+        return t -> t;
+    }
+}
diff --git a/java/util/function/package-info.java b/java/util/function/package-info.java
new file mode 100644
index 0000000..31a1c46
--- /dev/null
+++ b/java/util/function/package-info.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * <em>Functional interfaces</em> provide target types for lambda expressions
+ * and method references.  Each functional interface has a single abstract
+ * method, called the <em>functional method</em> for that functional interface,
+ * to which the lambda expression's parameter and return types are matched or
+ * adapted.  Functional interfaces can provide a target type in multiple
+ * contexts, such as assignment context, method invocation, or cast context:
+ *
+ * <pre>{@code
+ *     // Assignment context
+ *     Predicate<String> p = String::isEmpty;
+ *
+ *     // Method invocation context
+ *     stream.filter(e -> e.getSize() > 10)...
+ *
+ *     // Cast context
+ *     stream.map((ToIntFunction) e -> e.getSize())...
+ * }</pre>
+ *
+ * <p>The interfaces in this package are general purpose functional interfaces
+ * used by the JDK, and are available to be used by user code as well.  While
+ * they do not identify a complete set of function shapes to which lambda
+ * expressions might be adapted, they provide enough to cover common
+ * requirements. Other functional interfaces provided for specific purposes,
+ * such as {@link java.io.FileFilter}, are defined in the packages where they
+ * are used.
+ *
+ * <p>The interfaces in this package are annotated with
+ * {@link java.lang.FunctionalInterface}. This annotation is not a requirement
+ * for the compiler to recognize an interface as a functional interface, but
+ * merely an aid to capture design intent and enlist the help of the compiler in
+ * identifying accidental violations of design intent.
+ *
+ * <p>Functional interfaces often represent abstract concepts like functions,
+ * actions, or predicates.  In documenting functional interfaces, or referring
+ * to variables typed as functional interfaces, it is common to refer directly
+ * to those abstract concepts, for example using "this function" instead of
+ * "the function represented by this object".  When an API method is said to
+ * accept or return a functional interface in this manner, such as "applies the
+ * provided function to...", this is understood to mean a <i>non-null</i>
+ * reference to an object implementing the appropriate functional interface,
+ * unless potential nullity is explicitly specified.
+ *
+ * <p>The functional interfaces in this package follow an extensible naming
+ * convention, as follows:
+ *
+ * <ul>
+ *     <li>There are several basic function shapes, including
+ *     {@link java.util.function.Function} (unary function from {@code T} to {@code R}),
+ *     {@link java.util.function.Consumer} (unary function from {@code T} to {@code void}),
+ *     {@link java.util.function.Predicate} (unary function from {@code T} to {@code boolean}),
+ *     and {@link java.util.function.Supplier} (nilary function to {@code R}).
+ *     </li>
+ *
+ *     <li>Function shapes have a natural arity based on how they are most
+ *     commonly used.  The basic shapes can be modified by an arity prefix to
+ *     indicate a different arity, such as
+ *     {@link java.util.function.BiFunction} (binary function from {@code T} and
+ *     {@code U} to {@code R}).
+ *     </li>
+ *
+ *     <li>There are additional derived function shapes which extend the basic
+ *     function shapes, including {@link java.util.function.UnaryOperator}
+ *     (extends {@code Function}) and {@link java.util.function.BinaryOperator}
+ *     (extends {@code BiFunction}).
+ *     </li>
+ *
+ *     <li>Type parameters of functional interfaces can be specialized to
+ *     primitives with additional type prefixes.  To specialize the return type
+ *     for a type that has both generic return type and generic arguments, we
+ *     prefix {@code ToXxx}, as in {@link java.util.function.ToIntFunction}.
+ *     Otherwise, type arguments are specialized left-to-right, as in
+ *     {@link java.util.function.DoubleConsumer}
+ *     or {@link java.util.function.ObjIntConsumer}.
+ *     (The type prefix {@code Obj} is used to indicate that we don't want to
+ *     specialize this parameter, but want to move on to the next parameter,
+ *     as in {@link java.util.function.ObjIntConsumer}.)
+ *     These schemes can be combined, as in {@code IntToDoubleFunction}.
+ *     </li>
+ *
+ *     <li>If there are specialization prefixes for all arguments, the arity
+ *     prefix may be left out (as in {@link java.util.function.ObjIntConsumer}).
+ *     </li>
+ * </ul>
+ *
+ * @see java.lang.FunctionalInterface
+ * @since 1.8
+ */
+package java.util.function;
diff --git a/java/util/jar/Attributes.java b/java/util/jar/Attributes.java
new file mode 100644
index 0000000..795b809
--- /dev/null
+++ b/java/util/jar/Attributes.java
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Collection;
+import java.util.AbstractSet;
+import java.util.Iterator;
+import sun.util.logging.PlatformLogger;
+import java.util.Comparator;
+import sun.misc.ASCIICaseInsensitiveComparator;
+
+/**
+ * The Attributes class maps Manifest attribute names to associated string
+ * values. Valid attribute names are case-insensitive, are restricted to
+ * the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed 70
+ * characters in length. Attribute values can contain any characters and
+ * will be UTF8-encoded when written to the output stream.  See the
+ * <a href="../../../../technotes/guides/jar/jar.html">JAR File Specification</a>
+ * for more information about valid attribute names and values.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @since   1.2
+ */
+public class Attributes implements Map<Object,Object>, Cloneable {
+    /**
+     * The attribute name-value mappings.
+     */
+    protected Map<Object,Object> map;
+
+    /**
+     * Constructs a new, empty Attributes object with default size.
+     */
+    public Attributes() {
+        this(11);
+    }
+
+    /**
+     * Constructs a new, empty Attributes object with the specified
+     * initial size.
+     *
+     * @param size the initial number of attributes
+     */
+    public Attributes(int size) {
+        map = new HashMap<>(size);
+    }
+
+    /**
+     * Constructs a new Attributes object with the same attribute name-value
+     * mappings as in the specified Attributes.
+     *
+     * @param attr the specified Attributes
+     */
+    public Attributes(Attributes attr) {
+        map = new HashMap<>(attr);
+    }
+
+
+    /**
+     * Returns the value of the specified attribute name, or null if the
+     * attribute name was not found.
+     *
+     * @param name the attribute name
+     * @return the value of the specified attribute name, or null if
+     *         not found.
+     */
+    public Object get(Object name) {
+        return map.get(name);
+    }
+
+    /**
+     * Returns the value of the specified attribute name, specified as
+     * a string, or null if the attribute was not found. The attribute
+     * name is case-insensitive.
+     * <p>
+     * This method is defined as:
+     * <pre>
+     *      return (String)get(new Attributes.Name((String)name));
+     * </pre>
+     *
+     * @param name the attribute name as a string
+     * @return the String value of the specified attribute name, or null if
+     *         not found.
+     * @throws IllegalArgumentException if the attribute name is invalid
+     */
+    public String getValue(String name) {
+        return (String)get(new Attributes.Name(name));
+    }
+
+    /**
+     * Returns the value of the specified Attributes.Name, or null if the
+     * attribute was not found.
+     * <p>
+     * This method is defined as:
+     * <pre>
+     *     return (String)get(name);
+     * </pre>
+     *
+     * @param name the Attributes.Name object
+     * @return the String value of the specified Attribute.Name, or null if
+     *         not found.
+     */
+    public String getValue(Name name) {
+        return (String)get(name);
+    }
+
+    /**
+     * Associates the specified value with the specified attribute name
+     * (key) in this Map. If the Map previously contained a mapping for
+     * the attribute name, the old value is replaced.
+     *
+     * @param name the attribute name
+     * @param value the attribute value
+     * @return the previous value of the attribute, or null if none
+     * @exception ClassCastException if the name is not a Attributes.Name
+     *            or the value is not a String
+     */
+    public Object put(Object name, Object value) {
+        return map.put((Attributes.Name)name, (String)value);
+    }
+
+    /**
+     * Associates the specified value with the specified attribute name,
+     * specified as a String. The attributes name is case-insensitive.
+     * If the Map previously contained a mapping for the attribute name,
+     * the old value is replaced.
+     * <p>
+     * This method is defined as:
+     * <pre>
+     *      return (String)put(new Attributes.Name(name), value);
+     * </pre>
+     *
+     * @param name the attribute name as a string
+     * @param value the attribute value
+     * @return the previous value of the attribute, or null if none
+     * @exception IllegalArgumentException if the attribute name is invalid
+     */
+    public String putValue(String name, String value) {
+        return (String)put(new Name(name), value);
+    }
+
+    /**
+     * Removes the attribute with the specified name (key) from this Map.
+     * Returns the previous attribute value, or null if none.
+     *
+     * @param name attribute name
+     * @return the previous value of the attribute, or null if none
+     */
+    public Object remove(Object name) {
+        return map.remove(name);
+    }
+
+    /**
+     * Returns true if this Map maps one or more attribute names (keys)
+     * to the specified value.
+     *
+     * @param value the attribute value
+     * @return true if this Map maps one or more attribute names to
+     *         the specified value
+     */
+    public boolean containsValue(Object value) {
+        return map.containsValue(value);
+    }
+
+    /**
+     * Returns true if this Map contains the specified attribute name (key).
+     *
+     * @param name the attribute name
+     * @return true if this Map contains the specified attribute name
+     */
+    public boolean containsKey(Object name) {
+        return map.containsKey(name);
+    }
+
+    /**
+     * Copies all of the attribute name-value mappings from the specified
+     * Attributes to this Map. Duplicate mappings will be replaced.
+     *
+     * @param attr the Attributes to be stored in this map
+     * @exception ClassCastException if attr is not an Attributes
+     */
+    public void putAll(Map<?,?> attr) {
+        // ## javac bug?
+        if (!Attributes.class.isInstance(attr))
+            throw new ClassCastException();
+        for (Map.Entry<?,?> me : (attr).entrySet())
+            put(me.getKey(), me.getValue());
+    }
+
+    /**
+     * Removes all attributes from this Map.
+     */
+    public void clear() {
+        map.clear();
+    }
+
+    /**
+     * Returns the number of attributes in this Map.
+     */
+    public int size() {
+        return map.size();
+    }
+
+    /**
+     * Returns true if this Map contains no attributes.
+     */
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    /**
+     * Returns a Set view of the attribute names (keys) contained in this Map.
+     */
+    public Set<Object> keySet() {
+        return map.keySet();
+    }
+
+    /**
+     * Returns a Collection view of the attribute values contained in this Map.
+     */
+    public Collection<Object> values() {
+        return map.values();
+    }
+
+    /**
+     * Returns a Collection view of the attribute name-value mappings
+     * contained in this Map.
+     */
+    public Set<Map.Entry<Object,Object>> entrySet() {
+        return map.entrySet();
+    }
+
+    /**
+     * Compares the specified Attributes object with this Map for equality.
+     * Returns true if the given object is also an instance of Attributes
+     * and the two Attributes objects represent the same mappings.
+     *
+     * @param o the Object to be compared
+     * @return true if the specified Object is equal to this Map
+     */
+    public boolean equals(Object o) {
+        return map.equals(o);
+    }
+
+    /**
+     * Returns the hash code value for this Map.
+     */
+    public int hashCode() {
+        return map.hashCode();
+    }
+
+    /**
+     * Returns a copy of the Attributes, implemented as follows:
+     * <pre>
+     *     public Object clone() { return new Attributes(this); }
+     * </pre>
+     * Since the attribute names and values are themselves immutable,
+     * the Attributes returned can be safely modified without affecting
+     * the original.
+     */
+    public Object clone() {
+        return new Attributes(this);
+    }
+
+    /*
+     * Writes the current attributes to the specified data output stream.
+     * XXX Need to handle UTF8 values and break up lines longer than 72 bytes
+     */
+     void write(DataOutputStream os) throws IOException {
+        Iterator<Map.Entry<Object, Object>> it = entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<Object, Object> e = it.next();
+            StringBuffer buffer = new StringBuffer(
+                                        ((Name)e.getKey()).toString());
+            buffer.append(": ");
+
+            String value = (String)e.getValue();
+            if (value != null) {
+                byte[] vb = value.getBytes("UTF8");
+                value = new String(vb, 0, 0, vb.length);
+            }
+            buffer.append(value);
+
+            buffer.append("\r\n");
+            Manifest.make72Safe(buffer);
+            os.writeBytes(buffer.toString());
+        }
+        os.writeBytes("\r\n");
+    }
+
+    /*
+     * Writes the current attributes to the specified data output stream,
+     * make sure to write out the MANIFEST_VERSION or SIGNATURE_VERSION
+     * attributes first.
+     *
+     * XXX Need to handle UTF8 values and break up lines longer than 72 bytes
+     */
+    void writeMain(DataOutputStream out) throws IOException
+    {
+        // write out the *-Version header first, if it exists
+        String vername = Name.MANIFEST_VERSION.toString();
+        String version = getValue(vername);
+        if (version == null) {
+            vername = Name.SIGNATURE_VERSION.toString();
+            version = getValue(vername);
+        }
+
+        if (version != null) {
+            out.writeBytes(vername+": "+version+"\r\n");
+        }
+
+        // write out all attributes except for the version
+        // we wrote out earlier
+        Iterator<Map.Entry<Object, Object>> it = entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<Object, Object> e = it.next();
+            String name = ((Name)e.getKey()).toString();
+            if ((version != null) && ! (name.equalsIgnoreCase(vername))) {
+
+                StringBuffer buffer = new StringBuffer(name);
+                buffer.append(": ");
+
+                String value = (String)e.getValue();
+                if (value != null) {
+                    byte[] vb = value.getBytes("UTF8");
+                    value = new String(vb, 0, 0, vb.length);
+                }
+                buffer.append(value);
+
+                buffer.append("\r\n");
+                Manifest.make72Safe(buffer);
+                out.writeBytes(buffer.toString());
+            }
+        }
+        out.writeBytes("\r\n");
+    }
+
+    /*
+     * Reads attributes from the specified input stream.
+     * XXX Need to handle UTF8 values.
+     */
+    void read(Manifest.FastInputStream is, byte[] lbuf) throws IOException {
+        String name = null, value = null;
+        byte[] lastline = null;
+
+        int len;
+        while ((len = is.readLine(lbuf)) != -1) {
+            boolean lineContinued = false;
+            if (lbuf[--len] != '\n') {
+                throw new IOException("line too long");
+            }
+            if (len > 0 && lbuf[len-1] == '\r') {
+                --len;
+            }
+            if (len == 0) {
+                break;
+            }
+            int i = 0;
+            if (lbuf[0] == ' ') {
+                // continuation of previous line
+                if (name == null) {
+                    throw new IOException("misplaced continuation line");
+                }
+                lineContinued = true;
+                byte[] buf = new byte[lastline.length + len - 1];
+                System.arraycopy(lastline, 0, buf, 0, lastline.length);
+                System.arraycopy(lbuf, 1, buf, lastline.length, len - 1);
+                if (is.peek() == ' ') {
+                    lastline = buf;
+                    continue;
+                }
+                value = new String(buf, 0, buf.length, "UTF8");
+                lastline = null;
+            } else {
+                while (lbuf[i++] != ':') {
+                    if (i >= len) {
+                        throw new IOException("invalid header field");
+                    }
+                }
+                if (lbuf[i++] != ' ') {
+                    throw new IOException("invalid header field");
+                }
+                name = new String(lbuf, 0, 0, i - 2);
+                if (is.peek() == ' ') {
+                    lastline = new byte[len - i];
+                    System.arraycopy(lbuf, i, lastline, 0, len - i);
+                    continue;
+                }
+                value = new String(lbuf, i, len - i, "UTF8");
+            }
+            try {
+                if ((putValue(name, value) != null) && (!lineContinued)) {
+                    PlatformLogger.getLogger("java.util.jar").warning(
+                                     "Duplicate name in Manifest: " + name
+                                     + ".\n"
+                                     + "Ensure that the manifest does not "
+                                     + "have duplicate entries, and\n"
+                                     + "that blank lines separate "
+                                     + "individual sections in both your\n"
+                                     + "manifest and in the META-INF/MANIFEST.MF "
+                                     + "entry in the jar file.");
+                }
+            } catch (IllegalArgumentException e) {
+                throw new IOException("invalid header field name: " + name);
+            }
+        }
+    }
+
+    /**
+     * The Attributes.Name class represents an attribute name stored in
+     * this Map. Valid attribute names are case-insensitive, are restricted
+     * to the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed
+     * 70 characters in length. Attribute values can contain any characters
+     * and will be UTF8-encoded when written to the output stream.  See the
+     * <a href="../../../../technotes/guides/jar/jar.html">JAR File Specification</a>
+     * for more information about valid attribute names and values.
+     */
+    public static class Name {
+        private String name;
+        private int hashCode = -1;
+
+        /**
+         * Constructs a new attribute name using the given string name.
+         *
+         * @param name the attribute string name
+         * @exception IllegalArgumentException if the attribute name was
+         *            invalid
+         * @exception NullPointerException if the attribute name was null
+         */
+        public Name(String name) {
+            if (name == null) {
+                throw new NullPointerException("name");
+            }
+            if (!isValid(name)) {
+                throw new IllegalArgumentException(name);
+            }
+            this.name = name.intern();
+        }
+
+        private static boolean isValid(String name) {
+            int len = name.length();
+            if (len > 70 || len == 0) {
+                return false;
+            }
+            for (int i = 0; i < len; i++) {
+                if (!isValid(name.charAt(i))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private static boolean isValid(char c) {
+            return isAlpha(c) || isDigit(c) || c == '_' || c == '-';
+        }
+
+        private static boolean isAlpha(char c) {
+            return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+        }
+
+        private static boolean isDigit(char c) {
+            return c >= '0' && c <= '9';
+        }
+
+        /**
+         * Compares this attribute name to another for equality.
+         * @param o the object to compare
+         * @return true if this attribute name is equal to the
+         *         specified attribute object
+         */
+        public boolean equals(Object o) {
+            if (o instanceof Name) {
+                Comparator<String> c = ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER;
+                return c.compare(name, ((Name)o).name) == 0;
+            } else {
+                return false;
+            }
+        }
+
+        /**
+         * Computes the hash value for this attribute name.
+         */
+        public int hashCode() {
+            if (hashCode == -1) {
+                hashCode = ASCIICaseInsensitiveComparator.lowerCaseHashCode(name);
+            }
+            return hashCode;
+        }
+
+        /**
+         * Returns the attribute name as a String.
+         */
+        public String toString() {
+            return name;
+        }
+
+        /**
+         * <code>Name</code> object for <code>Manifest-Version</code>
+         * manifest attribute. This attribute indicates the version number
+         * of the manifest standard to which a JAR file's manifest conforms.
+         * @see <a href="../../../../technotes/guides/jar/jar.html#JAR_Manifest">
+         *      Manifest and Signature Specification</a>
+         */
+        public static final Name MANIFEST_VERSION = new Name("Manifest-Version");
+
+        /**
+         * <code>Name</code> object for <code>Signature-Version</code>
+         * manifest attribute used when signing JAR files.
+         * @see <a href="../../../../technotes/guides/jar/jar.html#JAR_Manifest">
+         *      Manifest and Signature Specification</a>
+         */
+        public static final Name SIGNATURE_VERSION = new Name("Signature-Version");
+
+        /**
+         * <code>Name</code> object for <code>Content-Type</code>
+         * manifest attribute.
+         */
+        public static final Name CONTENT_TYPE = new Name("Content-Type");
+
+        /**
+         * <code>Name</code> object for <code>Class-Path</code>
+         * manifest attribute. Bundled extensions can use this attribute
+         * to find other JAR files containing needed classes.
+         * @see <a href="../../../../technotes/guides/jar/jar.html#classpath">
+         *      JAR file specification</a>
+         */
+        public static final Name CLASS_PATH = new Name("Class-Path");
+
+        /**
+         * <code>Name</code> object for <code>Main-Class</code> manifest
+         * attribute used for launching applications packaged in JAR files.
+         * The <code>Main-Class</code> attribute is used in conjunction
+         * with the <code>-jar</code> command-line option of the
+         * <tt>java</tt> application launcher.
+         */
+        public static final Name MAIN_CLASS = new Name("Main-Class");
+
+        /**
+         * <code>Name</code> object for <code>Sealed</code> manifest attribute
+         * used for sealing.
+         * @see <a href="../../../../technotes/guides/jar/jar.html#sealing">
+         *      Package Sealing</a>
+         */
+        public static final Name SEALED = new Name("Sealed");
+
+       /**
+         * <code>Name</code> object for <code>Extension-List</code> manifest attribute
+         * used for declaring dependencies on installed extensions.
+         * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
+         *      Installed extension dependency</a>
+         */
+        public static final Name EXTENSION_LIST = new Name("Extension-List");
+
+        /**
+         * <code>Name</code> object for <code>Extension-Name</code> manifest attribute
+         * used for declaring dependencies on installed extensions.
+         * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
+         *      Installed extension dependency</a>
+         */
+        public static final Name EXTENSION_NAME = new Name("Extension-Name");
+
+        /**
+         * <code>Name</code> object for <code>Extension-Name</code> manifest attribute
+         * used for declaring dependencies on installed extensions.
+         * @deprecated Extension mechanism will be removed in a future release.
+         *             Use class path instead.
+         * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
+         *      Installed extension dependency</a>
+         */
+        @Deprecated
+        public static final Name EXTENSION_INSTALLATION = new Name("Extension-Installation");
+
+        /**
+         * <code>Name</code> object for <code>Implementation-Title</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name IMPLEMENTATION_TITLE = new Name("Implementation-Title");
+
+        /**
+         * <code>Name</code> object for <code>Implementation-Version</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name IMPLEMENTATION_VERSION = new Name("Implementation-Version");
+
+        /**
+         * <code>Name</code> object for <code>Implementation-Vendor</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name IMPLEMENTATION_VENDOR = new Name("Implementation-Vendor");
+
+        /**
+         * <code>Name</code> object for <code>Implementation-Vendor-Id</code>
+         * manifest attribute used for package versioning.
+         * @deprecated Extension mechanism will be removed in a future release.
+         *             Use class path instead.
+         * @see <a href="../../../../technotes/guides/extensions/versioning.html#applet">
+         *      Optional Package Versioning</a>
+         */
+        @Deprecated
+        public static final Name IMPLEMENTATION_VENDOR_ID = new Name("Implementation-Vendor-Id");
+
+       /**
+         * <code>Name</code> object for <code>Implementation-URL</code>
+         * manifest attribute used for package versioning.
+         * @deprecated Extension mechanism will be removed in a future release.
+         *             Use class path instead.
+         * @see <a href="../../../../technotes/guides/extensions/versioning.html#applet">
+         *      Optional Package Versioning</a>
+         */
+        @Deprecated
+        public static final Name IMPLEMENTATION_URL = new Name("Implementation-URL");
+
+        /**
+         * <code>Name</code> object for <code>Specification-Title</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name SPECIFICATION_TITLE = new Name("Specification-Title");
+
+        /**
+         * <code>Name</code> object for <code>Specification-Version</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name SPECIFICATION_VERSION = new Name("Specification-Version");
+
+        /**
+         * <code>Name</code> object for <code>Specification-Vendor</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name SPECIFICATION_VENDOR = new Name("Specification-Vendor");
+    }
+}
diff --git a/java/util/jar/JarEntry.java b/java/util/jar/JarEntry.java
new file mode 100644
index 0000000..b0e6841
--- /dev/null
+++ b/java/util/jar/JarEntry.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.security.CodeSigner;
+import java.security.cert.Certificate;
+
+/**
+ * This class is used to represent a JAR file entry.
+ */
+public
+class JarEntry extends ZipEntry {
+    Attributes attr;
+    Certificate[] certs;
+    CodeSigner[] signers;
+
+    /**
+     * Creates a new <code>JarEntry</code> for the specified JAR file
+     * entry name.
+     *
+     * @param name the JAR file entry name
+     * @exception NullPointerException if the entry name is <code>null</code>
+     * @exception IllegalArgumentException if the entry name is longer than
+     *            0xFFFF bytes.
+     */
+    public JarEntry(String name) {
+        super(name);
+    }
+
+    /**
+     * Creates a new <code>JarEntry</code> with fields taken from the
+     * specified <code>ZipEntry</code> object.
+     * @param ze the <code>ZipEntry</code> object to create the
+     *           <code>JarEntry</code> from
+     */
+    public JarEntry(ZipEntry ze) {
+        super(ze);
+    }
+
+    /**
+     * Creates a new <code>JarEntry</code> with fields taken from the
+     * specified <code>JarEntry</code> object.
+     *
+     * @param je the <code>JarEntry</code> to copy
+     */
+    public JarEntry(JarEntry je) {
+        this((ZipEntry)je);
+        this.attr = je.attr;
+        this.certs = je.certs;
+        this.signers = je.signers;
+    }
+
+    /**
+     * Returns the <code>Manifest</code> <code>Attributes</code> for this
+     * entry, or <code>null</code> if none.
+     *
+     * @return the <code>Manifest</code> <code>Attributes</code> for this
+     * entry, or <code>null</code> if none
+     * @throws IOException  if an I/O error has occurred
+     */
+    public Attributes getAttributes() throws IOException {
+        return attr;
+    }
+
+    /**
+     * Returns the <code>Certificate</code> objects for this entry, or
+     * <code>null</code> if none. This method can only be called once
+     * the <code>JarEntry</code> has been completely verified by reading
+     * from the entry input stream until the end of the stream has been
+     * reached. Otherwise, this method will return <code>null</code>.
+     *
+     * <p>The returned certificate array comprises all the signer certificates
+     * that were used to verify this entry. Each signer certificate is
+     * followed by its supporting certificate chain (which may be empty).
+     * Each signer certificate and its supporting certificate chain are ordered
+     * bottom-to-top (i.e., with the signer certificate first and the (root)
+     * certificate authority last).
+     *
+     * @return the <code>Certificate</code> objects for this entry, or
+     * <code>null</code> if none.
+     */
+    public Certificate[] getCertificates() {
+        return certs == null ? null : certs.clone();
+    }
+
+    /**
+     * Returns the <code>CodeSigner</code> objects for this entry, or
+     * <code>null</code> if none. This method can only be called once
+     * the <code>JarEntry</code> has been completely verified by reading
+     * from the entry input stream until the end of the stream has been
+     * reached. Otherwise, this method will return <code>null</code>.
+     *
+     * <p>The returned array comprises all the code signers that have signed
+     * this entry.
+     *
+     * @return the <code>CodeSigner</code> objects for this entry, or
+     * <code>null</code> if none.
+     *
+     * @since 1.5
+     */
+    public CodeSigner[] getCodeSigners() {
+        return signers == null ? null : signers.clone();
+    }
+}
diff --git a/java/util/jar/JarException.java b/java/util/jar/JarException.java
new file mode 100644
index 0000000..b6e1ca2
--- /dev/null
+++ b/java/util/jar/JarException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+/**
+ * Signals that an error of some sort has occurred while reading from
+ * or writing to a JAR file.
+ *
+ * @author  David Connelly
+ * @since   1.2
+ */
+public
+class JarException extends java.util.zip.ZipException {
+    private static final long serialVersionUID = 7159778400963954473L;
+
+    /**
+     * Constructs a JarException with no detail message.
+     */
+    public JarException() {
+    }
+
+    /**
+     * Constructs a JarException with the specified detail message.
+     * @param s the detail message
+     */
+    public JarException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/jar/JarFile.java b/java/util/jar/JarFile.java
new file mode 100644
index 0000000..342e341
--- /dev/null
+++ b/java/util/jar/JarFile.java
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.*;
+import java.lang.ref.SoftReference;
+import java.util.*;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import java.util.zip.*;
+import java.security.CodeSigner;
+import java.security.cert.Certificate;
+import java.security.AccessController;
+import sun.misc.IOUtils;
+import sun.security.action.GetPropertyAction;
+import sun.security.util.ManifestEntryVerifier;
+import sun.security.util.SignatureFileVerifier;
+
+/**
+ * The <code>JarFile</code> class is used to read the contents of a jar file
+ * from any file that can be opened with <code>java.io.RandomAccessFile</code>.
+ * It extends the class <code>java.util.zip.ZipFile</code> with support
+ * for reading an optional <code>Manifest</code> entry. The
+ * <code>Manifest</code> can be used to specify meta-information about the
+ * jar file and its entries.
+ *
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
+ * If the verify flag is on when opening a signed jar file, the content of the
+ * file is verified against its signature embedded inside the file. Please note
+ * that the verification process does not include validating the signer's
+ * certificate. A caller should inspect the return value of
+ * {@link JarEntry#getCodeSigners()} to further determine if the signature
+ * can be trusted.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @see     java.util.zip.ZipFile
+ * @see     java.util.jar.JarEntry
+ * @since   1.2
+ */
+public
+class JarFile extends ZipFile {
+    // Android-changed: Hold the Manifest via a hard reference. http://b/28692091
+    // private SoftReference<Manifest> manRef;
+    private Manifest manifest;
+    private JarEntry manEntry;
+    private JarVerifier jv;
+    private boolean jvInitialized;
+    private boolean verify;
+
+    // indicates if Class-Path attribute present (only valid if hasCheckedSpecialAttributes true)
+    private boolean hasClassPathAttribute;
+    // true if manifest checked for special attributes
+    private volatile boolean hasCheckedSpecialAttributes;
+
+    // Android-removed: SharedSecrets.setJavaUtilJarAccess
+    /*
+    // Set up JavaUtilJarAccess in SharedSecrets
+    static {
+        SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl());
+    }
+    */
+
+    /**
+     * The JAR manifest file name.
+     */
+    public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * file <code>name</code>. The <code>JarFile</code> will be verified if
+     * it is signed.
+     * @param name the name of the jar file to be opened for reading
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     */
+    public JarFile(String name) throws IOException {
+        this(new File(name), true, ZipFile.OPEN_READ);
+    }
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * file <code>name</code>.
+     * @param name the name of the jar file to be opened for reading
+     * @param verify whether or not to verify the jar file if
+     * it is signed.
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     */
+    public JarFile(String name, boolean verify) throws IOException {
+        this(new File(name), verify, ZipFile.OPEN_READ);
+    }
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * <code>File</code> object. The <code>JarFile</code> will be verified if
+     * it is signed.
+     * @param file the jar file to be opened for reading
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     */
+    public JarFile(File file) throws IOException {
+        this(file, true, ZipFile.OPEN_READ);
+    }
+
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * <code>File</code> object.
+     * @param file the jar file to be opened for reading
+     * @param verify whether or not to verify the jar file if
+     * it is signed.
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager.
+     */
+    public JarFile(File file, boolean verify) throws IOException {
+        this(file, verify, ZipFile.OPEN_READ);
+    }
+
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * <code>File</code> object in the specified mode.  The mode argument
+     * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>.
+     *
+     * @param file the jar file to be opened for reading
+     * @param verify whether or not to verify the jar file if
+     * it is signed.
+     * @param mode the mode in which the file is to be opened
+     * @throws IOException if an I/O error has occurred
+     * @throws IllegalArgumentException
+     *         if the <tt>mode</tt> argument is invalid
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     * @since 1.3
+     */
+    public JarFile(File file, boolean verify, int mode) throws IOException {
+        super(file, mode);
+        this.verify = verify;
+    }
+
+    /**
+     * Returns the jar file manifest, or <code>null</code> if none.
+     *
+     * @return the jar file manifest, or <code>null</code> if none
+     *
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     * @throws IOException  if an I/O error has occurred
+     */
+    public Manifest getManifest() throws IOException {
+        return getManifestFromReference();
+    }
+
+    // BEGIN Android-changed: Fix JarFile to be thread safe. http://b/27826114
+    // A volatile field might also work instead of synchronized. http://b/81505612
+    // private Manifest getManifestFromReference() throws IOException {
+    private synchronized Manifest getManifestFromReference() throws IOException {
+    // END Android-changed: Fix JarFile to be thread safe. http://b/27826114
+        // Android-changed: Hold the Manifest via a hard reference. http://b/28692091
+        // Manifest man = manRef != null ? manRef.get() : null;
+        Manifest man = manifest;
+        if (man == null) {
+
+            JarEntry manEntry = getManEntry();
+
+            // If found then load the manifest
+            if (manEntry != null) {
+                if (verify) {
+                    byte[] b = getBytes(manEntry);
+                    man = new Manifest(new ByteArrayInputStream(b));
+                    if (!jvInitialized) {
+                        jv = new JarVerifier(b);
+                    }
+                } else {
+                    man = new Manifest(super.getInputStream(manEntry));
+                }
+                // Android-changed: Hold the Manifest via a hard reference. http://b/28692091
+                // manRef = new SoftReference<>(man);
+                manifest = man;
+            }
+        }
+        return man;
+    }
+
+    private native String[] getMetaInfEntryNames();
+
+    /**
+     * Returns the <code>JarEntry</code> for the given entry name or
+     * <code>null</code> if not found.
+     *
+     * @param name the jar file entry name
+     * @return the <code>JarEntry</code> for the given entry name or
+     *         <code>null</code> if not found.
+     *
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     *
+     * @see java.util.jar.JarEntry
+     */
+    public JarEntry getJarEntry(String name) {
+        return (JarEntry)getEntry(name);
+    }
+
+    /**
+     * Returns the <code>ZipEntry</code> for the given entry name or
+     * <code>null</code> if not found.
+     *
+     * @param name the jar file entry name
+     * @return the <code>ZipEntry</code> for the given entry name or
+     *         <code>null</code> if not found
+     *
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     *
+     * @see java.util.zip.ZipEntry
+     */
+    public ZipEntry getEntry(String name) {
+        ZipEntry ze = super.getEntry(name);
+        if (ze != null) {
+            return new JarFileEntry(ze);
+        }
+        return null;
+    }
+
+    private class JarEntryIterator implements Enumeration<JarEntry>,
+            Iterator<JarEntry>
+    {
+        final Enumeration<? extends ZipEntry> e = JarFile.super.entries();
+
+        public boolean hasNext() {
+            return e.hasMoreElements();
+        }
+
+        public JarEntry next() {
+            ZipEntry ze = e.nextElement();
+            return new JarFileEntry(ze);
+        }
+
+        public boolean hasMoreElements() {
+            return hasNext();
+        }
+
+        public JarEntry nextElement() {
+            return next();
+        }
+    }
+
+    /**
+     * Returns an enumeration of the zip file entries.
+     */
+    public Enumeration<JarEntry> entries() {
+        return new JarEntryIterator();
+    }
+
+    @Override
+    public Stream<JarEntry> stream() {
+        return StreamSupport.stream(Spliterators.spliterator(
+                new JarEntryIterator(), size(),
+                Spliterator.ORDERED | Spliterator.DISTINCT |
+                        Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
+    }
+
+    private class JarFileEntry extends JarEntry {
+        JarFileEntry(ZipEntry ze) {
+            super(ze);
+        }
+        public Attributes getAttributes() throws IOException {
+            Manifest man = JarFile.this.getManifest();
+            if (man != null) {
+                return man.getAttributes(getName());
+            } else {
+                return null;
+            }
+        }
+        public Certificate[] getCertificates() {
+            try {
+                maybeInstantiateVerifier();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            if (certs == null && jv != null) {
+                certs = jv.getCerts(JarFile.this, this);
+            }
+            return certs == null ? null : certs.clone();
+        }
+        public CodeSigner[] getCodeSigners() {
+            try {
+                maybeInstantiateVerifier();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            if (signers == null && jv != null) {
+                signers = jv.getCodeSigners(JarFile.this, this);
+            }
+            return signers == null ? null : signers.clone();
+        }
+    }
+
+    /*
+     * Ensures that the JarVerifier has been created if one is
+     * necessary (i.e., the jar appears to be signed.) This is done as
+     * a quick check to avoid processing of the manifest for unsigned
+     * jars.
+     */
+    private void maybeInstantiateVerifier() throws IOException {
+        if (jv != null) {
+            return;
+        }
+
+        if (verify) {
+            String[] names = getMetaInfEntryNames();
+            if (names != null) {
+                for (int i = 0; i < names.length; i++) {
+                    String name = names[i].toUpperCase(Locale.ENGLISH);
+                    if (name.endsWith(".DSA") ||
+                        name.endsWith(".RSA") ||
+                        name.endsWith(".EC") ||
+                        name.endsWith(".SF")) {
+                        // Assume since we found a signature-related file
+                        // that the jar is signed and that we therefore
+                        // need a JarVerifier and Manifest
+                        getManifest();
+                        return;
+                    }
+                }
+            }
+            // No signature-related files; don't instantiate a
+            // verifier
+            verify = false;
+        }
+    }
+
+
+    /*
+     * Initializes the verifier object by reading all the manifest
+     * entries and passing them to the verifier.
+     */
+    private void initializeVerifier() {
+        ManifestEntryVerifier mev = null;
+
+        // Verify "META-INF/" entries...
+        try {
+            String[] names = getMetaInfEntryNames();
+            if (names != null) {
+                for (int i = 0; i < names.length; i++) {
+                    String uname = names[i].toUpperCase(Locale.ENGLISH);
+                    if (MANIFEST_NAME.equals(uname)
+                            || SignatureFileVerifier.isBlockOrSF(uname)) {
+                        JarEntry e = getJarEntry(names[i]);
+                        if (e == null) {
+                            throw new JarException("corrupted jar file");
+                        }
+                        if (mev == null) {
+                            mev = new ManifestEntryVerifier
+                                (getManifestFromReference());
+                        }
+                        byte[] b = getBytes(e);
+                        if (b != null && b.length > 0) {
+                            jv.beginEntry(e, mev);
+                            jv.update(b.length, b, 0, b.length, mev);
+                            jv.update(-1, null, 0, 0, mev);
+                        }
+                    }
+                }
+            }
+        } catch (IOException ex) {
+            // if we had an error parsing any blocks, just
+            // treat the jar file as being unsigned
+            jv = null;
+            verify = false;
+            if (JarVerifier.debug != null) {
+                JarVerifier.debug.println("jarfile parsing error!");
+                ex.printStackTrace();
+            }
+        }
+
+        // if after initializing the verifier we have nothing
+        // signed, we null it out.
+
+        if (jv != null) {
+
+            jv.doneWithMeta();
+            if (JarVerifier.debug != null) {
+                JarVerifier.debug.println("done with meta!");
+            }
+
+            if (jv.nothingToVerify()) {
+                if (JarVerifier.debug != null) {
+                    JarVerifier.debug.println("nothing to verify!");
+                }
+                jv = null;
+                verify = false;
+            }
+        }
+    }
+
+    /*
+     * Reads all the bytes for a given entry. Used to process the
+     * META-INF files.
+     */
+    private byte[] getBytes(ZipEntry ze) throws IOException {
+        try (InputStream is = super.getInputStream(ze)) {
+            return IOUtils.readFully(is, (int)ze.getSize(), true);
+        }
+    }
+
+    /**
+     * Returns an input stream for reading the contents of the specified
+     * zip file entry.
+     * @param ze the zip file entry
+     * @return an input stream for reading the contents of the specified
+     *         zip file entry
+     * @throws ZipException if a zip file format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     */
+    public synchronized InputStream getInputStream(ZipEntry ze)
+        throws IOException
+    {
+        maybeInstantiateVerifier();
+        if (jv == null) {
+            return super.getInputStream(ze);
+        }
+        if (!jvInitialized) {
+            initializeVerifier();
+            jvInitialized = true;
+            // could be set to null after a call to
+            // initializeVerifier if we have nothing to
+            // verify
+            if (jv == null)
+                return super.getInputStream(ze);
+        }
+
+        // wrap a verifier stream around the real stream
+        return new JarVerifier.VerifierStream(
+            getManifestFromReference(),
+            ze instanceof JarFileEntry ?
+            (JarEntry) ze : getJarEntry(ze.getName()),
+            super.getInputStream(ze),
+            jv);
+    }
+
+    // Statics for hand-coded Boyer-Moore search
+    private static final char[] CLASSPATH_CHARS = {'c','l','a','s','s','-','p','a','t','h'};
+    // The bad character shift for "class-path"
+    private static final int[] CLASSPATH_LASTOCC;
+    // The good suffix shift for "class-path"
+    private static final int[] CLASSPATH_OPTOSFT;
+
+    static {
+        CLASSPATH_LASTOCC = new int[128];
+        CLASSPATH_OPTOSFT = new int[10];
+        CLASSPATH_LASTOCC[(int)'c'] = 1;
+        CLASSPATH_LASTOCC[(int)'l'] = 2;
+        CLASSPATH_LASTOCC[(int)'s'] = 5;
+        CLASSPATH_LASTOCC[(int)'-'] = 6;
+        CLASSPATH_LASTOCC[(int)'p'] = 7;
+        CLASSPATH_LASTOCC[(int)'a'] = 8;
+        CLASSPATH_LASTOCC[(int)'t'] = 9;
+        CLASSPATH_LASTOCC[(int)'h'] = 10;
+        for (int i=0; i<9; i++)
+            CLASSPATH_OPTOSFT[i] = 10;
+        CLASSPATH_OPTOSFT[9]=1;
+    }
+
+    // BEGIN Android-changed: Fix JarFile to be thread safe. http://b/27826114
+    // A volatile field might also work instead of synchronized. http://b/81505612
+    // private JarEntry getManEntry() {
+    private synchronized JarEntry getManEntry() {
+    // END Android-changed: Fix JarFile to be thread safe. http://b/27826114
+        if (manEntry == null) {
+            // First look up manifest entry using standard name
+            manEntry = getJarEntry(MANIFEST_NAME);
+            if (manEntry == null) {
+                // If not found, then iterate through all the "META-INF/"
+                // entries to find a match.
+                String[] names = getMetaInfEntryNames();
+                if (names != null) {
+                    for (int i = 0; i < names.length; i++) {
+                        if (MANIFEST_NAME.equals(
+                                                 names[i].toUpperCase(Locale.ENGLISH))) {
+                            manEntry = getJarEntry(names[i]);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        return manEntry;
+    }
+
+   /**
+    * Returns {@code true} iff this JAR file has a manifest with the
+    * Class-Path attribute
+    * @hide
+    */
+    // Android-changed: Make hasClassPathAttribute() @hide public, for internal use.
+    // Used by URLClassPath.JarLoader.
+    // boolean hasClassPathAttribute() throws IOException {
+    public boolean hasClassPathAttribute() throws IOException {
+        checkForSpecialAttributes();
+        return hasClassPathAttribute;
+    }
+
+    /**
+     * Returns true if the pattern {@code src} is found in {@code b}.
+     * The {@code lastOcc} and {@code optoSft} arrays are the precomputed
+     * bad character and good suffix shifts.
+     */
+    private boolean match(char[] src, byte[] b, int[] lastOcc, int[] optoSft) {
+        int len = src.length;
+        int last = b.length - len;
+        int i = 0;
+        next:
+        while (i<=last) {
+            for (int j=(len-1); j>=0; j--) {
+                char c = (char) b[i+j];
+                c = (((c-'A')|('Z'-c)) >= 0) ? (char)(c + 32) : c;
+                if (c != src[j]) {
+                    i += Math.max(j + 1 - lastOcc[c&0x7F], optoSft[j]);
+                    continue next;
+                 }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * On first invocation, check if the JAR file has the Class-Path
+     * attribute. A no-op on subsequent calls.
+     */
+    private void checkForSpecialAttributes() throws IOException {
+        if (hasCheckedSpecialAttributes) return;
+        // Android-changed: Special handling of well-known .jar files specific to OpenJDK.
+        // if (!isKnownNotToHaveSpecialAttributes()) {
+        {
+            JarEntry manEntry = getManEntry();
+            if (manEntry != null) {
+                byte[] b = getBytes(manEntry);
+                if (match(CLASSPATH_CHARS, b, CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT))
+                    hasClassPathAttribute = true;
+            }
+        }
+        hasCheckedSpecialAttributes = true;
+    }
+
+
+    // Android-removed: Special handling of well-known .jar files specific to OpenJDK.
+    /*
+    private static String javaHome;
+    private static volatile String[] jarNames;
+    private boolean isKnownNotToHaveSpecialAttributes() {
+        // Optimize away even scanning of manifest for jar files we
+        // deliver which don't have a class-path attribute. If one of
+        // these jars is changed to include such an attribute this code
+        // must be changed.
+        if (javaHome == null) {
+            javaHome = AccessController.doPrivileged(
+                new GetPropertyAction("java.home"));
+        }
+        if (jarNames == null) {
+            String[] names = new String[11];
+            String fileSep = File.separator;
+            int i = 0;
+            names[i++] = fileSep + "rt.jar";
+            names[i++] = fileSep + "jsse.jar";
+            names[i++] = fileSep + "jce.jar";
+            names[i++] = fileSep + "charsets.jar";
+            names[i++] = fileSep + "dnsns.jar";
+            names[i++] = fileSep + "zipfs.jar";
+            names[i++] = fileSep + "localedata.jar";
+            names[i++] = fileSep = "cldrdata.jar";
+            names[i++] = fileSep + "sunjce_provider.jar";
+            names[i++] = fileSep + "sunpkcs11.jar";
+            names[i++] = fileSep + "sunec.jar";
+            jarNames = names;
+        }
+
+        String name = getName();
+        String localJavaHome = javaHome;
+        if (name.startsWith(localJavaHome)) {
+            String[] names = jarNames;
+            for (int i = 0; i < names.length; i++) {
+                if (name.endsWith(names[i])) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    */
+
+    // Android-removed: Unused method ensureInitialization().
+    /*
+    private synchronized void ensureInitialization() {
+        try {
+            maybeInstantiateVerifier();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        if (jv != null && !jvInitialized) {
+            initializeVerifier();
+            jvInitialized = true;
+        }
+    }
+    */
+
+    JarEntry newEntry(ZipEntry ze) {
+        return new JarFileEntry(ze);
+    }
+
+    // Android-removed: Unused methods entryNames(), entries2().
+    /*
+    Enumeration<String> entryNames(CodeSource[] cs) {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.entryNames(this, cs);
+        }
+
+        /*
+         * JAR file has no signed content. Is there a non-signing
+         * code source?
+         *
+        boolean includeUnsigned = false;
+        for (int i = 0; i < cs.length; i++) {
+            if (cs[i].getCodeSigners() == null) {
+                includeUnsigned = true;
+                break;
+            }
+        }
+        if (includeUnsigned) {
+            return unsignedEntryNames();
+        } else {
+            return new Enumeration<String>() {
+
+                public boolean hasMoreElements() {
+                    return false;
+                }
+
+                public String nextElement() {
+                    throw new NoSuchElementException();
+                }
+            };
+        }
+    }
+
+    /**
+     * Returns an enumeration of the zip file entries
+     * excluding internal JAR mechanism entries and including
+     * signed entries missing from the ZIP directory.
+     *
+    Enumeration<JarEntry> entries2() {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.entries2(this, super.entries());
+        }
+
+        // screen out entries which are never signed
+        final Enumeration<? extends ZipEntry> enum_ = super.entries();
+        return new Enumeration<JarEntry>() {
+
+            ZipEntry entry;
+
+            public boolean hasMoreElements() {
+                if (entry != null) {
+                    return true;
+                }
+                while (enum_.hasMoreElements()) {
+                    ZipEntry ze = enum_.nextElement();
+                    if (JarVerifier.isSigningRelated(ze.getName())) {
+                        continue;
+                    }
+                    entry = ze;
+                    return true;
+                }
+                return false;
+            }
+
+            public JarFileEntry nextElement() {
+                if (hasMoreElements()) {
+                    ZipEntry ze = entry;
+                    entry = null;
+                    return new JarFileEntry(ze);
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+
+    CodeSource[] getCodeSources(URL url) {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.getCodeSources(this, url);
+        }
+
+        /*
+         * JAR file has no signed content. Is there a non-signing
+         * code source?
+         *
+        Enumeration<String> unsigned = unsignedEntryNames();
+        if (unsigned.hasMoreElements()) {
+            return new CodeSource[]{JarVerifier.getUnsignedCS(url)};
+        } else {
+            return null;
+        }
+    }
+
+    private Enumeration<String> unsignedEntryNames() {
+        final Enumeration<JarEntry> entries = entries();
+        return new Enumeration<String>() {
+
+            String name;
+
+            /*
+             * Grab entries from ZIP directory but screen out
+             * metadata.
+             *
+            public boolean hasMoreElements() {
+                if (name != null) {
+                    return true;
+                }
+                while (entries.hasMoreElements()) {
+                    String value;
+                    ZipEntry e = entries.nextElement();
+                    value = e.getName();
+                    if (e.isDirectory() || JarVerifier.isSigningRelated(value)) {
+                        continue;
+                    }
+                    name = value;
+                    return true;
+                }
+                return false;
+            }
+
+            public String nextElement() {
+                if (hasMoreElements()) {
+                    String value = name;
+                    name = null;
+                    return value;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+
+    CodeSource getCodeSource(URL url, String name) {
+        ensureInitialization();
+        if (jv != null) {
+            if (jv.eagerValidation) {
+                CodeSource cs = null;
+                JarEntry je = getJarEntry(name);
+                if (je != null) {
+                    cs = jv.getCodeSource(url, this, je);
+                } else {
+                    cs = jv.getCodeSource(url, name);
+                }
+                return cs;
+            } else {
+                return jv.getCodeSource(url, name);
+            }
+        }
+
+        return JarVerifier.getUnsignedCS(url);
+    }
+
+    void setEagerValidation(boolean eager) {
+        try {
+            maybeInstantiateVerifier();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        if (jv != null) {
+            jv.setEagerValidation(eager);
+        }
+    }
+
+    List<Object> getManifestDigests() {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.getManifestDigests();
+        }
+        return new ArrayList<Object>();
+    }
+    */
+}
diff --git a/java/util/jar/JarInputStream.java b/java/util/jar/JarInputStream.java
new file mode 100644
index 0000000..67f27be
--- /dev/null
+++ b/java/util/jar/JarInputStream.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.util.zip.*;
+import java.io.*;
+import sun.security.util.ManifestEntryVerifier;
+import sun.misc.JarIndex;
+
+/**
+ * The <code>JarInputStream</code> class is used to read the contents of
+ * a JAR file from any input stream. It extends the class
+ * <code>java.util.zip.ZipInputStream</code> with support for reading
+ * an optional <code>Manifest</code> entry. The <code>Manifest</code>
+ * can be used to store meta-information about the JAR file and its entries.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @see     java.util.zip.ZipInputStream
+ * @since   1.2
+ */
+public
+class JarInputStream extends ZipInputStream {
+    private Manifest man;
+    private JarEntry first;
+    private JarVerifier jv;
+    private ManifestEntryVerifier mev;
+    private final boolean doVerify;
+    private boolean tryManifest;
+
+    /**
+     * Creates a new <code>JarInputStream</code> and reads the optional
+     * manifest. If a manifest is present, also attempts to verify
+     * the signatures if the JarInputStream is signed.
+     * @param in the actual input stream
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarInputStream(InputStream in) throws IOException {
+        this(in, true);
+    }
+
+    /**
+     * Creates a new <code>JarInputStream</code> and reads the optional
+     * manifest. If a manifest is present and verify is true, also attempts
+     * to verify the signatures if the JarInputStream is signed.
+     *
+     * @param in the actual input stream
+     * @param verify whether or not to verify the JarInputStream if
+     * it is signed.
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarInputStream(InputStream in, boolean verify) throws IOException {
+        super(in);
+        this.doVerify = verify;
+
+        // This implementation assumes the META-INF/MANIFEST.MF entry
+        // should be either the first or the second entry (when preceded
+        // by the dir META-INF/). It skips the META-INF/ and then
+        // "consumes" the MANIFEST.MF to initialize the Manifest object.
+        JarEntry e = (JarEntry)super.getNextEntry();
+        if (e != null && e.getName().equalsIgnoreCase("META-INF/"))
+            e = (JarEntry)super.getNextEntry();
+        first = checkManifest(e);
+    }
+
+    private JarEntry checkManifest(JarEntry e)
+        throws IOException
+    {
+        if (e != null && JarFile.MANIFEST_NAME.equalsIgnoreCase(e.getName())) {
+            man = new Manifest();
+            byte bytes[] = getBytes(new BufferedInputStream(this));
+            man.read(new ByteArrayInputStream(bytes));
+            closeEntry();
+            if (doVerify) {
+                jv = new JarVerifier(bytes);
+                mev = new ManifestEntryVerifier(man);
+            }
+            return (JarEntry)super.getNextEntry();
+        }
+        return e;
+    }
+
+    private byte[] getBytes(InputStream is)
+        throws IOException
+    {
+        byte[] buffer = new byte[8192];
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
+        int n;
+        while ((n = is.read(buffer, 0, buffer.length)) != -1) {
+            baos.write(buffer, 0, n);
+        }
+        return baos.toByteArray();
+    }
+
+    /**
+     * Returns the <code>Manifest</code> for this JAR file, or
+     * <code>null</code> if none.
+     *
+     * @return the <code>Manifest</code> for this JAR file, or
+     *         <code>null</code> if none.
+     */
+    public Manifest getManifest() {
+        return man;
+    }
+
+    /**
+     * Reads the next ZIP file entry and positions the stream at the
+     * beginning of the entry data. If verification has been enabled,
+     * any invalid signature detected while positioning the stream for
+     * the next entry will result in an exception.
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     * @exception SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     */
+    public ZipEntry getNextEntry() throws IOException {
+        JarEntry e;
+        if (first == null) {
+            e = (JarEntry)super.getNextEntry();
+            if (tryManifest) {
+                e = checkManifest(e);
+                tryManifest = false;
+            }
+        } else {
+            e = first;
+            if (first.getName().equalsIgnoreCase(JarIndex.INDEX_NAME))
+                tryManifest = true;
+            first = null;
+        }
+        if (jv != null && e != null) {
+            // At this point, we might have parsed all the meta-inf
+            // entries and have nothing to verify. If we have
+            // nothing to verify, get rid of the JarVerifier object.
+            if (jv.nothingToVerify() == true) {
+                jv = null;
+                mev = null;
+            } else {
+                jv.beginEntry(e, mev);
+            }
+        }
+        return e;
+    }
+
+    /**
+     * Reads the next JAR file entry and positions the stream at the
+     * beginning of the entry data. If verification has been enabled,
+     * any invalid signature detected while positioning the stream for
+     * the next entry will result in an exception.
+     * @return the next JAR file entry, or null if there are no more entries
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     * @exception SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     */
+    public JarEntry getNextJarEntry() throws IOException {
+        return (JarEntry)getNextEntry();
+    }
+
+    /**
+     * Reads from the current JAR file entry into an array of bytes.
+     * If <code>len</code> is not zero, the method
+     * blocks until some input is available; otherwise, no
+     * bytes are read and <code>0</code> is returned.
+     * If verification has been enabled, any invalid signature
+     * on the current entry will be reported at some point before the
+     * end of the entry is reached.
+     * @param b the buffer into which the data is read
+     * @param off the start offset in the destination array <code>b</code>
+     * @param len the maximum number of bytes to read
+     * @return the actual number of bytes read, or -1 if the end of the
+     *         entry is reached
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     * @exception SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        int n;
+        if (first == null) {
+            n = super.read(b, off, len);
+        } else {
+            n = -1;
+        }
+        if (jv != null) {
+            jv.update(n, b, off, len, mev);
+        }
+        return n;
+    }
+
+    /**
+     * Creates a new <code>JarEntry</code> (<code>ZipEntry</code>) for the
+     * specified JAR file entry name. The manifest attributes of
+     * the specified JAR file entry name will be copied to the new
+     * <CODE>JarEntry</CODE>.
+     *
+     * @param name the name of the JAR/ZIP file entry
+     * @return the <code>JarEntry</code> object just created
+     */
+    protected ZipEntry createZipEntry(String name) {
+        JarEntry e = new JarEntry(name);
+        if (man != null) {
+            e.attr = man.getAttributes(name);
+        }
+        return e;
+    }
+}
diff --git a/java/util/jar/JarOutputStream.java b/java/util/jar/JarOutputStream.java
new file mode 100644
index 0000000..3694277
--- /dev/null
+++ b/java/util/jar/JarOutputStream.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.util.zip.*;
+import java.io.*;
+
+/**
+ * The <code>JarOutputStream</code> class is used to write the contents
+ * of a JAR file to any output stream. It extends the class
+ * <code>java.util.zip.ZipOutputStream</code> with support
+ * for writing an optional <code>Manifest</code> entry. The
+ * <code>Manifest</code> can be used to specify meta-information about
+ * the JAR file and its entries.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @see     java.util.zip.ZipOutputStream
+ * @since   1.2
+ */
+public
+class JarOutputStream extends ZipOutputStream {
+    private static final int JAR_MAGIC = 0xCAFE;
+
+    /**
+     * Creates a new <code>JarOutputStream</code> with the specified
+     * <code>Manifest</code>. The manifest is written as the first
+     * entry to the output stream.
+     *
+     * @param out the actual output stream
+     * @param man the optional <code>Manifest</code>
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarOutputStream(OutputStream out, Manifest man) throws IOException {
+        super(out);
+        if (man == null) {
+            throw new NullPointerException("man");
+        }
+        ZipEntry e = new ZipEntry(JarFile.MANIFEST_NAME);
+        putNextEntry(e);
+        man.write(new BufferedOutputStream(this));
+        closeEntry();
+    }
+
+    /**
+     * Creates a new <code>JarOutputStream</code> with no manifest.
+     * @param out the actual output stream
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarOutputStream(OutputStream out) throws IOException {
+        super(out);
+    }
+
+    /**
+     * Begins writing a new JAR file entry and positions the stream
+     * to the start of the entry data. This method will also close
+     * any previous entry. The default compression method will be
+     * used if no compression method was specified for the entry.
+     * The current time will be used if the entry has no set modification
+     * time.
+     *
+     * @param ze the ZIP/JAR entry to be written
+     * @exception ZipException if a ZIP error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public void putNextEntry(ZipEntry ze) throws IOException {
+        if (firstEntry) {
+            // Make sure that extra field data for first JAR
+            // entry includes JAR magic number id.
+            byte[] edata = ze.getExtra();
+            if (edata == null || !hasMagic(edata)) {
+                if (edata == null) {
+                    edata = new byte[4];
+                } else {
+                    // Prepend magic to existing extra data
+                    byte[] tmp = new byte[edata.length + 4];
+                    System.arraycopy(edata, 0, tmp, 4, edata.length);
+                    edata = tmp;
+                }
+                set16(edata, 0, JAR_MAGIC); // extra field id
+                set16(edata, 2, 0);         // extra field size
+                ze.setExtra(edata);
+            }
+            firstEntry = false;
+        }
+        super.putNextEntry(ze);
+    }
+
+    private boolean firstEntry = true;
+
+    /*
+     * Returns true if specified byte array contains the
+     * jar magic extra field id.
+     */
+    private static boolean hasMagic(byte[] edata) {
+        try {
+            int i = 0;
+            while (i < edata.length) {
+                if (get16(edata, i) == JAR_MAGIC) {
+                    return true;
+                }
+                i += get16(edata, i + 2) + 4;
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Invalid extra field data
+        }
+        return false;
+    }
+
+    /*
+     * Fetches unsigned 16-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    private static int get16(byte[] b, int off) {
+        return Byte.toUnsignedInt(b[off]) | ( Byte.toUnsignedInt(b[off+1]) << 8);
+    }
+
+    /*
+     * Sets 16-bit value at specified offset. The bytes are assumed to
+     * be in Intel (little-endian) byte order.
+     */
+    private static void set16(byte[] b, int off, int value) {
+        b[off+0] = (byte)value;
+        b[off+1] = (byte)(value >> 8);
+    }
+}
diff --git a/java/util/jar/JarVerifier.java b/java/util/jar/JarVerifier.java
new file mode 100644
index 0000000..e0e7d55
--- /dev/null
+++ b/java/util/jar/JarVerifier.java
@@ -0,0 +1,905 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.util.zip.ZipEntry;
+
+import sun.misc.JarIndex;
+import sun.security.util.ManifestDigester;
+import sun.security.util.ManifestEntryVerifier;
+import sun.security.util.SignatureFileVerifier;
+import sun.security.util.Debug;
+
+/**
+ *
+ * @author      Roland Schemers
+ */
+class JarVerifier {
+
+    /* Are we debugging ? */
+    static final Debug debug = Debug.getInstance("jar");
+
+    /* a table mapping names to code signers, for jar entries that have
+       had their actual hashes verified */
+    private Hashtable<String, CodeSigner[]> verifiedSigners;
+
+    /* a table mapping names to code signers, for jar entries that have
+       passed the .SF/.DSA/.EC -> MANIFEST check */
+    private Hashtable<String, CodeSigner[]> sigFileSigners;
+
+    /* a hash table to hold .SF bytes */
+    private Hashtable<String, byte[]> sigFileData;
+
+    /** "queue" of pending PKCS7 blocks that we couldn't parse
+     *  until we parsed the .SF file */
+    private ArrayList<SignatureFileVerifier> pendingBlocks;
+
+    /* cache of CodeSigner objects */
+    private ArrayList<CodeSigner[]> signerCache;
+
+    /* Are we parsing a block? */
+    private boolean parsingBlockOrSF = false;
+
+    /* Are we done parsing META-INF entries? */
+    private boolean parsingMeta = true;
+
+    /* Are there are files to verify? */
+    private boolean anyToVerify = true;
+
+    /* The output stream to use when keeping track of files we are interested
+       in */
+    private ByteArrayOutputStream baos;
+
+    /** The ManifestDigester object */
+    private volatile ManifestDigester manDig;
+
+    /** the bytes for the manDig object */
+    byte manifestRawBytes[] = null;
+
+    /** controls eager signature validation */
+    boolean eagerValidation;
+
+    /** makes code source singleton instances unique to us */
+    private Object csdomain = new Object();
+
+    /** collect -DIGEST-MANIFEST values for blacklist */
+    private List<Object> manifestDigests;
+
+    public JarVerifier(byte rawBytes[]) {
+        manifestRawBytes = rawBytes;
+        sigFileSigners = new Hashtable<>();
+        verifiedSigners = new Hashtable<>();
+        sigFileData = new Hashtable<>(11);
+        pendingBlocks = new ArrayList<>();
+        baos = new ByteArrayOutputStream();
+        manifestDigests = new ArrayList<>();
+    }
+
+    /**
+     * This method scans to see which entry we're parsing and
+     * keeps various state information depending on what type of
+     * file is being parsed.
+     */
+    public void beginEntry(JarEntry je, ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (je == null)
+            return;
+
+        if (debug != null) {
+            debug.println("beginEntry "+je.getName());
+        }
+
+        String name = je.getName();
+
+        /*
+         * Assumptions:
+         * 1. The manifest should be the first entry in the META-INF directory.
+         * 2. The .SF/.DSA/.EC files follow the manifest, before any normal entries
+         * 3. Any of the following will throw a SecurityException:
+         *    a. digest mismatch between a manifest section and
+         *       the SF section.
+         *    b. digest mismatch between the actual jar entry and the manifest
+         */
+
+        if (parsingMeta) {
+            String uname = name.toUpperCase(Locale.ENGLISH);
+            if ((uname.startsWith("META-INF/") ||
+                 uname.startsWith("/META-INF/"))) {
+
+                if (je.isDirectory()) {
+                    mev.setEntry(null, je);
+                    return;
+                }
+
+                if (uname.equals(JarFile.MANIFEST_NAME) ||
+                        uname.equals(JarIndex.INDEX_NAME)) {
+                    return;
+                }
+
+                if (SignatureFileVerifier.isBlockOrSF(uname)) {
+                    /* We parse only DSA, RSA or EC PKCS7 blocks. */
+                    parsingBlockOrSF = true;
+                    baos.reset();
+                    mev.setEntry(null, je);
+                    return;
+                }
+
+                // If a META-INF entry is not MF or block or SF, they should
+                // be normal entries. According to 2 above, no more block or
+                // SF will appear. Let's doneWithMeta.
+            }
+        }
+
+        if (parsingMeta) {
+            doneWithMeta();
+        }
+
+        if (je.isDirectory()) {
+            mev.setEntry(null, je);
+            return;
+        }
+
+        // be liberal in what you accept. If the name starts with ./, remove
+        // it as we internally canonicalize it with out the ./.
+        if (name.startsWith("./"))
+            name = name.substring(2);
+
+        // be liberal in what you accept. If the name starts with /, remove
+        // it as we internally canonicalize it with out the /.
+        if (name.startsWith("/"))
+            name = name.substring(1);
+
+        // only set the jev object for entries that have a signature
+        // (either verified or not)
+        if (sigFileSigners.get(name) != null ||
+                verifiedSigners.get(name) != null) {
+            mev.setEntry(name, je);
+            return;
+        }
+
+        // don't compute the digest for this entry
+        mev.setEntry(null, je);
+
+        return;
+    }
+
+    /**
+     * update a single byte.
+     */
+
+    public void update(int b, ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (b != -1) {
+            if (parsingBlockOrSF) {
+                baos.write(b);
+            } else {
+                mev.update((byte)b);
+            }
+        } else {
+            processEntry(mev);
+        }
+    }
+
+    /**
+     * update an array of bytes.
+     */
+
+    public void update(int n, byte[] b, int off, int len,
+                       ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (n != -1) {
+            if (parsingBlockOrSF) {
+                baos.write(b, off, n);
+            } else {
+                mev.update(b, off, n);
+            }
+        } else {
+            processEntry(mev);
+        }
+    }
+
+    /**
+     * called when we reach the end of entry in one of the read() methods.
+     */
+    private void processEntry(ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (!parsingBlockOrSF) {
+            JarEntry je = mev.getEntry();
+            if ((je != null) && (je.signers == null)) {
+                je.signers = mev.verify(verifiedSigners, sigFileSigners);
+                je.certs = mapSignersToCertArray(je.signers);
+            }
+        } else {
+
+            try {
+                parsingBlockOrSF = false;
+
+                if (debug != null) {
+                    debug.println("processEntry: processing block");
+                }
+
+                String uname = mev.getEntry().getName()
+                                             .toUpperCase(Locale.ENGLISH);
+
+                if (uname.endsWith(".SF")) {
+                    String key = uname.substring(0, uname.length()-3);
+                    byte bytes[] = baos.toByteArray();
+                    // add to sigFileData in case future blocks need it
+                    sigFileData.put(key, bytes);
+                    // check pending blocks, we can now process
+                    // anyone waiting for this .SF file
+                    Iterator<SignatureFileVerifier> it = pendingBlocks.iterator();
+                    while (it.hasNext()) {
+                        SignatureFileVerifier sfv = it.next();
+                        if (sfv.needSignatureFile(key)) {
+                            if (debug != null) {
+                                debug.println(
+                                 "processEntry: processing pending block");
+                            }
+
+                            sfv.setSignatureFile(bytes);
+                            sfv.process(sigFileSigners, manifestDigests);
+                        }
+                    }
+                    return;
+                }
+
+                // now we are parsing a signature block file
+
+                String key = uname.substring(0, uname.lastIndexOf("."));
+
+                if (signerCache == null)
+                    signerCache = new ArrayList<>();
+
+                if (manDig == null) {
+                    synchronized(manifestRawBytes) {
+                        if (manDig == null) {
+                            manDig = new ManifestDigester(manifestRawBytes);
+                            manifestRawBytes = null;
+                        }
+                    }
+                }
+
+                SignatureFileVerifier sfv =
+                  new SignatureFileVerifier(signerCache,
+                                            manDig, uname, baos.toByteArray());
+
+                if (sfv.needSignatureFileBytes()) {
+                    // see if we have already parsed an external .SF file
+                    byte[] bytes = sigFileData.get(key);
+
+                    if (bytes == null) {
+                        // put this block on queue for later processing
+                        // since we don't have the .SF bytes yet
+                        // (uname, block);
+                        if (debug != null) {
+                            debug.println("adding pending block");
+                        }
+                        pendingBlocks.add(sfv);
+                        return;
+                    } else {
+                        sfv.setSignatureFile(bytes);
+                    }
+                }
+                sfv.process(sigFileSigners, manifestDigests);
+
+            } catch (IOException ioe) {
+                // e.g. sun.security.pkcs.ParsingException
+                if (debug != null) debug.println("processEntry caught: "+ioe);
+                // ignore and treat as unsigned
+            } catch (SignatureException se) {
+                if (debug != null) debug.println("processEntry caught: "+se);
+                // ignore and treat as unsigned
+            } catch (NoSuchAlgorithmException nsae) {
+                if (debug != null) debug.println("processEntry caught: "+nsae);
+                // ignore and treat as unsigned
+            } catch (CertificateException ce) {
+                if (debug != null) debug.println("processEntry caught: "+ce);
+                // ignore and treat as unsigned
+            }
+        }
+    }
+
+    // Android-changed: @deprecated tag needs a description. http://b/110781661
+    /**
+     * Return an array of java.security.cert.Certificate objects for
+     * the given file in the jar.
+     * @deprecated Deprecated.
+     */
+    @Deprecated
+    public java.security.cert.Certificate[] getCerts(String name)
+    {
+        return mapSignersToCertArray(getCodeSigners(name));
+    }
+
+    public java.security.cert.Certificate[] getCerts(JarFile jar, JarEntry entry)
+    {
+        return mapSignersToCertArray(getCodeSigners(jar, entry));
+    }
+
+    /**
+     * return an array of CodeSigner objects for
+     * the given file in the jar. this array is not cloned.
+     *
+     */
+    public CodeSigner[] getCodeSigners(String name)
+    {
+        return verifiedSigners.get(name);
+    }
+
+    public CodeSigner[] getCodeSigners(JarFile jar, JarEntry entry)
+    {
+        String name = entry.getName();
+        if (eagerValidation && sigFileSigners.get(name) != null) {
+            /*
+             * Force a read of the entry data to generate the
+             * verification hash.
+             */
+            try {
+                InputStream s = jar.getInputStream(entry);
+                byte[] buffer = new byte[1024];
+                int n = buffer.length;
+                while (n != -1) {
+                    n = s.read(buffer, 0, buffer.length);
+                }
+                s.close();
+            } catch (IOException e) {
+            }
+        }
+        return getCodeSigners(name);
+    }
+
+    /*
+     * Convert an array of signers into an array of concatenated certificate
+     * arrays.
+     */
+    private static java.security.cert.Certificate[] mapSignersToCertArray(
+        CodeSigner[] signers) {
+
+        if (signers != null) {
+            ArrayList<java.security.cert.Certificate> certChains = new ArrayList<>();
+            for (int i = 0; i < signers.length; i++) {
+                certChains.addAll(
+                    signers[i].getSignerCertPath().getCertificates());
+            }
+
+            // Convert into a Certificate[]
+            return certChains.toArray(
+                    new java.security.cert.Certificate[certChains.size()]);
+        }
+        return null;
+    }
+
+    /**
+     * returns true if there no files to verify.
+     * should only be called after all the META-INF entries
+     * have been processed.
+     */
+    boolean nothingToVerify()
+    {
+        return (anyToVerify == false);
+    }
+
+    /**
+     * called to let us know we have processed all the
+     * META-INF entries, and if we re-read one of them, don't
+     * re-process it. Also gets rid of any data structures
+     * we needed when parsing META-INF entries.
+     */
+    void doneWithMeta()
+    {
+        parsingMeta = false;
+        anyToVerify = !sigFileSigners.isEmpty();
+        baos = null;
+        sigFileData = null;
+        pendingBlocks = null;
+        signerCache = null;
+        manDig = null;
+        // MANIFEST.MF is always treated as signed and verified,
+        // move its signers from sigFileSigners to verifiedSigners.
+        if (sigFileSigners.containsKey(JarFile.MANIFEST_NAME)) {
+            CodeSigner[] codeSigners = sigFileSigners.remove(JarFile.MANIFEST_NAME);
+            verifiedSigners.put(JarFile.MANIFEST_NAME, codeSigners);
+        }
+    }
+
+    static class VerifierStream extends java.io.InputStream {
+
+        private InputStream is;
+        private JarVerifier jv;
+        private ManifestEntryVerifier mev;
+        private long numLeft;
+
+        VerifierStream(Manifest man,
+                       JarEntry je,
+                       InputStream is,
+                       JarVerifier jv) throws IOException
+        {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            // To know that null signals that the stream has been closed, we disallow
+            // it in the constructor. There's no need for anyone to pass null into this
+            // constructor, anyway.
+            if (is == null) {
+                throw new NullPointerException("is == null");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            this.is = is;
+            this.jv = jv;
+            this.mev = new ManifestEntryVerifier(man);
+            this.jv.beginEntry(je, mev);
+            this.numLeft = je.getSize();
+            if (this.numLeft == 0)
+                this.jv.update(-1, this.mev);
+        }
+
+        public int read() throws IOException
+        {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (is == null) {
+                throw new IOException("stream closed");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (numLeft > 0) {
+                int b = is.read();
+                jv.update(b, mev);
+                numLeft--;
+                if (numLeft == 0)
+                    jv.update(-1, mev);
+                return b;
+            } else {
+                return -1;
+            }
+        }
+
+        public int read(byte b[], int off, int len) throws IOException {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (is == null) {
+                throw new IOException("stream closed");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if ((numLeft > 0) && (numLeft < len)) {
+                len = (int)numLeft;
+            }
+
+            if (numLeft > 0) {
+                int n = is.read(b, off, len);
+                jv.update(n, b, off, len, mev);
+                numLeft -= n;
+                if (numLeft == 0)
+                    jv.update(-1, b, off, len, mev);
+                return n;
+            } else {
+                return -1;
+            }
+        }
+
+        public void close()
+            throws IOException
+        {
+            if (is != null)
+                is.close();
+            is = null;
+            mev = null;
+            jv = null;
+        }
+
+        public int available() throws IOException {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (is == null) {
+                throw new IOException("stream closed");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            return is.available();
+        }
+
+    }
+
+    // Extended JavaUtilJarAccess CodeSource API Support
+
+    private Map<URL, Map<CodeSigner[], CodeSource>> urlToCodeSourceMap = new HashMap<>();
+    private Map<CodeSigner[], CodeSource> signerToCodeSource = new HashMap<>();
+    private URL lastURL;
+    private Map<CodeSigner[], CodeSource> lastURLMap;
+
+    /*
+     * Create a unique mapping from codeSigner cache entries to CodeSource.
+     * In theory, multiple URLs origins could map to a single locally cached
+     * and shared JAR file although in practice there will be a single URL in use.
+     */
+    private synchronized CodeSource mapSignersToCodeSource(URL url, CodeSigner[] signers) {
+        Map<CodeSigner[], CodeSource> map;
+        if (url == lastURL) {
+            map = lastURLMap;
+        } else {
+            map = urlToCodeSourceMap.get(url);
+            if (map == null) {
+                map = new HashMap<>();
+                urlToCodeSourceMap.put(url, map);
+            }
+            lastURLMap = map;
+            lastURL = url;
+        }
+        CodeSource cs = map.get(signers);
+        if (cs == null) {
+            cs = new VerifierCodeSource(csdomain, url, signers);
+            signerToCodeSource.put(signers, cs);
+        }
+        return cs;
+    }
+
+    private CodeSource[] mapSignersToCodeSources(URL url, List<CodeSigner[]> signers, boolean unsigned) {
+        List<CodeSource> sources = new ArrayList<>();
+
+        for (int i = 0; i < signers.size(); i++) {
+            sources.add(mapSignersToCodeSource(url, signers.get(i)));
+        }
+        if (unsigned) {
+            sources.add(mapSignersToCodeSource(url, null));
+        }
+        return sources.toArray(new CodeSource[sources.size()]);
+    }
+    private CodeSigner[] emptySigner = new CodeSigner[0];
+
+    /*
+     * Match CodeSource to a CodeSigner[] in the signer cache.
+     */
+    private CodeSigner[] findMatchingSigners(CodeSource cs) {
+        if (cs instanceof VerifierCodeSource) {
+            VerifierCodeSource vcs = (VerifierCodeSource) cs;
+            if (vcs.isSameDomain(csdomain)) {
+                return ((VerifierCodeSource) cs).getPrivateSigners();
+            }
+        }
+
+        /*
+         * In practice signers should always be optimized above
+         * but this handles a CodeSource of any type, just in case.
+         */
+        CodeSource[] sources = mapSignersToCodeSources(cs.getLocation(), getJarCodeSigners(), true);
+        List<CodeSource> sourceList = new ArrayList<>();
+        for (int i = 0; i < sources.length; i++) {
+            sourceList.add(sources[i]);
+        }
+        int j = sourceList.indexOf(cs);
+        if (j != -1) {
+            CodeSigner[] match;
+            match = ((VerifierCodeSource) sourceList.get(j)).getPrivateSigners();
+            if (match == null) {
+                match = emptySigner;
+            }
+            return match;
+        }
+        return null;
+    }
+
+    /*
+     * Instances of this class hold uncopied references to internal
+     * signing data that can be compared by object reference identity.
+     */
+    private static class VerifierCodeSource extends CodeSource {
+        private static final long serialVersionUID = -9047366145967768825L;
+
+        URL vlocation;
+        CodeSigner[] vsigners;
+        java.security.cert.Certificate[] vcerts;
+        Object csdomain;
+
+        VerifierCodeSource(Object csdomain, URL location, CodeSigner[] signers) {
+            super(location, signers);
+            this.csdomain = csdomain;
+            vlocation = location;
+            vsigners = signers; // from signerCache
+        }
+
+        VerifierCodeSource(Object csdomain, URL location, java.security.cert.Certificate[] certs) {
+            super(location, certs);
+            this.csdomain = csdomain;
+            vlocation = location;
+            vcerts = certs; // from signerCache
+        }
+
+        /*
+         * All VerifierCodeSource instances are constructed based on
+         * singleton signerCache or signerCacheCert entries for each unique signer.
+         * No CodeSigner<->Certificate[] conversion is required.
+         * We use these assumptions to optimize equality comparisons.
+         */
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            if (obj instanceof VerifierCodeSource) {
+                VerifierCodeSource that = (VerifierCodeSource) obj;
+
+                /*
+                 * Only compare against other per-signer singletons constructed
+                 * on behalf of the same JarFile instance. Otherwise, compare
+                 * things the slower way.
+                 */
+                if (isSameDomain(that.csdomain)) {
+                    if (that.vsigners != this.vsigners
+                            || that.vcerts != this.vcerts) {
+                        return false;
+                    }
+                    if (that.vlocation != null) {
+                        return that.vlocation.equals(this.vlocation);
+                    } else if (this.vlocation != null) {
+                        return this.vlocation.equals(that.vlocation);
+                    } else { // both null
+                        return true;
+                    }
+                }
+            }
+            return super.equals(obj);
+        }
+
+        boolean isSameDomain(Object csdomain) {
+            return this.csdomain == csdomain;
+        }
+
+        private CodeSigner[] getPrivateSigners() {
+            return vsigners;
+        }
+
+        private java.security.cert.Certificate[] getPrivateCertificates() {
+            return vcerts;
+        }
+    }
+    private Map<String, CodeSigner[]> signerMap;
+
+    private synchronized Map<String, CodeSigner[]> signerMap() {
+        if (signerMap == null) {
+            /*
+             * Snapshot signer state so it doesn't change on us. We care
+             * only about the asserted signatures. Verification of
+             * signature validity happens via the JarEntry apis.
+             */
+            signerMap = new HashMap<>(verifiedSigners.size() + sigFileSigners.size());
+            signerMap.putAll(verifiedSigners);
+            signerMap.putAll(sigFileSigners);
+        }
+        return signerMap;
+    }
+
+    public synchronized Enumeration<String> entryNames(JarFile jar, final CodeSource[] cs) {
+        final Map<String, CodeSigner[]> map = signerMap();
+        final Iterator<Map.Entry<String, CodeSigner[]>> itor = map.entrySet().iterator();
+        boolean matchUnsigned = false;
+
+        /*
+         * Grab a single copy of the CodeSigner arrays. Check
+         * to see if we can optimize CodeSigner equality test.
+         */
+        List<CodeSigner[]> req = new ArrayList<>(cs.length);
+        for (int i = 0; i < cs.length; i++) {
+            CodeSigner[] match = findMatchingSigners(cs[i]);
+            if (match != null) {
+                if (match.length > 0) {
+                    req.add(match);
+                } else {
+                    matchUnsigned = true;
+                }
+            } else {
+                matchUnsigned = true;
+            }
+        }
+
+        final List<CodeSigner[]> signersReq = req;
+        final Enumeration<String> enum2 = (matchUnsigned) ? unsignedEntryNames(jar) : emptyEnumeration;
+
+        return new Enumeration<String>() {
+
+            String name;
+
+            public boolean hasMoreElements() {
+                if (name != null) {
+                    return true;
+                }
+
+                while (itor.hasNext()) {
+                    Map.Entry<String, CodeSigner[]> e = itor.next();
+                    if (signersReq.contains(e.getValue())) {
+                        name = e.getKey();
+                        return true;
+                    }
+                }
+                while (enum2.hasMoreElements()) {
+                    name = enum2.nextElement();
+                    return true;
+                }
+                return false;
+            }
+
+            public String nextElement() {
+                if (hasMoreElements()) {
+                    String value = name;
+                    name = null;
+                    return value;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+
+    /*
+     * Like entries() but screens out internal JAR mechanism entries
+     * and includes signed entries with no ZIP data.
+     */
+    public Enumeration<JarEntry> entries2(final JarFile jar, Enumeration<? extends ZipEntry> e) {
+        final Map<String, CodeSigner[]> map = new HashMap<>();
+        map.putAll(signerMap());
+        final Enumeration<? extends ZipEntry> enum_ = e;
+        return new Enumeration<JarEntry>() {
+
+            Enumeration<String> signers = null;
+            JarEntry entry;
+
+            public boolean hasMoreElements() {
+                if (entry != null) {
+                    return true;
+                }
+                while (enum_.hasMoreElements()) {
+                    ZipEntry ze = enum_.nextElement();
+                    if (JarVerifier.isSigningRelated(ze.getName())) {
+                        continue;
+                    }
+                    entry = jar.newEntry(ze);
+                    return true;
+                }
+                if (signers == null) {
+                    signers = Collections.enumeration(map.keySet());
+                }
+                while (signers.hasMoreElements()) {
+                    String name = signers.nextElement();
+                    entry = jar.newEntry(new ZipEntry(name));
+                    return true;
+                }
+
+                // Any map entries left?
+                return false;
+            }
+
+            public JarEntry nextElement() {
+                if (hasMoreElements()) {
+                    JarEntry je = entry;
+                    map.remove(je.getName());
+                    entry = null;
+                    return je;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+    private Enumeration<String> emptyEnumeration = new Enumeration<String>() {
+
+        public boolean hasMoreElements() {
+            return false;
+        }
+
+        public String nextElement() {
+            throw new NoSuchElementException();
+        }
+    };
+
+    // true if file is part of the signature mechanism itself
+    static boolean isSigningRelated(String name) {
+        return SignatureFileVerifier.isSigningRelated(name);
+    }
+
+    private Enumeration<String> unsignedEntryNames(JarFile jar) {
+        final Map<String, CodeSigner[]> map = signerMap();
+        final Enumeration<JarEntry> entries = jar.entries();
+        return new Enumeration<String>() {
+
+            String name;
+
+            /*
+             * Grab entries from ZIP directory but screen out
+             * metadata.
+             */
+            public boolean hasMoreElements() {
+                if (name != null) {
+                    return true;
+                }
+                while (entries.hasMoreElements()) {
+                    String value;
+                    ZipEntry e = entries.nextElement();
+                    value = e.getName();
+                    if (e.isDirectory() || isSigningRelated(value)) {
+                        continue;
+                    }
+                    if (map.get(value) == null) {
+                        name = value;
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            public String nextElement() {
+                if (hasMoreElements()) {
+                    String value = name;
+                    name = null;
+                    return value;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+    private List<CodeSigner[]> jarCodeSigners;
+
+    private synchronized List<CodeSigner[]> getJarCodeSigners() {
+        CodeSigner[] signers;
+        if (jarCodeSigners == null) {
+            HashSet<CodeSigner[]> set = new HashSet<>();
+            set.addAll(signerMap().values());
+            jarCodeSigners = new ArrayList<>();
+            jarCodeSigners.addAll(set);
+        }
+        return jarCodeSigners;
+    }
+
+    public synchronized CodeSource[] getCodeSources(JarFile jar, URL url) {
+        boolean hasUnsigned = unsignedEntryNames(jar).hasMoreElements();
+
+        return mapSignersToCodeSources(url, getJarCodeSigners(), hasUnsigned);
+    }
+
+    public CodeSource getCodeSource(URL url, String name) {
+        CodeSigner[] signers;
+
+        signers = signerMap().get(name);
+        return mapSignersToCodeSource(url, signers);
+    }
+
+    public CodeSource getCodeSource(URL url, JarFile jar, JarEntry je) {
+        CodeSigner[] signers;
+
+        return mapSignersToCodeSource(url, getCodeSigners(jar, je));
+    }
+
+    public void setEagerValidation(boolean eager) {
+        eagerValidation = eager;
+    }
+
+    public synchronized List<Object> getManifestDigests() {
+        return Collections.unmodifiableList(manifestDigests);
+    }
+
+    static CodeSource getUnsignedCS(URL url) {
+        return new VerifierCodeSource(null, url, (java.security.cert.Certificate[]) null);
+    }
+}
diff --git a/java/util/jar/Manifest.java b/java/util/jar/Manifest.java
new file mode 100644
index 0000000..976e44c
--- /dev/null
+++ b/java/util/jar/Manifest.java
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.FilterInputStream;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * The Manifest class is used to maintain Manifest entry names and their
+ * associated Attributes. There are main Manifest Attributes as well as
+ * per-entry Attributes. For information on the Manifest format, please
+ * see the
+ * <a href="../../../../technotes/guides/jar/jar.html">
+ * Manifest format specification</a>.
+ *
+ * @author  David Connelly
+ * @see     Attributes
+ * @since   1.2
+ */
+public class Manifest implements Cloneable {
+    // manifest main attributes
+    private Attributes attr = new Attributes();
+
+    // manifest entries
+    private Map<String, Attributes> entries = new HashMap<>();
+
+    /**
+     * Constructs a new, empty Manifest.
+     */
+    public Manifest() {
+    }
+
+    /**
+     * Constructs a new Manifest from the specified input stream.
+     *
+     * @param is the input stream containing manifest data
+     * @throws IOException if an I/O error has occurred
+     */
+    public Manifest(InputStream is) throws IOException {
+        read(is);
+    }
+
+    /**
+     * Constructs a new Manifest that is a copy of the specified Manifest.
+     *
+     * @param man the Manifest to copy
+     */
+    public Manifest(Manifest man) {
+        attr.putAll(man.getMainAttributes());
+        entries.putAll(man.getEntries());
+    }
+
+    /**
+     * Returns the main Attributes for the Manifest.
+     * @return the main Attributes for the Manifest
+     */
+    public Attributes getMainAttributes() {
+        return attr;
+    }
+
+    /**
+     * Returns a Map of the entries contained in this Manifest. Each entry
+     * is represented by a String name (key) and associated Attributes (value).
+     * The Map permits the {@code null} key, but no entry with a null key is
+     * created by {@link #read}, nor is such an entry written by using {@link
+     * #write}.
+     *
+     * @return a Map of the entries contained in this Manifest
+     */
+    public Map<String,Attributes> getEntries() {
+        return entries;
+    }
+
+    /**
+     * Returns the Attributes for the specified entry name.
+     * This method is defined as:
+     * <pre>
+     *      return (Attributes)getEntries().get(name)
+     * </pre>
+     * Though {@code null} is a valid {@code name}, when
+     * {@code getAttributes(null)} is invoked on a {@code Manifest}
+     * obtained from a jar file, {@code null} will be returned.  While jar
+     * files themselves do not allow {@code null}-named attributes, it is
+     * possible to invoke {@link #getEntries} on a {@code Manifest}, and
+     * on that result, invoke {@code put} with a null key and an
+     * arbitrary value.  Subsequent invocations of
+     * {@code getAttributes(null)} will return the just-{@code put}
+     * value.
+     * <p>
+     * Note that this method does not return the manifest's main attributes;
+     * see {@link #getMainAttributes}.
+     *
+     * @param name entry name
+     * @return the Attributes for the specified entry name
+     */
+    public Attributes getAttributes(String name) {
+        return getEntries().get(name);
+    }
+
+    /**
+     * Clears the main Attributes as well as the entries in this Manifest.
+     */
+    public void clear() {
+        attr.clear();
+        entries.clear();
+    }
+
+    /**
+     * Writes the Manifest to the specified OutputStream.
+     * Attributes.Name.MANIFEST_VERSION must be set in
+     * MainAttributes prior to invoking this method.
+     *
+     * @param out the output stream
+     * @exception IOException if an I/O error has occurred
+     * @see #getMainAttributes
+     */
+    public void write(OutputStream out) throws IOException {
+        DataOutputStream dos = new DataOutputStream(out);
+        // Write out the main attributes for the manifest
+        attr.writeMain(dos);
+        // Now write out the pre-entry attributes
+        Iterator<Map.Entry<String, Attributes>> it = entries.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<String, Attributes> e = it.next();
+            StringBuffer buffer = new StringBuffer("Name: ");
+            String value = e.getKey();
+            if (value != null) {
+                byte[] vb = value.getBytes("UTF8");
+                value = new String(vb, 0, 0, vb.length);
+            }
+            buffer.append(value);
+            buffer.append("\r\n");
+            make72Safe(buffer);
+            dos.writeBytes(buffer.toString());
+            e.getValue().write(dos);
+        }
+        dos.flush();
+    }
+
+    /**
+     * Adds line breaks to enforce a maximum 72 bytes per line.
+     */
+    static void make72Safe(StringBuffer line) {
+        int length = line.length();
+        if (length > 72) {
+            int index = 70;
+            while (index < length - 2) {
+                line.insert(index, "\r\n ");
+                index += 72;
+                length += 3;
+            }
+        }
+        return;
+    }
+
+    /**
+     * Reads the Manifest from the specified InputStream. The entry
+     * names and attributes read will be merged in with the current
+     * manifest entries.
+     *
+     * @param is the input stream
+     * @exception IOException if an I/O error has occurred
+     */
+    public void read(InputStream is) throws IOException {
+        // Buffered input stream for reading manifest data
+        FastInputStream fis = new FastInputStream(is);
+        // Line buffer
+        byte[] lbuf = new byte[512];
+        // Read the main attributes for the manifest
+        attr.read(fis, lbuf);
+        // Total number of entries, attributes read
+        int ecount = 0, acount = 0;
+        // Average size of entry attributes
+        int asize = 2;
+        // Now parse the manifest entries
+        int len;
+        String name = null;
+        boolean skipEmptyLines = true;
+        byte[] lastline = null;
+
+        while ((len = fis.readLine(lbuf)) != -1) {
+            if (lbuf[--len] != '\n') {
+                throw new IOException("manifest line too long");
+            }
+            if (len > 0 && lbuf[len-1] == '\r') {
+                --len;
+            }
+            if (len == 0 && skipEmptyLines) {
+                continue;
+            }
+            skipEmptyLines = false;
+
+            if (name == null) {
+                name = parseName(lbuf, len);
+                if (name == null) {
+                    throw new IOException("invalid manifest format");
+                }
+                if (fis.peek() == ' ') {
+                    // name is wrapped
+                    lastline = new byte[len - 6];
+                    System.arraycopy(lbuf, 6, lastline, 0, len - 6);
+                    continue;
+                }
+            } else {
+                // continuation line
+                byte[] buf = new byte[lastline.length + len - 1];
+                System.arraycopy(lastline, 0, buf, 0, lastline.length);
+                System.arraycopy(lbuf, 1, buf, lastline.length, len - 1);
+                if (fis.peek() == ' ') {
+                    // name is wrapped
+                    lastline = buf;
+                    continue;
+                }
+                name = new String(buf, 0, buf.length, "UTF8");
+                lastline = null;
+            }
+            Attributes attr = getAttributes(name);
+            if (attr == null) {
+                attr = new Attributes(asize);
+                entries.put(name, attr);
+            }
+            attr.read(fis, lbuf);
+            ecount++;
+            acount += attr.size();
+            //XXX: Fix for when the average is 0. When it is 0,
+            // you get an Attributes object with an initial
+            // capacity of 0, which tickles a bug in HashMap.
+            asize = Math.max(2, acount / ecount);
+
+            name = null;
+            skipEmptyLines = true;
+        }
+    }
+
+    private String parseName(byte[] lbuf, int len) {
+        if (toLower(lbuf[0]) == 'n' && toLower(lbuf[1]) == 'a' &&
+            toLower(lbuf[2]) == 'm' && toLower(lbuf[3]) == 'e' &&
+            lbuf[4] == ':' && lbuf[5] == ' ') {
+            try {
+                return new String(lbuf, 6, len - 6, "UTF8");
+            }
+            catch (Exception e) {
+            }
+        }
+        return null;
+    }
+
+    private int toLower(int c) {
+        return (c >= 'A' && c <= 'Z') ? 'a' + (c - 'A') : c;
+    }
+
+    /**
+     * Returns true if the specified Object is also a Manifest and has
+     * the same main Attributes and entries.
+     *
+     * @param o the object to be compared
+     * @return true if the specified Object is also a Manifest and has
+     * the same main Attributes and entries
+     */
+    public boolean equals(Object o) {
+        if (o instanceof Manifest) {
+            Manifest m = (Manifest)o;
+            return attr.equals(m.getMainAttributes()) &&
+                   entries.equals(m.getEntries());
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the hash code for this Manifest.
+     */
+    public int hashCode() {
+        return attr.hashCode() + entries.hashCode();
+    }
+
+    /**
+     * Returns a shallow copy of this Manifest.  The shallow copy is
+     * implemented as follows:
+     * <pre>
+     *     public Object clone() { return new Manifest(this); }
+     * </pre>
+     * @return a shallow copy of this Manifest
+     */
+    public Object clone() {
+        return new Manifest(this);
+    }
+
+    /*
+     * A fast buffered input stream for parsing manifest files.
+     */
+    static class FastInputStream extends FilterInputStream {
+        private byte buf[];
+        private int count = 0;
+        private int pos = 0;
+
+        FastInputStream(InputStream in) {
+            this(in, 8192);
+        }
+
+        FastInputStream(InputStream in, int size) {
+            super(in);
+            buf = new byte[size];
+        }
+
+        public int read() throws IOException {
+            if (pos >= count) {
+                fill();
+                if (pos >= count) {
+                    return -1;
+                }
+            }
+            return Byte.toUnsignedInt(buf[pos++]);
+        }
+
+        public int read(byte[] b, int off, int len) throws IOException {
+            int avail = count - pos;
+            if (avail <= 0) {
+                if (len >= buf.length) {
+                    return in.read(b, off, len);
+                }
+                fill();
+                avail = count - pos;
+                if (avail <= 0) {
+                    return -1;
+                }
+            }
+            if (len > avail) {
+                len = avail;
+            }
+            System.arraycopy(buf, pos, b, off, len);
+            pos += len;
+            return len;
+        }
+
+        /*
+         * Reads 'len' bytes from the input stream, or until an end-of-line
+         * is reached. Returns the number of bytes read.
+         */
+        public int readLine(byte[] b, int off, int len) throws IOException {
+            byte[] tbuf = this.buf;
+            int total = 0;
+            while (total < len) {
+                int avail = count - pos;
+                if (avail <= 0) {
+                    fill();
+                    avail = count - pos;
+                    if (avail <= 0) {
+                        return -1;
+                    }
+                }
+                int n = len - total;
+                if (n > avail) {
+                    n = avail;
+                }
+                int tpos = pos;
+                int maxpos = tpos + n;
+                while (tpos < maxpos && tbuf[tpos++] != '\n') ;
+                n = tpos - pos;
+                System.arraycopy(tbuf, pos, b, off, n);
+                off += n;
+                total += n;
+                pos = tpos;
+                if (tbuf[tpos-1] == '\n') {
+                    break;
+                }
+            }
+            return total;
+        }
+
+        public byte peek() throws IOException {
+            if (pos == count)
+                fill();
+            if (pos == count)
+                return -1; // nothing left in buffer
+            return buf[pos];
+        }
+
+        public int readLine(byte[] b) throws IOException {
+            return readLine(b, 0, b.length);
+        }
+
+        public long skip(long n) throws IOException {
+            if (n <= 0) {
+                return 0;
+            }
+            long avail = count - pos;
+            if (avail <= 0) {
+                return in.skip(n);
+            }
+            if (n > avail) {
+                n = avail;
+            }
+            pos += n;
+            return n;
+        }
+
+        public int available() throws IOException {
+            return (count - pos) + in.available();
+        }
+
+        public void close() throws IOException {
+            if (in != null) {
+                in.close();
+                in = null;
+                buf = null;
+            }
+        }
+
+        private void fill() throws IOException {
+            count = pos = 0;
+            int n = in.read(buf, 0, buf.length);
+            if (n > 0) {
+                count = n;
+            }
+        }
+    }
+}
diff --git a/java/util/jar/Pack200.java b/java/util/jar/Pack200.java
new file mode 100644
index 0000000..9211f0a
--- /dev/null
+++ b/java/util/jar/Pack200.java
@@ -0,0 +1,825 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.jar;
+
+import java.util.SortedMap;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.beans.PropertyChangeListener;
+
+
+
+
+/**
+ * Transforms a JAR file to or from a packed stream in Pack200 format.
+ * Please refer to Network Transfer Format JSR 200 Specification at
+ * <a href=http://jcp.org/aboutJava/communityprocess/review/jsr200/index.html>http://jcp.org/aboutJava/communityprocess/review/jsr200/index.html</a>
+ * <p>
+ * Typically the packer engine is used by application developers
+ * to deploy or host JAR files on a website.
+ * The unpacker  engine is used by deployment applications to
+ * transform the byte-stream back to JAR format.
+ * <p>
+ * Here is an example using  packer and unpacker:
+ * <pre>{@code
+ *    import java.util.jar.Pack200;
+ *    import java.util.jar.Pack200.*;
+ *    ...
+ *    // Create the Packer object
+ *    Packer packer = Pack200.newPacker();
+ *
+ *    // Initialize the state by setting the desired properties
+ *    Map p = packer.properties();
+ *    // take more time choosing codings for better compression
+ *    p.put(Packer.EFFORT, "7");  // default is "5"
+ *    // use largest-possible archive segments (>10% better compression).
+ *    p.put(Packer.SEGMENT_LIMIT, "-1");
+ *    // reorder files for better compression.
+ *    p.put(Packer.KEEP_FILE_ORDER, Packer.FALSE);
+ *    // smear modification times to a single value.
+ *    p.put(Packer.MODIFICATION_TIME, Packer.LATEST);
+ *    // ignore all JAR deflation requests,
+ *    // transmitting a single request to use "store" mode.
+ *    p.put(Packer.DEFLATE_HINT, Packer.FALSE);
+ *    // discard debug attributes
+ *    p.put(Packer.CODE_ATTRIBUTE_PFX+"LineNumberTable", Packer.STRIP);
+ *    // throw an error if an attribute is unrecognized
+ *    p.put(Packer.UNKNOWN_ATTRIBUTE, Packer.ERROR);
+ *    // pass one class file uncompressed:
+ *    p.put(Packer.PASS_FILE_PFX+0, "mutants/Rogue.class");
+ *    try {
+ *        JarFile jarFile = new JarFile("/tmp/testref.jar");
+ *        FileOutputStream fos = new FileOutputStream("/tmp/test.pack");
+ *        // Call the packer
+ *        packer.pack(jarFile, fos);
+ *        jarFile.close();
+ *        fos.close();
+ *
+ *        File f = new File("/tmp/test.pack");
+ *        FileOutputStream fostream = new FileOutputStream("/tmp/test.jar");
+ *        JarOutputStream jostream = new JarOutputStream(fostream);
+ *        Unpacker unpacker = Pack200.newUnpacker();
+ *        // Call the unpacker
+ *        unpacker.unpack(f, jostream);
+ *        // Must explicitly close the output.
+ *        jostream.close();
+ *    } catch (IOException ioe) {
+ *        ioe.printStackTrace();
+ *    }
+ * }</pre>
+ * <p>
+ * A Pack200 file compressed with gzip can be hosted on HTTP/1.1 web servers.
+ * The deployment applications can use "Accept-Encoding=pack200-gzip". This
+ * indicates to the server that the client application desires a version of
+ * the file encoded with Pack200 and further compressed with gzip. Please
+ * refer to  <a href="{@docRoot}/../technotes/guides/deployment/deployment-guide/pack200.html">Java Deployment Guide</a> for more details and
+ * techniques.
+ * <p>
+ * Unless otherwise noted, passing a <tt>null</tt> argument to a constructor or
+ * method in this class will cause a {@link NullPointerException} to be thrown.
+ *
+ * @author John Rose
+ * @author Kumar Srinivasan
+ * @since 1.5
+ */
+public abstract class Pack200 {
+    private Pack200() {} //prevent instantiation
+
+    // Static methods of the Pack200 class.
+    /**
+     * Obtain new instance of a class that implements Packer.
+     * <ul>
+     * <li><p>If the system property <tt>java.util.jar.Pack200.Packer</tt>
+     * is defined, then the value is taken to be the fully-qualified name
+     * of a concrete implementation class, which must implement Packer.
+     * This class is loaded and instantiated.  If this process fails
+     * then an unspecified error is thrown.</p></li>
+     *
+     * <li><p>If an implementation has not been specified with the system
+     * property, then the system-default implementation class is instantiated,
+     * and the result is returned.</p></li>
+     * </ul>
+     *
+     * <p>Note:  The returned object is not guaranteed to operate
+     * correctly if multiple threads use it at the same time.
+     * A multi-threaded application should either allocate multiple
+     * packer engines, or else serialize use of one engine with a lock.
+     *
+     * @return  A newly allocated Packer engine.
+     */
+    public synchronized static Packer newPacker() {
+        return (Packer) newInstance(PACK_PROVIDER);
+    }
+
+
+    /**
+     * Obtain new instance of a class that implements Unpacker.
+     * <ul>
+     * <li><p>If the system property <tt>java.util.jar.Pack200.Unpacker</tt>
+     * is defined, then the value is taken to be the fully-qualified
+     * name of a concrete implementation class, which must implement Unpacker.
+     * The class is loaded and instantiated.  If this process fails
+     * then an unspecified error is thrown.</p></li>
+     *
+     * <li><p>If an implementation has not been specified with the
+     * system property, then the system-default implementation class
+     * is instantiated, and the result is returned.</p></li>
+     * </ul>
+     *
+     * <p>Note:  The returned object is not guaranteed to operate
+     * correctly if multiple threads use it at the same time.
+     * A multi-threaded application should either allocate multiple
+     * unpacker engines, or else serialize use of one engine with a lock.
+     *
+     * @return  A newly allocated Unpacker engine.
+     */
+
+    public static Unpacker newUnpacker() {
+        return (Unpacker) newInstance(UNPACK_PROVIDER);
+    }
+
+    // Interfaces
+    /**
+     * The packer engine applies various transformations to the input JAR file,
+     * making the pack stream highly compressible by a compressor such as
+     * gzip or zip. An instance of the engine can be obtained
+     * using {@link #newPacker}.
+
+     * The high degree of compression is achieved
+     * by using a number of techniques described in the JSR 200 specification.
+     * Some of the techniques are sorting, re-ordering and co-location of the
+     * constant pool.
+     * <p>
+     * The pack engine is initialized to an initial state as described
+     * by their properties below.
+     * The initial state can be manipulated by getting the
+     * engine properties (using {@link #properties}) and storing
+     * the modified properties on the map.
+     * The resource files will be passed through with no changes at all.
+     * The class files will not contain identical bytes, since the unpacker
+     * is free to change minor class file features such as constant pool order.
+     * However, the class files will be semantically identical,
+     * as specified in
+     * <cite>The Java&trade; Virtual Machine Specification</cite>.
+     * <p>
+     * By default, the packer does not change the order of JAR elements.
+     * Also, the modification time and deflation hint of each
+     * JAR element is passed unchanged.
+     * (Any other ZIP-archive information, such as extra attributes
+     * giving Unix file permissions, are lost.)
+     * <p>
+     * Note that packing and unpacking a JAR will in general alter the
+     * bytewise contents of classfiles in the JAR.  This means that packing
+     * and unpacking will in general invalidate any digital signatures
+     * which rely on bytewise images of JAR elements.  In order both to sign
+     * and to pack a JAR, you must first pack and unpack the JAR to
+     * "normalize" it, then compute signatures on the unpacked JAR elements,
+     * and finally repack the signed JAR.
+     * Both packing steps should
+     * use precisely the same options, and the segment limit may also
+     * need to be set to "-1", to prevent accidental variation of segment
+     * boundaries as class file sizes change slightly.
+     * <p>
+     * (Here's why this works:  Any reordering the packer does
+     * of any classfile structures is idempotent, so the second packing
+     * does not change the orderings produced by the first packing.
+     * Also, the unpacker is guaranteed by the JSR 200 specification
+     * to produce a specific bytewise image for any given transmission
+     * ordering of archive elements.)
+     * <p>
+     * In order to maintain backward compatibility, the pack file's version is
+     * set to accommodate the class files present in the input JAR file. In
+     * other words, the pack file version will be the latest, if the class files
+     * are the latest and conversely the pack file version will be the oldest
+     * if the class file versions are also the oldest. For intermediate class
+     * file versions the corresponding pack file version will be used.
+     * For example:
+     *    If the input JAR-files are solely comprised of 1.5  (or  lesser)
+     * class files, a 1.5 compatible pack file is  produced. This will also be
+     * the case for archives that have no class files.
+     *    If the input JAR-files contains a 1.6 class file, then the pack file
+     * version will be set to 1.6.
+     * <p>
+     * Note: Unless otherwise noted, passing a <tt>null</tt> argument to a
+     * constructor or method in this class will cause a {@link NullPointerException}
+     * to be thrown.
+     * <p>
+     * @since 1.5
+     */
+    public interface Packer {
+        /**
+         * This property is a numeral giving the estimated target size N
+         * (in bytes) of each archive segment.
+         * If a single input file requires more than N bytes,
+         * it will be given its own archive segment.
+         * <p>
+         * As a special case, a value of -1 will produce a single large
+         * segment with all input files, while a value of 0 will
+         * produce one segment for each class.
+         * Larger archive segments result in less fragmentation and
+         * better compression, but processing them requires more memory.
+         * <p>
+         * The size of each segment is estimated by counting the size of each
+         * input file to be transmitted in the segment, along with the size
+         * of its name and other transmitted properties.
+         * <p>
+         * The default is -1, which means the packer will always create a single
+         * segment output file. In cases where extremely large output files are
+         * generated, users are strongly encouraged to use segmenting or break
+         * up the input file into smaller JARs.
+         * <p>
+         * A 10Mb JAR packed without this limit will
+         * typically pack about 10% smaller, but the packer may require
+         * a larger Java heap (about ten times the segment limit).
+         */
+        String SEGMENT_LIMIT    = "pack.segment.limit";
+
+        /**
+         * If this property is set to {@link #TRUE}, the packer will transmit
+         * all elements in their original order within the source archive.
+         * <p>
+         * If it is set to {@link #FALSE}, the packer may reorder elements,
+         * and also remove JAR directory entries, which carry no useful
+         * information for Java applications.
+         * (Typically this enables better compression.)
+         * <p>
+         * The default is {@link #TRUE}, which preserves the input information,
+         * but may cause the transmitted archive to be larger than necessary.
+         */
+        String KEEP_FILE_ORDER = "pack.keep.file.order";
+
+
+        /**
+         * If this property is set to a single decimal digit, the packer will
+         * use the indicated amount of effort in compressing the archive.
+         * Level 1 may produce somewhat larger size and faster compression speed,
+         * while level 9 will take much longer but may produce better compression.
+         * <p>
+         * The special value 0 instructs the packer to copy through the
+         * original JAR file directly, with no compression.  The JSR 200
+         * standard requires any unpacker to understand this special case
+         * as a pass-through of the entire archive.
+         * <p>
+         * The default is 5, investing a modest amount of time to
+         * produce reasonable compression.
+         */
+        String EFFORT           = "pack.effort";
+
+        /**
+         * If this property is set to {@link #TRUE} or {@link #FALSE}, the packer
+         * will set the deflation hint accordingly in the output archive, and
+         * will not transmit the individual deflation hints of archive elements.
+         * <p>
+         * If this property is set to the special string {@link #KEEP}, the packer
+         * will attempt to determine an independent deflation hint for each
+         * available element of the input archive, and transmit this hint separately.
+         * <p>
+         * The default is {@link #KEEP}, which preserves the input information,
+         * but may cause the transmitted archive to be larger than necessary.
+         * <p>
+         * It is up to the unpacker implementation
+         * to take action upon the hint to suitably compress the elements of
+         * the resulting unpacked jar.
+         * <p>
+         * The deflation hint of a ZIP or JAR element indicates
+         * whether the element was deflated or stored directly.
+         */
+        String DEFLATE_HINT     = "pack.deflate.hint";
+
+        /**
+         * If this property is set to the special string {@link #LATEST},
+         * the packer will attempt to determine the latest modification time,
+         * among all the available entries in the original archive or the latest
+         * modification time of all the available entries in each segment.
+         * This single value will be transmitted as part of the segment and applied
+         * to all the entries in each segment, {@link #SEGMENT_LIMIT}.
+         * <p>
+         * This can marginally decrease the transmitted size of the
+         * archive, at the expense of setting all installed files to a single
+         * date.
+         * <p>
+         * If this property is set to the special string {@link #KEEP},
+         * the packer transmits a separate modification time for each input
+         * element.
+         * <p>
+         * The default is {@link #KEEP}, which preserves the input information,
+         * but may cause the transmitted archive to be larger than necessary.
+         * <p>
+         * It is up to the unpacker implementation to take action to suitably
+         * set the modification time of each element of its output file.
+         * @see #SEGMENT_LIMIT
+         */
+        String MODIFICATION_TIME        = "pack.modification.time";
+
+        /**
+         * Indicates that a file should be passed through bytewise, with no
+         * compression.  Multiple files may be specified by specifying
+         * additional properties with distinct strings appended, to
+         * make a family of properties with the common prefix.
+         * <p>
+         * There is no pathname transformation, except
+         * that the system file separator is replaced by the JAR file
+         * separator '/'.
+         * <p>
+         * The resulting file names must match exactly as strings with their
+         * occurrences in the JAR file.
+         * <p>
+         * If a property value is a directory name, all files under that
+         * directory will be passed also.
+         * <p>
+         * Examples:
+         * <pre>{@code
+         *     Map p = packer.properties();
+         *     p.put(PASS_FILE_PFX+0, "mutants/Rogue.class");
+         *     p.put(PASS_FILE_PFX+1, "mutants/Wolverine.class");
+         *     p.put(PASS_FILE_PFX+2, "mutants/Storm.class");
+         *     # Pass all files in an entire directory hierarchy:
+         *     p.put(PASS_FILE_PFX+3, "police/");
+         * }</pre>
+         */
+        String PASS_FILE_PFX            = "pack.pass.file.";
+
+        /// Attribute control.
+
+        /**
+         * Indicates the action to take when a class-file containing an unknown
+         * attribute is encountered.  Possible values are the strings {@link #ERROR},
+         * {@link #STRIP}, and {@link #PASS}.
+         * <p>
+         * The string {@link #ERROR} means that the pack operation
+         * as a whole will fail, with an exception of type <code>IOException</code>.
+         * The string
+         * {@link #STRIP} means that the attribute will be dropped.
+         * The string
+         * {@link #PASS} means that the whole class-file will be passed through
+         * (as if it were a resource file) without compression, with  a suitable warning.
+         * This is the default value for this property.
+         * <p>
+         * Examples:
+         * <pre>{@code
+         *     Map p = pack200.getProperties();
+         *     p.put(UNKNOWN_ATTRIBUTE, ERROR);
+         *     p.put(UNKNOWN_ATTRIBUTE, STRIP);
+         *     p.put(UNKNOWN_ATTRIBUTE, PASS);
+         * }</pre>
+         */
+        String UNKNOWN_ATTRIBUTE        = "pack.unknown.attribute";
+
+        /**
+         * When concatenated with a class attribute name,
+         * indicates the format of that attribute,
+         * using the layout language specified in the JSR 200 specification.
+         * <p>
+         * For example, the effect of this option is built in:
+         * <code>pack.class.attribute.SourceFile=RUH</code>.
+         * <p>
+         * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS} are
+         * also allowed, with the same meaning as {@link #UNKNOWN_ATTRIBUTE}.
+         * This provides a way for users to request that specific attributes be
+         * refused, stripped, or passed bitwise (with no class compression).
+         * <p>
+         * Code like this might be used to support attributes for JCOV:
+         * <pre><code>
+         *     Map p = packer.properties();
+         *     p.put(CODE_ATTRIBUTE_PFX+"CoverageTable",       "NH[PHHII]");
+         *     p.put(CODE_ATTRIBUTE_PFX+"CharacterRangeTable", "NH[PHPOHIIH]");
+         *     p.put(CLASS_ATTRIBUTE_PFX+"SourceID",           "RUH");
+         *     p.put(CLASS_ATTRIBUTE_PFX+"CompilationID",      "RUH");
+         * </code></pre>
+         * <p>
+         * Code like this might be used to strip debugging attributes:
+         * <pre><code>
+         *     Map p = packer.properties();
+         *     p.put(CODE_ATTRIBUTE_PFX+"LineNumberTable",    STRIP);
+         *     p.put(CODE_ATTRIBUTE_PFX+"LocalVariableTable", STRIP);
+         *     p.put(CLASS_ATTRIBUTE_PFX+"SourceFile",        STRIP);
+         * </code></pre>
+         */
+        String CLASS_ATTRIBUTE_PFX      = "pack.class.attribute.";
+
+        /**
+         * When concatenated with a field attribute name,
+         * indicates the format of that attribute.
+         * For example, the effect of this option is built in:
+         * <code>pack.field.attribute.Deprecated=</code>.
+         * The special strings {@link #ERROR}, {@link #STRIP}, and
+         * {@link #PASS} are also allowed.
+         * @see #CLASS_ATTRIBUTE_PFX
+         */
+        String FIELD_ATTRIBUTE_PFX      = "pack.field.attribute.";
+
+        /**
+         * When concatenated with a method attribute name,
+         * indicates the format of that attribute.
+         * For example, the effect of this option is built in:
+         * <code>pack.method.attribute.Exceptions=NH[RCH]</code>.
+         * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS}
+         * are also allowed.
+         * @see #CLASS_ATTRIBUTE_PFX
+         */
+        String METHOD_ATTRIBUTE_PFX     = "pack.method.attribute.";
+
+        /**
+         * When concatenated with a code attribute name,
+         * indicates the format of that attribute.
+         * For example, the effect of this option is built in:
+         * <code>pack.code.attribute.LocalVariableTable=NH[PHOHRUHRSHH]</code>.
+         * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS}
+         * are also allowed.
+         * @see #CLASS_ATTRIBUTE_PFX
+         */
+        String CODE_ATTRIBUTE_PFX       = "pack.code.attribute.";
+
+        /**
+         * The unpacker's progress as a percentage, as periodically
+         * updated by the unpacker.
+         * Values of 0 - 100 are normal, and -1 indicates a stall.
+         * Progress can be monitored by polling the value of this
+         * property.
+         * <p>
+         * At a minimum, the unpacker must set progress to 0
+         * at the beginning of a packing operation, and to 100
+         * at the end.
+         */
+        String PROGRESS                 = "pack.progress";
+
+        /** The string "keep", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         * @see #MODIFICATION_TIME
+         */
+        String KEEP  = "keep";
+
+        /** The string "pass", a possible value for certain properties.
+         * @see #UNKNOWN_ATTRIBUTE
+         * @see #CLASS_ATTRIBUTE_PFX
+         * @see #FIELD_ATTRIBUTE_PFX
+         * @see #METHOD_ATTRIBUTE_PFX
+         * @see #CODE_ATTRIBUTE_PFX
+         */
+        String PASS  = "pass";
+
+        /** The string "strip", a possible value for certain properties.
+         * @see #UNKNOWN_ATTRIBUTE
+         * @see #CLASS_ATTRIBUTE_PFX
+         * @see #FIELD_ATTRIBUTE_PFX
+         * @see #METHOD_ATTRIBUTE_PFX
+         * @see #CODE_ATTRIBUTE_PFX
+         */
+        String STRIP = "strip";
+
+        /** The string "error", a possible value for certain properties.
+         * @see #UNKNOWN_ATTRIBUTE
+         * @see #CLASS_ATTRIBUTE_PFX
+         * @see #FIELD_ATTRIBUTE_PFX
+         * @see #METHOD_ATTRIBUTE_PFX
+         * @see #CODE_ATTRIBUTE_PFX
+         */
+        String ERROR = "error";
+
+        /** The string "true", a possible value for certain properties.
+         * @see #KEEP_FILE_ORDER
+         * @see #DEFLATE_HINT
+         */
+        String TRUE = "true";
+
+        /** The string "false", a possible value for certain properties.
+         * @see #KEEP_FILE_ORDER
+         * @see #DEFLATE_HINT
+         */
+        String FALSE = "false";
+
+        /** The string "latest", a possible value for certain properties.
+         * @see #MODIFICATION_TIME
+         */
+        String LATEST = "latest";
+
+        /**
+         * Get the set of this engine's properties.
+         * This set is a "live view", so that changing its
+         * contents immediately affects the Packer engine, and
+         * changes from the engine (such as progress indications)
+         * are immediately visible in the map.
+         *
+         * <p>The property map may contain pre-defined implementation
+         * specific and default properties.  Users are encouraged to
+         * read the information and fully understand the implications,
+         * before modifying pre-existing properties.
+         * <p>
+         * Implementation specific properties are prefixed with a
+         * package name associated with the implementor, beginning
+         * with <tt>com.</tt> or a similar prefix.
+         * All property names beginning with <tt>pack.</tt> and
+         * <tt>unpack.</tt> are reserved for use by this API.
+         * <p>
+         * Unknown properties may be ignored or rejected with an
+         * unspecified error, and invalid entries may cause an
+         * unspecified error to be thrown.
+         *
+         * <p>
+         * The returned map implements all optional {@link SortedMap} operations
+         * @return A sorted association of property key strings to property
+         * values.
+         */
+        SortedMap<String,String> properties();
+
+        /**
+         * Takes a JarFile and converts it into a Pack200 archive.
+         * <p>
+         * Closes its input but not its output.  (Pack200 archives are appendable.)
+         * @param in a JarFile
+         * @param out an OutputStream
+         * @exception IOException if an error is encountered.
+         */
+        void pack(JarFile in, OutputStream out) throws IOException ;
+
+        /**
+         * Takes a JarInputStream and converts it into a Pack200 archive.
+         * <p>
+         * Closes its input but not its output.  (Pack200 archives are appendable.)
+         * <p>
+         * The modification time and deflation hint attributes are not available,
+         * for the JAR manifest file and its containing directory.
+         *
+         * @see #MODIFICATION_TIME
+         * @see #DEFLATE_HINT
+         * @param in a JarInputStream
+         * @param out an OutputStream
+         * @exception IOException if an error is encountered.
+         */
+        void pack(JarInputStream in, OutputStream out) throws IOException ;
+
+        /**
+         * Registers a listener for PropertyChange events on the properties map.
+         * This is typically used by applications to update a progress bar.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+
+         * @see #properties
+         * @see #PROGRESS
+         * @param listener  An object to be invoked when a property is changed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         *             Applications that need to monitor progress of the packer
+         *             can poll the value of the {@link #PROGRESS PROGRESS}
+         *             property instead.
+         */
+        @Deprecated
+        default void addPropertyChangeListener(PropertyChangeListener listener) {
+        }
+
+        /**
+         * Remove a listener for PropertyChange events, added by
+         * the {@link #addPropertyChangeListener}.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+         *
+         * @see #addPropertyChangeListener
+         * @param listener  The PropertyChange listener to be removed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         */
+        @Deprecated
+        default void removePropertyChangeListener(PropertyChangeListener listener) {
+        }
+    }
+
+    /**
+     * The unpacker engine converts the packed stream to a JAR file.
+     * An instance of the engine can be obtained
+     * using {@link #newUnpacker}.
+     * <p>
+     * Every JAR file produced by this engine will include the string
+     * "<tt>PACK200</tt>" as a zip file comment.
+     * This allows a deployer to detect if a JAR archive was packed and unpacked.
+     * <p>
+     * Note: Unless otherwise noted, passing a <tt>null</tt> argument to a
+     * constructor or method in this class will cause a {@link NullPointerException}
+     * to be thrown.
+     * <p>
+     * This version of the unpacker is compatible with all previous versions.
+     * @since 1.5
+     */
+    public interface Unpacker {
+
+        /** The string "keep", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         */
+        String KEEP  = "keep";
+
+        /** The string "true", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         */
+        String TRUE = "true";
+
+        /** The string "false", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         */
+        String FALSE = "false";
+
+        /**
+         * Property indicating that the unpacker should
+         * ignore all transmitted values for DEFLATE_HINT,
+         * replacing them by the given value, {@link #TRUE} or {@link #FALSE}.
+         * The default value is the special string {@link #KEEP},
+         * which asks the unpacker to preserve all transmitted
+         * deflation hints.
+         */
+        String DEFLATE_HINT      = "unpack.deflate.hint";
+
+
+
+        /**
+         * The unpacker's progress as a percentage, as periodically
+         * updated by the unpacker.
+         * Values of 0 - 100 are normal, and -1 indicates a stall.
+         * Progress can be monitored by polling the value of this
+         * property.
+         * <p>
+         * At a minimum, the unpacker must set progress to 0
+         * at the beginning of a packing operation, and to 100
+         * at the end.
+         */
+        String PROGRESS         = "unpack.progress";
+
+        /**
+         * Get the set of this engine's properties. This set is
+         * a "live view", so that changing its
+         * contents immediately affects the Packer engine, and
+         * changes from the engine (such as progress indications)
+         * are immediately visible in the map.
+         *
+         * <p>The property map may contain pre-defined implementation
+         * specific and default properties.  Users are encouraged to
+         * read the information and fully understand the implications,
+         * before modifying pre-existing properties.
+         * <p>
+         * Implementation specific properties are prefixed with a
+         * package name associated with the implementor, beginning
+         * with <tt>com.</tt> or a similar prefix.
+         * All property names beginning with <tt>pack.</tt> and
+         * <tt>unpack.</tt> are reserved for use by this API.
+         * <p>
+         * Unknown properties may be ignored or rejected with an
+         * unspecified error, and invalid entries may cause an
+         * unspecified error to be thrown.
+         *
+         * @return A sorted association of option key strings to option values.
+         */
+        SortedMap<String,String> properties();
+
+        /**
+         * Read a Pack200 archive, and write the encoded JAR to
+         * a JarOutputStream.
+         * The entire contents of the input stream will be read.
+         * It may be more efficient to read the Pack200 archive
+         * to a file and pass the File object, using the alternate
+         * method described below.
+         * <p>
+         * Closes its input but not its output.  (The output can accumulate more elements.)
+         * @param in an InputStream.
+         * @param out a JarOutputStream.
+         * @exception IOException if an error is encountered.
+         */
+        void unpack(InputStream in, JarOutputStream out) throws IOException;
+
+        /**
+         * Read a Pack200 archive, and write the encoded JAR to
+         * a JarOutputStream.
+         * <p>
+         * Does not close its output.  (The output can accumulate more elements.)
+         * @param in a File.
+         * @param out a JarOutputStream.
+         * @exception IOException if an error is encountered.
+         */
+        void unpack(File in, JarOutputStream out) throws IOException;
+
+        /**
+         * Registers a listener for PropertyChange events on the properties map.
+         * This is typically used by applications to update a progress bar.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+         *
+         * @see #properties
+         * @see #PROGRESS
+         * @param listener  An object to be invoked when a property is changed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         *             Applications that need to monitor progress of the
+         *             unpacker can poll the value of the {@link #PROGRESS
+         *             PROGRESS} property instead.
+         */
+        @Deprecated
+        default void addPropertyChangeListener(PropertyChangeListener listener) {
+        }
+
+        /**
+         * Remove a listener for PropertyChange events, added by
+         * the {@link #addPropertyChangeListener}.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+         *
+         * @see #addPropertyChangeListener
+         * @param listener  The PropertyChange listener to be removed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         */
+        @Deprecated
+        default void removePropertyChangeListener(PropertyChangeListener listener) {
+        }
+    }
+
+    // Private stuff....
+
+    private static final String PACK_PROVIDER = "java.util.jar.Pack200.Packer";
+    private static final String UNPACK_PROVIDER = "java.util.jar.Pack200.Unpacker";
+
+    private static Class<?> packerImpl;
+    private static Class<?> unpackerImpl;
+
+    private synchronized static Object newInstance(String prop) {
+        String implName = "(unknown)";
+        try {
+            Class<?> impl = (PACK_PROVIDER.equals(prop))? packerImpl: unpackerImpl;
+            if (impl == null) {
+                // The first time, we must decide which class to use.
+                implName = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(prop,""));
+                if (implName != null && !implName.equals(""))
+                    impl = Class.forName(implName);
+                // Android-changed: Remove default Packer Impl.
+                //
+                // else if (PACK_PROVIDER.equals(prop))
+                //     impl = com.sun.java.util.jar.pack.PackerImpl.class;
+                // else
+                //    impl = com.sun.java.util.jar.pack.UnpackerImpl.class;
+            }
+            // We have a class.  Now instantiate it.
+            return impl.newInstance();
+        } catch (ClassNotFoundException e) {
+            throw new Error("Class not found: " + implName +
+                                ":\ncheck property " + prop +
+                                " in your properties file.", e);
+        } catch (InstantiationException e) {
+            throw new Error("Could not instantiate: " + implName +
+                                ":\ncheck property " + prop +
+                                " in your properties file.", e);
+        } catch (IllegalAccessException e) {
+            throw new Error("Cannot access class: " + implName +
+                                ":\ncheck property " + prop +
+                                " in your properties file.", e);
+        }
+    }
+
+}
diff --git a/java/util/logging/ConsoleHandler.java b/java/util/logging/ConsoleHandler.java
new file mode 100644
index 0000000..b791547
--- /dev/null
+++ b/java/util/logging/ConsoleHandler.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * This <tt>Handler</tt> publishes log records to <tt>System.err</tt>.
+ * By default the <tt>SimpleFormatter</tt> is used to generate brief summaries.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>ConsoleHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where {@code <handler-name>}
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.INFO</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.SimpleFormatter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code ConsoleHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.ConsoleHandler.level=INFO </li>
+ * <li>   java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * @since 1.4
+ */
+public class ConsoleHandler extends StreamHandler {
+    // Private method to configure a ConsoleHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        setLevel(manager.getLevelProperty(cname +".level", Level.INFO));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new SimpleFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+    }
+
+    /**
+     * Create a <tt>ConsoleHandler</tt> for <tt>System.err</tt>.
+     * <p>
+     * The <tt>ConsoleHandler</tt> is configured based on
+     * <tt>LogManager</tt> properties (or their default values).
+     *
+     */
+    public ConsoleHandler() {
+        sealed = false;
+        configure();
+        setOutputStream(System.err);
+        sealed = true;
+    }
+
+    /**
+     * Publish a <tt>LogRecord</tt>.
+     * <p>
+     * The logging request was made initially to a <tt>Logger</tt> object,
+     * which initialized the <tt>LogRecord</tt> and forwarded it here.
+     * <p>
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public void publish(LogRecord record) {
+        super.publish(record);
+        flush();
+    }
+
+    /**
+     * Override <tt>StreamHandler.close</tt> to do a flush but not
+     * to close the output stream.  That is, we do <b>not</b>
+     * close <tt>System.err</tt>.
+     */
+    @Override
+    public void close() {
+        flush();
+    }
+}
diff --git a/java/util/logging/ErrorManager.java b/java/util/logging/ErrorManager.java
new file mode 100644
index 0000000..1aaba4c
--- /dev/null
+++ b/java/util/logging/ErrorManager.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * ErrorManager objects can be attached to Handlers to process
+ * any error that occurs on a Handler during Logging.
+ * <p>
+ * When processing logging output, if a Handler encounters problems
+ * then rather than throwing an Exception back to the issuer of
+ * the logging call (who is unlikely to be interested) the Handler
+ * should call its associated ErrorManager.
+ */
+
+public class ErrorManager {
+   private boolean reported = false;
+
+    /*
+     * We declare standard error codes for important categories of errors.
+     */
+
+    /**
+     * GENERIC_FAILURE is used for failure that don't fit
+     * into one of the other categories.
+     */
+    public final static int GENERIC_FAILURE = 0;
+    /**
+     * WRITE_FAILURE is used when a write to an output stream fails.
+     */
+    public final static int WRITE_FAILURE = 1;
+    /**
+     * FLUSH_FAILURE is used when a flush to an output stream fails.
+     */
+    public final static int FLUSH_FAILURE = 2;
+    /**
+     * CLOSE_FAILURE is used when a close of an output stream fails.
+     */
+    public final static int CLOSE_FAILURE = 3;
+    /**
+     * OPEN_FAILURE is used when an open of an output stream fails.
+     */
+    public final static int OPEN_FAILURE = 4;
+    /**
+     * FORMAT_FAILURE is used when formatting fails for any reason.
+     */
+    public final static int FORMAT_FAILURE = 5;
+
+    /**
+     * The error method is called when a Handler failure occurs.
+     * <p>
+     * This method may be overridden in subclasses.  The default
+     * behavior in this base class is that the first call is
+     * reported to System.err, and subsequent calls are ignored.
+     *
+     * @param msg    a descriptive string (may be null)
+     * @param ex     an exception (may be null)
+     * @param code   an error code defined in ErrorManager
+     */
+    public synchronized void error(String msg, Exception ex, int code) {
+        if (reported) {
+            // We only report the first error, to avoid clogging
+            // the screen.
+            return;
+        }
+        reported = true;
+        String text = "java.util.logging.ErrorManager: " + code;
+        if (msg != null) {
+            text = text + ": " + msg;
+        }
+        System.err.println(text);
+        if (ex != null) {
+            ex.printStackTrace();
+        }
+    }
+}
diff --git a/java/util/logging/FileHandler.java b/java/util/logging/FileHandler.java
new file mode 100644
index 0000000..24a7c75
--- /dev/null
+++ b/java/util/logging/FileHandler.java
@@ -0,0 +1,746 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+import static java.nio.file.StandardOpenOption.APPEND;
+import static java.nio.file.StandardOpenOption.CREATE_NEW;
+import static java.nio.file.StandardOpenOption.WRITE;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.channels.FileChannel;
+import java.nio.channels.OverlappingFileLockException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Simple file logging <tt>Handler</tt>.
+ * <p>
+ * The <tt>FileHandler</tt> can either write to a specified file,
+ * or it can write to a rotating set of files.
+ * <p>
+ * For a rotating set of files, as each file reaches a given size
+ * limit, it is closed, rotated out, and a new file opened.
+ * Successively older files are named by adding "0", "1", "2",
+ * etc. into the base filename.
+ * <p>
+ * By default buffering is enabled in the IO libraries but each log
+ * record is flushed out when it is complete.
+ * <p>
+ * By default the <tt>XMLFormatter</tt> class is used for formatting.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>FileHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.ALL</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.XMLFormatter</tt>) </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * <li>   &lt;handler-name&gt;.limit
+ *        specifies an approximate maximum amount to write (in bytes)
+ *        to any one file.  If this is zero, then there is no limit.
+ *        (Defaults to no limit). </li>
+ * <li>   &lt;handler-name&gt;.count
+ *        specifies how many output files to cycle through (defaults to 1). </li>
+ * <li>   &lt;handler-name&gt;.pattern
+ *        specifies a pattern for generating the output file name.  See
+ *        below for details. (Defaults to "%h/java%u.log"). </li>
+ * <li>   &lt;handler-name&gt;.append
+ *        specifies whether the FileHandler should append onto
+ *        any existing files (defaults to false). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code FileHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.FileHandler.level=INFO </li>
+ * <li>   java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * A pattern consists of a string that includes the following special
+ * components that will be replaced at runtime:
+ * <ul>
+ * <li>    "/"    the local pathname separator </li>
+ * <li>     "%t"   the system temporary directory </li>
+ * <li>     "%h"   the value of the "user.home" system property </li>
+ * <li>     "%g"   the generation number to distinguish rotated logs </li>
+ * <li>     "%u"   a unique number to resolve conflicts </li>
+ * <li>     "%%"   translates to a single percent sign "%" </li>
+ * </ul>
+ * If no "%g" field has been specified and the file count is greater
+ * than one, then the generation number will be added to the end of
+ * the generated filename, after a dot.
+ * <p>
+ * Thus for example a pattern of "%t/java%g.log" with a count of 2
+ * would typically cause log files to be written on Solaris to
+ * /var/tmp/java0.log and /var/tmp/java1.log whereas on Windows 95 they
+ * would be typically written to C:\TEMP\java0.log and C:\TEMP\java1.log
+ * <p>
+ * Generation numbers follow the sequence 0, 1, 2, etc.
+ * <p>
+ * Normally the "%u" unique field is set to 0.  However, if the <tt>FileHandler</tt>
+ * tries to open the filename and finds the file is currently in use by
+ * another process it will increment the unique number field and try
+ * again.  This will be repeated until <tt>FileHandler</tt> finds a file name that
+ * is  not currently in use. If there is a conflict and no "%u" field has
+ * been specified, it will be added at the end of the filename after a dot.
+ * (This will be after any automatically added generation number.)
+ * <p>
+ * Thus if three processes were all trying to log to fred%u.%g.txt then
+ * they  might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as
+ * the first file in their rotating sequences.
+ * <p>
+ * Note that the use of unique ids to avoid conflicts is only guaranteed
+ * to work reliably when using a local disk file system.
+ *
+ * @since 1.4
+ */
+
+public class FileHandler extends StreamHandler {
+    private MeteredStream meter;
+    private boolean append;
+    private int limit;       // zero => no limit.
+    private int count;
+    private String pattern;
+    private String lockFileName;
+    private FileChannel lockFileChannel;
+    private File files[];
+    private static final int MAX_LOCKS = 100;
+    private static final Set<String> locks = new HashSet<>();
+
+    /**
+     * A metered stream is a subclass of OutputStream that
+     * (a) forwards all its output to a target stream
+     * (b) keeps track of how many bytes have been written
+     */
+    private class MeteredStream extends OutputStream {
+        final OutputStream out;
+        int written;
+
+        MeteredStream(OutputStream out, int written) {
+            this.out = out;
+            this.written = written;
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            out.write(b);
+            written++;
+        }
+
+        @Override
+        public void write(byte buff[]) throws IOException {
+            out.write(buff);
+            written += buff.length;
+        }
+
+        @Override
+        public void write(byte buff[], int off, int len) throws IOException {
+            out.write(buff,off,len);
+            written += len;
+        }
+
+        @Override
+        public void flush() throws IOException {
+            out.flush();
+        }
+
+        @Override
+        public void close() throws IOException {
+            out.close();
+        }
+    }
+
+    private void open(File fname, boolean append) throws IOException {
+        int len = 0;
+        if (append) {
+            len = (int)fname.length();
+        }
+        FileOutputStream fout = new FileOutputStream(fname.toString(), append);
+        BufferedOutputStream bout = new BufferedOutputStream(fout);
+        meter = new MeteredStream(bout, len);
+        setOutputStream(meter);
+    }
+
+    /**
+     * Configure a FileHandler from LogManager properties and/or default values
+     * as specified in the class javadoc.
+     */
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+
+        String cname = getClass().getName();
+
+        pattern = manager.getStringProperty(cname + ".pattern", "%h/java%u.log");
+        limit = manager.getIntProperty(cname + ".limit", 0);
+        if (limit < 0) {
+            limit = 0;
+        }
+        count = manager.getIntProperty(cname + ".count", 1);
+        if (count <= 0) {
+            count = 1;
+        }
+        append = manager.getBooleanProperty(cname + ".append", false);
+        setLevel(manager.getLevelProperty(cname + ".level", Level.ALL));
+        setFilter(manager.getFilterProperty(cname + ".filter", null));
+        setFormatter(manager.getFormatterProperty(cname + ".formatter", new XMLFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+    }
+
+
+    /**
+     * Construct a default <tt>FileHandler</tt>.  This will be configured
+     * entirely from <tt>LogManager</tt> properties (or their default values).
+     * <p>
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control"))</tt>.
+     * @exception  NullPointerException if pattern property is an empty String.
+     */
+    public FileHandler() throws IOException, SecurityException {
+        checkPermission();
+        configure();
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to the given filename.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to no limit, and the file count is set to one.
+     * <p>
+     * There is no limit on the amount of data that may be written,
+     * so use this with care.
+     *
+     * @param pattern  the name of the output file
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     */
+    public FileHandler(String pattern) throws IOException, SecurityException {
+        if (pattern.length() < 1 ) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = 0;
+        this.count = 1;
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to the given filename,
+     * with optional append.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to no limit, the file count is set to one, and the append
+     * mode is set to the given <tt>append</tt> argument.
+     * <p>
+     * There is no limit on the amount of data that may be written,
+     * so use this with care.
+     *
+     * @param pattern  the name of the output file
+     * @param append  specifies append mode
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     */
+    public FileHandler(String pattern, boolean append) throws IOException,
+            SecurityException {
+        if (pattern.length() < 1 ) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = 0;
+        this.count = 1;
+        this.append = append;
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to a set of files.  When
+     * (approximately) the given limit has been written to one file,
+     * another file will be opened.  The output will cycle through a set
+     * of count files.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to the limit argument, and the file count is set to the
+     * given count argument.
+     * <p>
+     * The count must be at least 1.
+     *
+     * @param pattern  the pattern for naming the output file
+     * @param limit  the maximum number of bytes to write to any one file
+     * @param count  the number of files to use
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if {@code limit < 0}, or {@code count < 1}.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     */
+    public FileHandler(String pattern, int limit, int count)
+                                        throws IOException, SecurityException {
+        if (limit < 0 || count < 1 || pattern.length() < 1) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = limit;
+        this.count = count;
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to a set of files
+     * with optional append.  When (approximately) the given limit has
+     * been written to one file, another file will be opened.  The
+     * output will cycle through a set of count files.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to the limit argument, and the file count is set to the
+     * given count argument, and the append mode is set to the given
+     * <tt>append</tt> argument.
+     * <p>
+     * The count must be at least 1.
+     *
+     * @param pattern  the pattern for naming the output file
+     * @param limit  the maximum number of bytes to write to any one file
+     * @param count  the number of files to use
+     * @param append  specifies append mode
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if {@code limit < 0}, or {@code count < 1}.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     *
+     */
+    public FileHandler(String pattern, int limit, int count, boolean append)
+                                        throws IOException, SecurityException {
+        if (limit < 0 || count < 1 || pattern.length() < 1) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = limit;
+        this.count = count;
+        this.append = append;
+        openFiles();
+    }
+
+    private  boolean isParentWritable(Path path) {
+        Path parent = path.getParent();
+        if (parent == null) {
+            parent = path.toAbsolutePath().getParent();
+        }
+        return parent != null && Files.isWritable(parent);
+    }
+
+    /**
+     * Open the set of output files, based on the configured
+     * instance variables.
+     */
+    private void openFiles() throws IOException {
+        LogManager manager = LogManager.getLogManager();
+        manager.checkPermission();
+        if (count < 1) {
+           throw new IllegalArgumentException("file count = " + count);
+        }
+        if (limit < 0) {
+            limit = 0;
+        }
+
+        // We register our own ErrorManager during initialization
+        // so we can record exceptions.
+        InitializationErrorManager em = new InitializationErrorManager();
+        setErrorManager(em);
+
+        // Create a lock file.  This grants us exclusive access
+        // to our set of output files, as long as we are alive.
+        int unique = -1;
+        for (;;) {
+            unique++;
+            if (unique > MAX_LOCKS) {
+                throw new IOException("Couldn't get lock for " + pattern);
+            }
+            // Generate a lock file name from the "unique" int.
+            lockFileName = generate(pattern, 0, unique).toString() + ".lck";
+            // Now try to lock that filename.
+            // Because some systems (e.g., Solaris) can only do file locks
+            // between processes (and not within a process), we first check
+            // if we ourself already have the file locked.
+            synchronized(locks) {
+                if (locks.contains(lockFileName)) {
+                    // We already own this lock, for a different FileHandler
+                    // object.  Try again.
+                    continue;
+                }
+
+                final Path lockFilePath = Paths.get(lockFileName);
+                FileChannel channel = null;
+                int retries = -1;
+                boolean fileCreated = false;
+                while (channel == null && retries++ < 1) {
+                    try {
+                        channel = FileChannel.open(lockFilePath,
+                                CREATE_NEW, WRITE);
+                        fileCreated = true;
+                    } catch (FileAlreadyExistsException ix) {
+                        // This may be a zombie file left over by a previous
+                        // execution. Reuse it - but only if we can actually
+                        // write to its directory.
+                        // Note that this is a situation that may happen,
+                        // but not too frequently.
+                        if (Files.isRegularFile(lockFilePath, LinkOption.NOFOLLOW_LINKS)
+                            && isParentWritable(lockFilePath)) {
+                            try {
+                                channel = FileChannel.open(lockFilePath,
+                                    WRITE, APPEND);
+                            } catch (NoSuchFileException x) {
+                                // Race condition - retry once, and if that
+                                // fails again just try the next name in
+                                // the sequence.
+                                continue;
+                            } catch(IOException x) {
+                                // the file may not be writable for us.
+                                // try the next name in the sequence
+                                break;
+                            }
+                        } else {
+                            // at this point channel should still be null.
+                            // break and try the next name in the sequence.
+                            break;
+                        }
+                    }
+                }
+
+                if (channel == null) continue; // try the next name;
+                lockFileChannel = channel;
+
+                boolean available;
+                try {
+                    available = lockFileChannel.tryLock() != null;
+                    // We got the lock OK.
+                    // At this point we could call File.deleteOnExit().
+                    // However, this could have undesirable side effects
+                    // as indicated by JDK-4872014. So we will instead
+                    // rely on the fact that close() will remove the lock
+                    // file and that whoever is creating FileHandlers should
+                    // be responsible for closing them.
+                } catch (IOException ix) {
+                    // We got an IOException while trying to get the lock.
+                    // This normally indicates that locking is not supported
+                    // on the target directory.  We have to proceed without
+                    // getting a lock.   Drop through, but only if we did
+                    // create the file...
+                    available = fileCreated;
+                } catch (OverlappingFileLockException x) {
+                    // someone already locked this file in this VM, through
+                    // some other channel - that is - using something else
+                    // than new FileHandler(...);
+                    // continue searching for an available lock.
+                    available = false;
+                }
+                if (available) {
+                    // We got the lock.  Remember it.
+                    locks.add(lockFileName);
+                    break;
+                }
+
+                // We failed to get the lock.  Try next file.
+                lockFileChannel.close();
+            }
+        }
+
+        files = new File[count];
+        for (int i = 0; i < count; i++) {
+            files[i] = generate(pattern, i, unique);
+        }
+
+        // Create the initial log file.
+        if (append) {
+            open(files[0], true);
+        } else {
+            rotate();
+        }
+
+        // Did we detect any exceptions during initialization?
+        Exception ex = em.lastException;
+        if (ex != null) {
+            if (ex instanceof IOException) {
+                throw (IOException) ex;
+            } else if (ex instanceof SecurityException) {
+                throw (SecurityException) ex;
+            } else {
+                throw new IOException("Exception: " + ex);
+            }
+        }
+
+        // Install the normal default ErrorManager.
+        setErrorManager(new ErrorManager());
+    }
+
+    /**
+     * Generate a file based on a user-supplied pattern, generation number,
+     * and an integer uniqueness suffix
+     * @param pattern the pattern for naming the output file
+     * @param generation the generation number to distinguish rotated logs
+     * @param unique a unique number to resolve conflicts
+     * @return the generated File
+     * @throws IOException
+     */
+    private File generate(String pattern, int generation, int unique)
+            throws IOException {
+        File file = null;
+        String word = "";
+        int ix = 0;
+        boolean sawg = false;
+        boolean sawu = false;
+        while (ix < pattern.length()) {
+            char ch = pattern.charAt(ix);
+            ix++;
+            char ch2 = 0;
+            if (ix < pattern.length()) {
+                ch2 = Character.toLowerCase(pattern.charAt(ix));
+            }
+            if (ch == '/') {
+                if (file == null) {
+                    file = new File(word);
+                } else {
+                    file = new File(file, word);
+                }
+                word = "";
+                continue;
+            } else  if (ch == '%') {
+                if (ch2 == 't') {
+                    String tmpDir = System.getProperty("java.io.tmpdir");
+                    if (tmpDir == null) {
+                        tmpDir = System.getProperty("user.home");
+                    }
+                    file = new File(tmpDir);
+                    ix++;
+                    word = "";
+                    continue;
+                } else if (ch2 == 'h') {
+                    file = new File(System.getProperty("user.home"));
+                    // Android-removed: Don't prohibit using user.home property in setuid programs.
+                    /*
+                    if (isSetUID()) {
+                        // Ok, we are in a set UID program.  For safety's sake
+                        // we disallow attempts to open files relative to %h.
+                        throw new IOException("can't use %h in set UID program");
+                    }
+                    */
+                    ix++;
+                    word = "";
+                    continue;
+                } else if (ch2 == 'g') {
+                    word = word + generation;
+                    sawg = true;
+                    ix++;
+                    continue;
+                } else if (ch2 == 'u') {
+                    word = word + unique;
+                    sawu = true;
+                    ix++;
+                    continue;
+                } else if (ch2 == '%') {
+                    word = word + "%";
+                    ix++;
+                    continue;
+                }
+            }
+            word = word + ch;
+        }
+        if (count > 1 && !sawg) {
+            word = word + "." + generation;
+        }
+        if (unique > 0 && !sawu) {
+            word = word + "." + unique;
+        }
+        if (word.length() > 0) {
+            if (file == null) {
+                file = new File(word);
+            } else {
+                file = new File(file, word);
+            }
+        }
+        return file;
+    }
+
+    /**
+     * Rotate the set of output files
+     */
+    private synchronized void rotate() {
+        Level oldLevel = getLevel();
+        setLevel(Level.OFF);
+
+        super.close();
+        for (int i = count-2; i >= 0; i--) {
+            File f1 = files[i];
+            File f2 = files[i+1];
+            if (f1.exists()) {
+                if (f2.exists()) {
+                    f2.delete();
+                }
+                f1.renameTo(f2);
+            }
+        }
+        try {
+            open(files[0], false);
+        } catch (IOException ix) {
+            // We don't want to throw an exception here, but we
+            // report the exception to any registered ErrorManager.
+            reportError(null, ix, ErrorManager.OPEN_FAILURE);
+
+        }
+        setLevel(oldLevel);
+    }
+
+    /**
+     * Format and publish a <tt>LogRecord</tt>.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        super.publish(record);
+        flush();
+        if (limit > 0 && meter.written >= limit) {
+            // We performed access checks in the "init" method to make sure
+            // we are only initialized from trusted code.  So we assume
+            // it is OK to write the target files, even if we are
+            // currently being called from untrusted code.
+            // So it is safe to raise privilege here.
+            AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                @Override
+                public Object run() {
+                    rotate();
+                    return null;
+                }
+            });
+        }
+    }
+
+    /**
+     * Close all the files.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    @Override
+    public synchronized void close() throws SecurityException {
+        super.close();
+        // Unlock any lock file.
+        if (lockFileName == null) {
+            return;
+        }
+        try {
+            // Close the lock file channel (which also will free any locks)
+            lockFileChannel.close();
+        } catch (Exception ex) {
+            // Problems closing the stream.  Punt.
+        }
+        synchronized(locks) {
+            locks.remove(lockFileName);
+        }
+        new File(lockFileName).delete();
+        lockFileName = null;
+        lockFileChannel = null;
+    }
+
+    private static class InitializationErrorManager extends ErrorManager {
+        Exception lastException;
+        @Override
+        public void error(String msg, Exception ex, int code) {
+            lastException = ex;
+        }
+    }
+
+    // Android-removed: isSetUID's only caller is removed.
+    /*
+    /**
+     * check if we are in a set UID program.
+     *
+    private static native boolean isSetUID();
+    */
+}
diff --git a/java/util/logging/Filter.java b/java/util/logging/Filter.java
new file mode 100644
index 0000000..4383707
--- /dev/null
+++ b/java/util/logging/Filter.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * A Filter can be used to provide fine grain control over
+ * what is logged, beyond the control provided by log levels.
+ * <p>
+ * Each Logger and each Handler can have a filter associated with it.
+ * The Logger or Handler will call the isLoggable method to check
+ * if a given LogRecord should be published.  If isLoggable returns
+ * false, the LogRecord will be discarded.
+ *
+ * @since 1.4
+ */
+@FunctionalInterface
+public interface Filter {
+
+    /**
+     * Check if a given log record should be published.
+     * @param record  a LogRecord
+     * @return true if the log record should be published.
+     */
+    public boolean isLoggable(LogRecord record);
+}
diff --git a/java/util/logging/Formatter.java b/java/util/logging/Formatter.java
new file mode 100644
index 0000000..19e079f
--- /dev/null
+++ b/java/util/logging/Formatter.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * A Formatter provides support for formatting LogRecords.
+ * <p>
+ * Typically each logging Handler will have a Formatter associated
+ * with it.  The Formatter takes a LogRecord and converts it to
+ * a string.
+ * <p>
+ * Some formatters (such as the XMLFormatter) need to wrap head
+ * and tail strings around a set of formatted records. The getHeader
+ * and getTail methods can be used to obtain these strings.
+ *
+ * @since 1.4
+ */
+
+public abstract class Formatter {
+
+    /**
+     * Construct a new formatter.
+     */
+    protected Formatter() {
+    }
+
+    /**
+     * Format the given log record and return the formatted string.
+     * <p>
+     * The resulting formatted String will normally include a
+     * localized and formatted version of the LogRecord's message field.
+     * It is recommended to use the {@link Formatter#formatMessage}
+     * convenience method to localize and format the message field.
+     *
+     * @param record the log record to be formatted.
+     * @return the formatted log record
+     */
+    public abstract String format(LogRecord record);
+
+
+    /**
+     * Return the header string for a set of formatted records.
+     * <p>
+     * This base class returns an empty string, but this may be
+     * overridden by subclasses.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  header string
+     */
+    public String getHead(Handler h) {
+        return "";
+    }
+
+    /**
+     * Return the tail string for a set of formatted records.
+     * <p>
+     * This base class returns an empty string, but this may be
+     * overridden by subclasses.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  tail string
+     */
+    public String getTail(Handler h) {
+        return "";
+    }
+
+
+    /**
+     * Localize and format the message string from a log record.  This
+     * method is provided as a convenience for Formatter subclasses to
+     * use when they are performing formatting.
+     * <p>
+     * The message string is first localized to a format string using
+     * the record's ResourceBundle.  (If there is no ResourceBundle,
+     * or if the message key is not found, then the key is used as the
+     * format string.)  The format String uses java.text style
+     * formatting.
+     * <ul>
+     * <li>If there are no parameters, no formatter is used.
+     * <li>Otherwise, if the string contains "{0" then
+     *     java.text.MessageFormat  is used to format the string.
+     * <li>Otherwise no formatting is performed.
+     * </ul>
+     * <p>
+     *
+     * @param  record  the log record containing the raw message
+     * @return   a localized and formatted message
+     */
+    public synchronized String formatMessage(LogRecord record) {
+        String format = record.getMessage();
+        java.util.ResourceBundle catalog = record.getResourceBundle();
+        if (catalog != null) {
+            try {
+                format = catalog.getString(record.getMessage());
+            } catch (java.util.MissingResourceException ex) {
+                // Drop through.  Use record message as format
+                format = record.getMessage();
+            }
+        }
+        // Do the formatting.
+        try {
+            Object parameters[] = record.getParameters();
+            if (parameters == null || parameters.length == 0) {
+                // No parameters.  Just return format string.
+                return format;
+            }
+            // Is it a java.text style format?
+            // Ideally we could match with
+            // Pattern.compile("\\{\\d").matcher(format).find())
+            // However the cost is 14% higher, so we cheaply check for
+            // 1 of the first 4 parameters
+            if (format.indexOf("{0") >= 0 || format.indexOf("{1") >=0 ||
+                        format.indexOf("{2") >=0|| format.indexOf("{3") >=0) {
+                return java.text.MessageFormat.format(format, parameters);
+            }
+            return format;
+
+        } catch (Exception ex) {
+            // Formatting failed: use localized format string.
+            return format;
+        }
+    }
+}
diff --git a/java/util/logging/Handler.java b/java/util/logging/Handler.java
new file mode 100644
index 0000000..1cc7b43
--- /dev/null
+++ b/java/util/logging/Handler.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.UnsupportedEncodingException;
+/**
+ * A <tt>Handler</tt> object takes log messages from a <tt>Logger</tt> and
+ * exports them.  It might for example, write them to a console
+ * or write them to a file, or send them to a network logging service,
+ * or forward them to an OS log, or whatever.
+ * <p>
+ * A <tt>Handler</tt> can be disabled by doing a <tt>setLevel(Level.OFF)</tt>
+ * and can  be re-enabled by doing a <tt>setLevel</tt> with an appropriate level.
+ * <p>
+ * <tt>Handler</tt> classes typically use <tt>LogManager</tt> properties to set
+ * default values for the <tt>Handler</tt>'s <tt>Filter</tt>, <tt>Formatter</tt>,
+ * and <tt>Level</tt>.  See the specific documentation for each concrete
+ * <tt>Handler</tt> class.
+ *
+ *
+ * @since 1.4
+ */
+
+public abstract class Handler {
+    private static final int offValue = Level.OFF.intValue();
+    private final LogManager manager = LogManager.getLogManager();
+
+    // We're using volatile here to avoid synchronizing getters, which
+    // would prevent other threads from calling isLoggable()
+    // while publish() is executing.
+    // On the other hand, setters will be synchronized to exclude concurrent
+    // execution with more complex methods, such as StreamHandler.publish().
+    // We wouldn't want 'level' to be changed by another thread in the middle
+    // of the execution of a 'publish' call.
+    private volatile Filter filter;
+    private volatile Formatter formatter;
+    private volatile Level logLevel = Level.ALL;
+    private volatile ErrorManager errorManager = new ErrorManager();
+    private volatile String encoding;
+
+    // Package private support for security checking.  When sealed
+    // is true, we access check updates to the class.
+    boolean sealed = true;
+
+    /**
+     * Default constructor.  The resulting <tt>Handler</tt> has a log
+     * level of <tt>Level.ALL</tt>, no <tt>Formatter</tt>, and no
+     * <tt>Filter</tt>.  A default <tt>ErrorManager</tt> instance is installed
+     * as the <tt>ErrorManager</tt>.
+     */
+    protected Handler() {
+    }
+
+    /**
+     * Publish a <tt>LogRecord</tt>.
+     * <p>
+     * The logging request was made initially to a <tt>Logger</tt> object,
+     * which initialized the <tt>LogRecord</tt> and forwarded it here.
+     * <p>
+     * The <tt>Handler</tt>  is responsible for formatting the message, when and
+     * if necessary.  The formatting should include localization.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    public abstract void publish(LogRecord record);
+
+    /**
+     * Flush any buffered output.
+     */
+    public abstract void flush();
+
+    /**
+     * Close the <tt>Handler</tt> and free all associated resources.
+     * <p>
+     * The close method will perform a <tt>flush</tt> and then close the
+     * <tt>Handler</tt>.   After close has been called this <tt>Handler</tt>
+     * should no longer be used.  Method calls may either be silently
+     * ignored or may throw runtime exceptions.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public abstract void close() throws SecurityException;
+
+    /**
+     * Set a <tt>Formatter</tt>.  This <tt>Formatter</tt> will be used
+     * to format <tt>LogRecords</tt> for this <tt>Handler</tt>.
+     * <p>
+     * Some <tt>Handlers</tt> may not use <tt>Formatters</tt>, in
+     * which case the <tt>Formatter</tt> will be remembered, but not used.
+     * <p>
+     * @param newFormatter the <tt>Formatter</tt> to use (may not be null)
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setFormatter(Formatter newFormatter) throws SecurityException {
+        checkPermission();
+        // Check for a null pointer:
+        newFormatter.getClass();
+        formatter = newFormatter;
+    }
+
+    /**
+     * Return the <tt>Formatter</tt> for this <tt>Handler</tt>.
+     * @return the <tt>Formatter</tt> (may be null).
+     */
+    public Formatter getFormatter() {
+        return formatter;
+    }
+
+    /**
+     * Set the character encoding used by this <tt>Handler</tt>.
+     * <p>
+     * The encoding should be set before any <tt>LogRecords</tt> are written
+     * to the <tt>Handler</tt>.
+     *
+     * @param encoding  The name of a supported character encoding.
+     *        May be null, to indicate the default platform encoding.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  UnsupportedEncodingException if the named encoding is
+     *          not supported.
+     */
+    public synchronized void setEncoding(String encoding)
+                        throws SecurityException, java.io.UnsupportedEncodingException {
+        checkPermission();
+        if (encoding != null) {
+            try {
+                if(!java.nio.charset.Charset.isSupported(encoding)) {
+                    throw new UnsupportedEncodingException(encoding);
+                }
+            } catch (java.nio.charset.IllegalCharsetNameException e) {
+                throw new UnsupportedEncodingException(encoding);
+            }
+        }
+        this.encoding = encoding;
+    }
+
+    /**
+     * Return the character encoding for this <tt>Handler</tt>.
+     *
+     * @return  The encoding name.  May be null, which indicates the
+     *          default encoding should be used.
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Set a <tt>Filter</tt> to control output on this <tt>Handler</tt>.
+     * <P>
+     * For each call of <tt>publish</tt> the <tt>Handler</tt> will call
+     * this <tt>Filter</tt> (if it is non-null) to check if the
+     * <tt>LogRecord</tt> should be published or discarded.
+     *
+     * @param   newFilter  a <tt>Filter</tt> object (may be null)
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setFilter(Filter newFilter) throws SecurityException {
+        checkPermission();
+        filter = newFilter;
+    }
+
+    /**
+     * Get the current <tt>Filter</tt> for this <tt>Handler</tt>.
+     *
+     * @return  a <tt>Filter</tt> object (may be null)
+     */
+    public Filter getFilter() {
+        return filter;
+    }
+
+    /**
+     * Define an ErrorManager for this Handler.
+     * <p>
+     * The ErrorManager's "error" method will be invoked if any
+     * errors occur while using this Handler.
+     *
+     * @param em  the new ErrorManager
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setErrorManager(ErrorManager em) {
+        checkPermission();
+        if (em == null) {
+           throw new NullPointerException();
+        }
+        errorManager = em;
+    }
+
+    /**
+     * Retrieves the ErrorManager for this Handler.
+     *
+     * @return the ErrorManager for this Handler
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public ErrorManager getErrorManager() {
+        checkPermission();
+        return errorManager;
+    }
+
+   /**
+     * Protected convenience method to report an error to this Handler's
+     * ErrorManager.  Note that this method retrieves and uses the ErrorManager
+     * without doing a security check.  It can therefore be used in
+     * environments where the caller may be non-privileged.
+     *
+     * @param msg    a descriptive string (may be null)
+     * @param ex     an exception (may be null)
+     * @param code   an error code defined in ErrorManager
+     */
+    protected void reportError(String msg, Exception ex, int code) {
+        try {
+            errorManager.error(msg, ex, code);
+        } catch (Exception ex2) {
+            System.err.println("Handler.reportError caught:");
+            ex2.printStackTrace();
+        }
+    }
+
+    /**
+     * Set the log level specifying which message levels will be
+     * logged by this <tt>Handler</tt>.  Message levels lower than this
+     * value will be discarded.
+     * <p>
+     * The intention is to allow developers to turn on voluminous
+     * logging, but to limit the messages that are sent to certain
+     * <tt>Handlers</tt>.
+     *
+     * @param newLevel   the new value for the log level
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setLevel(Level newLevel) throws SecurityException {
+        if (newLevel == null) {
+            throw new NullPointerException();
+        }
+        checkPermission();
+        logLevel = newLevel;
+    }
+
+    /**
+     * Get the log level specifying which messages will be
+     * logged by this <tt>Handler</tt>.  Message levels lower
+     * than this level will be discarded.
+     * @return  the level of messages being logged.
+     */
+    public Level getLevel() {
+        return logLevel;
+    }
+
+    /**
+     * Check if this <tt>Handler</tt> would actually log a given <tt>LogRecord</tt>.
+     * <p>
+     * This method checks if the <tt>LogRecord</tt> has an appropriate
+     * <tt>Level</tt> and  whether it satisfies any <tt>Filter</tt>.  It also
+     * may make other <tt>Handler</tt> specific checks that might prevent a
+     * handler from logging the <tt>LogRecord</tt>. It will return false if
+     * the <tt>LogRecord</tt> is null.
+     * <p>
+     * @param record  a <tt>LogRecord</tt>
+     * @return true if the <tt>LogRecord</tt> would be logged.
+     *
+     */
+    public boolean isLoggable(LogRecord record) {
+        final int levelValue = getLevel().intValue();
+        if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
+            return false;
+        }
+        final Filter filter = getFilter();
+        if (filter == null) {
+            return true;
+        }
+        return filter.isLoggable(record);
+    }
+
+    // Package-private support method for security checks.
+    // If "sealed" is true, we check that the caller has
+    // appropriate security privileges to update Handler
+    // state and if not throw a SecurityException.
+    void checkPermission() throws SecurityException {
+        if (sealed) {
+            manager.checkPermission();
+        }
+    }
+}
diff --git a/java/util/logging/Level.annotated.java b/java/util/logging/Level.annotated.java
new file mode 100644
index 0000000..769e9fd
--- /dev/null
+++ b/java/util/logging/Level.annotated.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Level implements java.io.Serializable {
+
+protected Level(@libcore.util.NonNull java.lang.String name, int value) { throw new RuntimeException("Stub!"); }
+
+protected Level(@libcore.util.NonNull java.lang.String name, int value, @libcore.util.Nullable java.lang.String resourceBundleName) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getResourceBundleName() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getLocalizedName() { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public final int intValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public static synchronized java.util.logging.Level parse(@libcore.util.NonNull java.lang.String name) throws java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object ox) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.util.logging.Level ALL;
+static { ALL = null; }
+
[email protected] public static final java.util.logging.Level CONFIG;
+static { CONFIG = null; }
+
[email protected] public static final java.util.logging.Level FINE;
+static { FINE = null; }
+
[email protected] public static final java.util.logging.Level FINER;
+static { FINER = null; }
+
[email protected] public static final java.util.logging.Level FINEST;
+static { FINEST = null; }
+
[email protected] public static final java.util.logging.Level INFO;
+static { INFO = null; }
+
[email protected] public static final java.util.logging.Level OFF;
+static { OFF = null; }
+
[email protected] public static final java.util.logging.Level SEVERE;
+static { SEVERE = null; }
+
[email protected] public static final java.util.logging.Level WARNING;
+static { WARNING = null; }
+}
diff --git a/java/util/logging/Level.java b/java/util/logging/Level.java
new file mode 100644
index 0000000..17b585b
--- /dev/null
+++ b/java/util/logging/Level.java
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+/**
+ * The Level class defines a set of standard logging levels that
+ * can be used to control logging output.  The logging Level objects
+ * are ordered and are specified by ordered integers.  Enabling logging
+ * at a given level also enables logging at all higher levels.
+ * <p>
+ * Clients should normally use the predefined Level constants such
+ * as Level.SEVERE.
+ * <p>
+ * The levels in descending order are:
+ * <ul>
+ * <li>SEVERE (highest value)
+ * <li>WARNING
+ * <li>INFO
+ * <li>CONFIG
+ * <li>FINE
+ * <li>FINER
+ * <li>FINEST  (lowest value)
+ * </ul>
+ * In addition there is a level OFF that can be used to turn
+ * off logging, and a level ALL that can be used to enable
+ * logging of all messages.
+ * <p>
+ * It is possible for third parties to define additional logging
+ * levels by subclassing Level.  In such cases subclasses should
+ * take care to chose unique integer level values and to ensure that
+ * they maintain the Object uniqueness property across serialization
+ * by defining a suitable readResolve method.
+ *
+ * @since 1.4
+ */
+
+public class Level implements java.io.Serializable {
+    private static final String defaultBundle = "sun.util.logging.resources.logging";
+
+    /**
+     * @serial  The non-localized name of the level.
+     */
+    private final String name;
+
+    /**
+     * @serial  The integer value of the level.
+     */
+    private final int value;
+
+    /**
+     * @serial The resource bundle name to be used in localizing the level name.
+     */
+    private final String resourceBundleName;
+
+    // localized level name
+    private transient String localizedLevelName;
+    private transient Locale cachedLocale;
+
+    /**
+     * OFF is a special level that can be used to turn off logging.
+     * This level is initialized to <CODE>Integer.MAX_VALUE</CODE>.
+     */
+    public static final Level OFF = new Level("OFF",Integer.MAX_VALUE, defaultBundle);
+
+    /**
+     * SEVERE is a message level indicating a serious failure.
+     * <p>
+     * In general SEVERE messages should describe events that are
+     * of considerable importance and which will prevent normal
+     * program execution.   They should be reasonably intelligible
+     * to end users and to system administrators.
+     * This level is initialized to <CODE>1000</CODE>.
+     */
+    public static final Level SEVERE = new Level("SEVERE",1000, defaultBundle);
+
+    /**
+     * WARNING is a message level indicating a potential problem.
+     * <p>
+     * In general WARNING messages should describe events that will
+     * be of interest to end users or system managers, or which
+     * indicate potential problems.
+     * This level is initialized to <CODE>900</CODE>.
+     */
+    public static final Level WARNING = new Level("WARNING", 900, defaultBundle);
+
+    /**
+     * INFO is a message level for informational messages.
+     * <p>
+     * Typically INFO messages will be written to the console
+     * or its equivalent.  So the INFO level should only be
+     * used for reasonably significant messages that will
+     * make sense to end users and system administrators.
+     * This level is initialized to <CODE>800</CODE>.
+     */
+    public static final Level INFO = new Level("INFO", 800, defaultBundle);
+
+    /**
+     * CONFIG is a message level for static configuration messages.
+     * <p>
+     * CONFIG messages are intended to provide a variety of static
+     * configuration information, to assist in debugging problems
+     * that may be associated with particular configurations.
+     * For example, CONFIG message might include the CPU type,
+     * the graphics depth, the GUI look-and-feel, etc.
+     * This level is initialized to <CODE>700</CODE>.
+     */
+    public static final Level CONFIG = new Level("CONFIG", 700, defaultBundle);
+
+    /**
+     * FINE is a message level providing tracing information.
+     * <p>
+     * All of FINE, FINER, and FINEST are intended for relatively
+     * detailed tracing.  The exact meaning of the three levels will
+     * vary between subsystems, but in general, FINEST should be used
+     * for the most voluminous detailed output, FINER for somewhat
+     * less detailed output, and FINE for the  lowest volume (and
+     * most important) messages.
+     * <p>
+     * In general the FINE level should be used for information
+     * that will be broadly interesting to developers who do not have
+     * a specialized interest in the specific subsystem.
+     * <p>
+     * FINE messages might include things like minor (recoverable)
+     * failures.  Issues indicating potential performance problems
+     * are also worth logging as FINE.
+     * This level is initialized to <CODE>500</CODE>.
+     */
+    public static final Level FINE = new Level("FINE", 500, defaultBundle);
+
+    /**
+     * FINER indicates a fairly detailed tracing message.
+     * By default logging calls for entering, returning, or throwing
+     * an exception are traced at this level.
+     * This level is initialized to <CODE>400</CODE>.
+     */
+    public static final Level FINER = new Level("FINER", 400, defaultBundle);
+
+    /**
+     * FINEST indicates a highly detailed tracing message.
+     * This level is initialized to <CODE>300</CODE>.
+     */
+    public static final Level FINEST = new Level("FINEST", 300, defaultBundle);
+
+    /**
+     * ALL indicates that all messages should be logged.
+     * This level is initialized to <CODE>Integer.MIN_VALUE</CODE>.
+     */
+    public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, defaultBundle);
+
+    /**
+     * Create a named Level with a given integer value.
+     * <p>
+     * Note that this constructor is "protected" to allow subclassing.
+     * In general clients of logging should use one of the constant Level
+     * objects such as SEVERE or FINEST.  However, if clients need to
+     * add new logging levels, they may subclass Level and define new
+     * constants.
+     * @param name  the name of the Level, for example "SEVERE".
+     * @param value an integer value for the level.
+     * @throws NullPointerException if the name is null
+     */
+    protected Level(String name, int value) {
+        this(name, value, null);
+    }
+
+    /**
+     * Create a named Level with a given integer value and a
+     * given localization resource name.
+     * <p>
+     * @param name  the name of the Level, for example "SEVERE".
+     * @param value an integer value for the level.
+     * @param resourceBundleName name of a resource bundle to use in
+     *    localizing the given name. If the resourceBundleName is null
+     *    or an empty string, it is ignored.
+     * @throws NullPointerException if the name is null
+     */
+    protected Level(String name, int value, String resourceBundleName) {
+        this(name, value, resourceBundleName, true);
+    }
+
+    // private constructor to specify whether this instance should be added
+    // to the KnownLevel list from which Level.parse method does its look up
+    private Level(String name, int value, String resourceBundleName, boolean visible) {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        this.name = name;
+        this.value = value;
+        this.resourceBundleName = resourceBundleName;
+        this.localizedLevelName = resourceBundleName == null ? name : null;
+        this.cachedLocale = null;
+        if (visible) {
+            KnownLevel.add(this);
+        }
+    }
+
+    /**
+     * Return the level's localization resource bundle name, or
+     * null if no localization bundle is defined.
+     *
+     * @return localization resource bundle name
+     */
+    public String getResourceBundleName() {
+        return resourceBundleName;
+    }
+
+    /**
+     * Return the non-localized string name of the Level.
+     *
+     * @return non-localized name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Return the localized string name of the Level, for
+     * the current default locale.
+     * <p>
+     * If no localization information is available, the
+     * non-localized name is returned.
+     *
+     * @return localized name
+     */
+    public String getLocalizedName() {
+        return getLocalizedLevelName();
+    }
+
+    // package-private getLevelName() is used by the implementation
+    // instead of getName() to avoid calling the subclass's version
+    final String getLevelName() {
+        return this.name;
+    }
+
+    private String computeLocalizedLevelName(Locale newLocale) {
+        // Android-changed: Use Thread.currentThread().getContextClassLoader().
+        // Otherwise, we might get a BootClassLoader.
+        // ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale);
+        ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale,
+                                                     Thread.currentThread().getContextClassLoader());
+        final String localizedName = rb.getString(name);
+
+        final boolean isDefaultBundle = defaultBundle.equals(resourceBundleName);
+        if (!isDefaultBundle) return localizedName;
+
+        // This is a trick to determine whether the name has been translated
+        // or not. If it has not been translated, we need to use Locale.ROOT
+        // when calling toUpperCase().
+        final Locale rbLocale = rb.getLocale();
+        final Locale locale =
+                Locale.ROOT.equals(rbLocale)
+                || name.equals(localizedName.toUpperCase(Locale.ROOT))
+                ? Locale.ROOT : rbLocale;
+
+        // ALL CAPS in a resource bundle's message indicates no translation
+        // needed per Oracle translation guideline.  To workaround this
+        // in Oracle JDK implementation, convert the localized level name
+        // to uppercase for compatibility reason.
+        return Locale.ROOT.equals(locale) ? name : localizedName.toUpperCase(locale);
+    }
+
+    // Avoid looking up the localizedLevelName twice if we already
+    // have it.
+    final String getCachedLocalizedLevelName() {
+
+        if (localizedLevelName != null) {
+            if (cachedLocale != null) {
+                if (cachedLocale.equals(Locale.getDefault())) {
+                    // OK: our cached value was looked up with the same
+                    //     locale. We can use it.
+                    return localizedLevelName;
+                }
+            }
+        }
+
+        if (resourceBundleName == null) {
+            // No resource bundle: just use the name.
+            return name;
+        }
+
+        // We need to compute the localized name.
+        // Either because it's the first time, or because our cached
+        // value is for a different locale. Just return null.
+        return null;
+    }
+
+    final synchronized String getLocalizedLevelName() {
+
+        // See if we have a cached localized name
+        final String cachedLocalizedName = getCachedLocalizedLevelName();
+        if (cachedLocalizedName != null) {
+            return cachedLocalizedName;
+        }
+
+        // No cached localized name or cache invalid.
+        // Need to compute the localized name.
+        final Locale newLocale = Locale.getDefault();
+        try {
+            localizedLevelName = computeLocalizedLevelName(newLocale);
+        } catch (Exception ex) {
+            localizedLevelName = name;
+        }
+        cachedLocale = newLocale;
+        return localizedLevelName;
+    }
+
+    // Returns a mirrored Level object that matches the given name as
+    // specified in the Level.parse method.  Returns null if not found.
+    //
+    // It returns the same Level object as the one returned by Level.parse
+    // method if the given name is a non-localized name or integer.
+    //
+    // If the name is a localized name, findLevel and parse method may
+    // return a different level value if there is a custom Level subclass
+    // that overrides Level.getLocalizedName() to return a different string
+    // than what's returned by the default implementation.
+    //
+    static Level findLevel(String name) {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+
+        KnownLevel level;
+
+        // Look for a known Level with the given non-localized name.
+        level = KnownLevel.findByName(name);
+        if (level != null) {
+            return level.mirroredLevel;
+        }
+
+        // Now, check if the given name is an integer.  If so,
+        // first look for a Level with the given value and then
+        // if necessary create one.
+        try {
+            int x = Integer.parseInt(name);
+            level = KnownLevel.findByValue(x);
+            if (level == null) {
+                // add new Level
+                Level levelObject = new Level(name, x);
+                level = KnownLevel.findByValue(x);
+            }
+            return level.mirroredLevel;
+        } catch (NumberFormatException ex) {
+            // Not an integer.
+            // Drop through.
+        }
+
+        level = KnownLevel.findByLocalizedLevelName(name);
+        if (level != null) {
+            return level.mirroredLevel;
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a string representation of this Level.
+     *
+     * @return the non-localized name of the Level, for example "INFO".
+     */
+    @Override
+    public final String toString() {
+        return name;
+    }
+
+    /**
+     * Get the integer value for this level.  This integer value
+     * can be used for efficient ordering comparisons between
+     * Level objects.
+     * @return the integer value for this level.
+     */
+    public final int intValue() {
+        return value;
+    }
+
+    private static final long serialVersionUID = -8176160795706313070L;
+
+    // Serialization magic to prevent "doppelgangers".
+    // This is a performance optimization.
+    private Object readResolve() {
+        KnownLevel o = KnownLevel.matches(this);
+        if (o != null) {
+            return o.levelObject;
+        }
+
+        // Woops.  Whoever sent us this object knows
+        // about a new log level.  Add it to our list.
+        Level level = new Level(this.name, this.value, this.resourceBundleName);
+        return level;
+    }
+
+    /**
+     * Parse a level name string into a Level.
+     * <p>
+     * The argument string may consist of either a level name
+     * or an integer value.
+     * <p>
+     * For example:
+     * <ul>
+     * <li>     "SEVERE"
+     * <li>     "1000"
+     * </ul>
+     *
+     * @param  name   string to be parsed
+     * @throws NullPointerException if the name is null
+     * @throws IllegalArgumentException if the value is not valid.
+     * Valid values are integers between <CODE>Integer.MIN_VALUE</CODE>
+     * and <CODE>Integer.MAX_VALUE</CODE>, and all known level names.
+     * Known names are the levels defined by this class (e.g., <CODE>FINE</CODE>,
+     * <CODE>FINER</CODE>, <CODE>FINEST</CODE>), or created by this class with
+     * appropriate package access, or new levels defined or created
+     * by subclasses.
+     *
+     * @return The parsed value. Passing an integer that corresponds to a known name
+     * (e.g., 700) will return the associated name (e.g., <CODE>CONFIG</CODE>).
+     * Passing an integer that does not (e.g., 1) will return a new level name
+     * initialized to that value.
+     */
+    public static synchronized Level parse(String name) throws IllegalArgumentException {
+        // Check that name is not null.
+        name.length();
+
+        KnownLevel level;
+
+        // Look for a known Level with the given non-localized name.
+        level = KnownLevel.findByName(name);
+        if (level != null) {
+            return level.levelObject;
+        }
+
+        // Now, check if the given name is an integer.  If so,
+        // first look for a Level with the given value and then
+        // if necessary create one.
+        try {
+            int x = Integer.parseInt(name);
+            level = KnownLevel.findByValue(x);
+            if (level == null) {
+                // add new Level
+                Level levelObject = new Level(name, x);
+                level = KnownLevel.findByValue(x);
+            }
+            return level.levelObject;
+        } catch (NumberFormatException ex) {
+            // Not an integer.
+            // Drop through.
+        }
+
+        // Finally, look for a known level with the given localized name,
+        // in the current default locale.
+        // This is relatively expensive, but not excessively so.
+        level = KnownLevel.findByLocalizedLevelName(name);
+        if (level != null) {
+            return level.levelObject;
+        }
+
+        // OK, we've tried everything and failed
+        throw new IllegalArgumentException("Bad level \"" + name + "\"");
+    }
+
+    /**
+     * Compare two objects for value equality.
+     * @return true if and only if the two objects have the same level value.
+     */
+    @Override
+    public boolean equals(Object ox) {
+        try {
+            Level lx = (Level)ox;
+            return (lx.value == this.value);
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
+    /**
+     * Generate a hashcode.
+     * @return a hashcode based on the level value
+     */
+    @Override
+    public int hashCode() {
+        return this.value;
+    }
+
+    // KnownLevel class maintains the global list of all known levels.
+    // The API allows multiple custom Level instances of the same name/value
+    // be created. This class provides convenient methods to find a level
+    // by a given name, by a given value, or by a given localized name.
+    //
+    // KnownLevel wraps the following Level objects:
+    // 1. levelObject:   standard Level object or custom Level object
+    // 2. mirroredLevel: Level object representing the level specified in the
+    //                   logging configuration.
+    //
+    // Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
+    // are non-final but the name and resource bundle name are parameters to
+    // the Level constructor.  Use the mirroredLevel object instead of the
+    // levelObject to prevent the logging framework to execute foreign code
+    // implemented by untrusted Level subclass.
+    //
+    // Implementation Notes:
+    // If Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
+    // were final, the following KnownLevel implementation can be removed.
+    // Future API change should take this into consideration.
+    static final class KnownLevel {
+        private static Map<String, List<KnownLevel>> nameToLevels = new HashMap<>();
+        private static Map<Integer, List<KnownLevel>> intToLevels = new HashMap<>();
+        final Level levelObject;     // instance of Level class or Level subclass
+        final Level mirroredLevel;   // mirror of the custom Level
+        KnownLevel(Level l) {
+            this.levelObject = l;
+            if (l.getClass() == Level.class) {
+                this.mirroredLevel = l;
+            } else {
+                // this mirrored level object is hidden
+                this.mirroredLevel = new Level(l.name, l.value, l.resourceBundleName, false);
+            }
+        }
+
+        static synchronized void add(Level l) {
+            // the mirroredLevel object is always added to the list
+            // before the custom Level instance
+            KnownLevel o = new KnownLevel(l);
+            List<KnownLevel> list = nameToLevels.get(l.name);
+            if (list == null) {
+                list = new ArrayList<>();
+                nameToLevels.put(l.name, list);
+            }
+            list.add(o);
+
+            list = intToLevels.get(l.value);
+            if (list == null) {
+                list = new ArrayList<>();
+                intToLevels.put(l.value, list);
+            }
+            list.add(o);
+        }
+
+        // Returns a KnownLevel with the given non-localized name.
+        static synchronized KnownLevel findByName(String name) {
+            List<KnownLevel> list = nameToLevels.get(name);
+            if (list != null) {
+                return list.get(0);
+            }
+            return null;
+        }
+
+        // Returns a KnownLevel with the given value.
+        static synchronized KnownLevel findByValue(int value) {
+            List<KnownLevel> list = intToLevels.get(value);
+            if (list != null) {
+                return list.get(0);
+            }
+            return null;
+        }
+
+        // Returns a KnownLevel with the given localized name matching
+        // by calling the Level.getLocalizedLevelName() method (i.e. found
+        // from the resourceBundle associated with the Level object).
+        // This method does not call Level.getLocalizedName() that may
+        // be overridden in a subclass implementation
+        static synchronized KnownLevel findByLocalizedLevelName(String name) {
+            for (List<KnownLevel> levels : nameToLevels.values()) {
+                for (KnownLevel l : levels) {
+                    String lname = l.levelObject.getLocalizedLevelName();
+                    if (name.equals(lname)) {
+                        return l;
+                    }
+                }
+            }
+            return null;
+        }
+
+        static synchronized KnownLevel matches(Level l) {
+            List<KnownLevel> list = nameToLevels.get(l.name);
+            if (list != null) {
+                for (KnownLevel level : list) {
+                    Level other = level.mirroredLevel;
+                    Class<? extends Level> type = level.levelObject.getClass();
+                    if (l.value == other.value &&
+                           (l.resourceBundleName == other.resourceBundleName ||
+                               (l.resourceBundleName != null &&
+                                l.resourceBundleName.equals(other.resourceBundleName)))) {
+                        if (type == l.getClass()) {
+                            return level;
+                        }
+                    }
+                }
+            }
+            return null;
+        }
+    }
+
+}
diff --git a/java/util/logging/LogManager.java b/java/util/logging/LogManager.java
new file mode 100644
index 0000000..0d51b0f
--- /dev/null
+++ b/java/util/logging/LogManager.java
@@ -0,0 +1,1830 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.beans.PropertyChangeListener;
+
+/**
+ * There is a single global LogManager object that is used to
+ * maintain a set of shared state about Loggers and log services.
+ * <p>
+ * This LogManager object:
+ * <ul>
+ * <li> Manages a hierarchical namespace of Logger objects.  All
+ *      named Loggers are stored in this namespace.
+ * <li> Manages a set of logging control properties.  These are
+ *      simple key-value pairs that can be used by Handlers and
+ *      other logging objects to configure themselves.
+ * </ul>
+ * <p>
+ * The global LogManager object can be retrieved using LogManager.getLogManager().
+ * The LogManager object is created during class initialization and
+ * cannot subsequently be changed.
+ * <p>
+ * At startup the LogManager class is located using the
+ * java.util.logging.manager system property.
+ * <p>
+ * The LogManager defines two optional system properties that allow control over
+ * the initial configuration:
+ * <ul>
+ * <li>"java.util.logging.config.class"
+ * <li>"java.util.logging.config.file"
+ * </ul>
+ * These two properties may be specified on the command line to the "java"
+ * command, or as system property definitions passed to JNI_CreateJavaVM.
+ * <p>
+ * If the "java.util.logging.config.class" property is set, then the
+ * property value is treated as a class name.  The given class will be
+ * loaded, an object will be instantiated, and that object's constructor
+ * is responsible for reading in the initial configuration.  (That object
+ * may use other system properties to control its configuration.)  The
+ * alternate configuration class can use <tt>readConfiguration(InputStream)</tt>
+ * to define properties in the LogManager.
+ * <p>
+ * If "java.util.logging.config.class" property is <b>not</b> set,
+ * then the "java.util.logging.config.file" system property can be used
+ * to specify a properties file (in java.util.Properties format). The
+ * initial logging configuration will be read from this file.
+ * <p>
+ * If neither of these properties is defined then the LogManager uses its
+ * default configuration. The default configuration is typically loaded from the
+ * properties file "{@code lib/logging.properties}" in the Java installation
+ * directory.
+ * <p>
+ * The properties for loggers and Handlers will have names starting
+ * with the dot-separated name for the handler or logger.
+ * <p>
+ * The global logging properties may include:
+ * <ul>
+ * <li>A property "handlers".  This defines a whitespace or comma separated
+ * list of class names for handler classes to load and register as
+ * handlers on the root Logger (the Logger named "").  Each class
+ * name must be for a Handler class which has a default constructor.
+ * Note that these Handlers may be created lazily, when they are
+ * first used.
+ *
+ * <li>A property "&lt;logger&gt;.handlers". This defines a whitespace or
+ * comma separated list of class names for handlers classes to
+ * load and register as handlers to the specified logger. Each class
+ * name must be for a Handler class which has a default constructor.
+ * Note that these Handlers may be created lazily, when they are
+ * first used.
+ *
+ * <li>A property "&lt;logger&gt;.useParentHandlers". This defines a boolean
+ * value. By default every logger calls its parent in addition to
+ * handling the logging message itself, this often result in messages
+ * being handled by the root logger as well. When setting this property
+ * to false a Handler needs to be configured for this logger otherwise
+ * no logging messages are delivered.
+ *
+ * <li>A property "config".  This property is intended to allow
+ * arbitrary configuration code to be run.  The property defines a
+ * whitespace or comma separated list of class names.  A new instance will be
+ * created for each named class.  The default constructor of each class
+ * may execute arbitrary code to update the logging configuration, such as
+ * setting logger levels, adding handlers, adding filters, etc.
+ * </ul>
+ * <p>
+ * Note that all classes loaded during LogManager configuration are
+ * first searched on the system class path before any user class path.
+ * That includes the LogManager class, any config classes, and any
+ * handler classes.
+ * <p>
+ * Loggers are organized into a naming hierarchy based on their
+ * dot separated names.  Thus "a.b.c" is a child of "a.b", but
+ * "a.b1" and a.b2" are peers.
+ * <p>
+ * All properties whose names end with ".level" are assumed to define
+ * log levels for Loggers.  Thus "foo.level" defines a log level for
+ * the logger called "foo" and (recursively) for any of its children
+ * in the naming hierarchy.  Log Levels are applied in the order they
+ * are defined in the properties file.  Thus level settings for child
+ * nodes in the tree should come after settings for their parents.
+ * The property name ".level" can be used to set the level for the
+ * root of the tree.
+ * <p>
+ * All methods on the LogManager object are multi-thread safe.
+ *
+ * @since 1.4
+*/
+
+public class LogManager {
+    // The global LogManager object
+    private static final LogManager manager;
+
+    // 'props' is assigned within a lock but accessed without it.
+    // Declaring it volatile makes sure that another thread will not
+    // be able to see a partially constructed 'props' object.
+    // (seeing a partially constructed 'props' object can result in
+    // NPE being thrown in Hashtable.get(), because it leaves the door
+    // open for props.getProperties() to be called before the construcor
+    // of Hashtable is actually completed).
+    private volatile Properties props = new Properties();
+    private final static Level defaultLevel = Level.INFO;
+
+    // The map of the registered listeners. The map value is the registration
+    // count to allow for cases where the same listener is registered many times.
+    private final Map<Object,Integer> listenerMap = new HashMap<>();
+
+    // LoggerContext for system loggers and user loggers
+    private final LoggerContext systemContext = new SystemLoggerContext();
+    private final LoggerContext userContext = new LoggerContext();
+    // non final field - make it volatile to make sure that other threads
+    // will see the new value once ensureLogManagerInitialized() has finished
+    // executing.
+    private volatile Logger rootLogger;
+    // Have we done the primordial reading of the configuration file?
+    // (Must be done after a suitable amount of java.lang.System
+    // initialization has been done)
+    private volatile boolean readPrimordialConfiguration;
+    // Have we initialized global (root) handlers yet?
+    // This gets set to false in readConfiguration
+    private boolean initializedGlobalHandlers = true;
+    // True if JVM death is imminent and the exit hook has been called.
+    private boolean deathImminent;
+
+    static {
+        manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
+            @Override
+            public LogManager run() {
+                LogManager mgr = null;
+                String cname = null;
+                try {
+                    cname = System.getProperty("java.util.logging.manager");
+                    if (cname != null) {
+                        // Android-changed: Extract logic into the getClassInstance() helper.
+                        mgr = (LogManager) getClassInstance(cname).newInstance();
+                    }
+                } catch (Exception ex) {
+                    System.err.println("Could not load Logmanager \"" + cname + "\"");
+                    ex.printStackTrace();
+                }
+                if (mgr == null) {
+                    mgr = new LogManager();
+                }
+                return mgr;
+
+            }
+        });
+    }
+
+
+    // This private class is used as a shutdown hook.
+    // It does a "reset" to close all open handlers.
+    private class Cleaner extends Thread {
+
+        private Cleaner() {
+            /* Set context class loader to null in order to avoid
+             * keeping a strong reference to an application classloader.
+             */
+            this.setContextClassLoader(null);
+        }
+
+        @Override
+        public void run() {
+            // This is to ensure the LogManager.<clinit> is completed
+            // before synchronized block. Otherwise deadlocks are possible.
+            LogManager mgr = manager;
+
+            // If the global handlers haven't been initialized yet, we
+            // don't want to initialize them just so we can close them!
+            synchronized (LogManager.this) {
+                // Note that death is imminent.
+                deathImminent = true;
+                initializedGlobalHandlers = true;
+            }
+
+            // Do a reset to close all active handlers.
+            reset();
+        }
+    }
+
+
+    /**
+     * Protected constructor.  This is protected so that container applications
+     * (such as J2EE containers) can subclass the object.  It is non-public as
+     * it is intended that there only be one LogManager object, whose value is
+     * retrieved by calling LogManager.getLogManager.
+     */
+    protected LogManager() {
+        this(checkSubclassPermissions());
+    }
+
+    private LogManager(Void checked) {
+
+        // Add a shutdown hook to close the global handlers.
+        try {
+            Runtime.getRuntime().addShutdownHook(new Cleaner());
+        } catch (IllegalStateException e) {
+            // If the VM is already shutting down,
+            // We do not need to register shutdownHook.
+        }
+    }
+
+    private static Void checkSubclassPermissions() {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            // These permission will be checked in the LogManager constructor,
+            // in order to register the Cleaner() thread as a shutdown hook.
+            // Check them here to avoid the penalty of constructing the object
+            // etc...
+            sm.checkPermission(new RuntimePermission("shutdownHooks"));
+            sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+        }
+        return null;
+    }
+
+    /**
+     * Lazy initialization: if this instance of manager is the global
+     * manager then this method will read the initial configuration and
+     * add the root logger and global logger by calling addLogger().
+     *
+     * Note that it is subtly different from what we do in LoggerContext.
+     * In LoggerContext we're patching up the logger context tree in order to add
+     * the root and global logger *to the context tree*.
+     *
+     * For this to work, addLogger() must have already have been called
+     * once on the LogManager instance for the default logger being
+     * added.
+     *
+     * This is why ensureLogManagerInitialized() needs to be called before
+     * any logger is added to any logger context.
+     *
+     */
+    private boolean initializedCalled = false;
+    private volatile boolean initializationDone = false;
+    final void ensureLogManagerInitialized() {
+        final LogManager owner = this;
+        if (initializationDone || owner != manager) {
+            // we don't want to do this twice, and we don't want to do
+            // this on private manager instances.
+            return;
+        }
+
+        // Maybe another thread has called ensureLogManagerInitialized()
+        // before us and is still executing it. If so we will block until
+        // the log manager has finished initialized, then acquire the monitor,
+        // notice that initializationDone is now true and return.
+        // Otherwise - we have come here first! We will acquire the monitor,
+        // see that initializationDone is still false, and perform the
+        // initialization.
+        //
+        synchronized(this) {
+            // If initializedCalled is true it means that we're already in
+            // the process of initializing the LogManager in this thread.
+            // There has been a recursive call to ensureLogManagerInitialized().
+            final boolean isRecursiveInitialization = (initializedCalled == true);
+
+            assert initializedCalled || !initializationDone
+                    : "Initialization can't be done if initialized has not been called!";
+
+            if (isRecursiveInitialization || initializationDone) {
+                // If isRecursiveInitialization is true it means that we're
+                // already in the process of initializing the LogManager in
+                // this thread. There has been a recursive call to
+                // ensureLogManagerInitialized(). We should not proceed as
+                // it would lead to infinite recursion.
+                //
+                // If initializationDone is true then it means the manager
+                // has finished initializing; just return: we're done.
+                return;
+            }
+            // Calling addLogger below will in turn call requiresDefaultLogger()
+            // which will call ensureLogManagerInitialized().
+            // We use initializedCalled to break the recursion.
+            initializedCalled = true;
+            try {
+                AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                    @Override
+                    public Object run() {
+                        assert rootLogger == null;
+                        assert initializedCalled && !initializationDone;
+
+                        // Read configuration.
+                        owner.readPrimordialConfiguration();
+
+                        // Create and retain Logger for the root of the namespace.
+                        owner.rootLogger = owner.new RootLogger();
+                        owner.addLogger(owner.rootLogger);
+                        if (!owner.rootLogger.isLevelInitialized()) {
+                            owner.rootLogger.setLevel(defaultLevel);
+                        }
+
+                        // Adding the global Logger.
+                        // Do not call Logger.getGlobal() here as this might trigger
+                        // subtle inter-dependency issues.
+                        @SuppressWarnings("deprecation")
+                        final Logger global = Logger.global;
+
+                        // Make sure the global logger will be registered in the
+                        // global manager
+                        owner.addLogger(global);
+                        return null;
+                    }
+                });
+            } finally {
+                initializationDone = true;
+            }
+        }
+    }
+
+    /**
+     * Returns the global LogManager object.
+     * @return the global LogManager object
+     */
+    public static LogManager getLogManager() {
+        if (manager != null) {
+            manager.ensureLogManagerInitialized();
+        }
+        return manager;
+    }
+
+    private void readPrimordialConfiguration() {
+        if (!readPrimordialConfiguration) {
+            synchronized (this) {
+                if (!readPrimordialConfiguration) {
+                    // If System.in/out/err are null, it's a good
+                    // indication that we're still in the
+                    // bootstrapping phase
+                    if (System.out == null) {
+                        return;
+                    }
+                    readPrimordialConfiguration = true;
+
+                    try {
+                        AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                                @Override
+                                public Void run() throws Exception {
+                                    readConfiguration();
+
+                                    // Platform loggers begin to delegate to java.util.logging.Logger
+                                    sun.util.logging.PlatformLogger.redirectPlatformLoggers();
+                                    return null;
+                                }
+                            });
+                    } catch (Exception ex) {
+                        assert false : "Exception raised while reading logging configuration: " + ex;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds an event listener to be invoked when the logging
+     * properties are re-read. Adding multiple instances of
+     * the same event Listener results in multiple entries
+     * in the property event listener table.
+     *
+     * <p><b>WARNING:</b> This method is omitted from this class in all subset
+     * Profiles of Java SE that do not include the {@code java.beans} package.
+     * </p>
+     *
+     * @param l  event listener
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @exception NullPointerException if the PropertyChangeListener is null.
+     * @deprecated The dependency on {@code PropertyChangeListener} creates a
+     *             significant impediment to future modularization of the Java
+     *             platform. This method will be removed in a future release.
+     *             The global {@code LogManager} can detect changes to the
+     *             logging configuration by overridding the {@link
+     *             #readConfiguration readConfiguration} method.
+     */
+    @Deprecated
+    public void addPropertyChangeListener(PropertyChangeListener l) throws SecurityException {
+        PropertyChangeListener listener = Objects.requireNonNull(l);
+        checkPermission();
+        synchronized (listenerMap) {
+            // increment the registration count if already registered
+            Integer value = listenerMap.get(listener);
+            value = (value == null) ? 1 : (value + 1);
+            listenerMap.put(listener, value);
+        }
+    }
+
+    /**
+     * Removes an event listener for property change events.
+     * If the same listener instance has been added to the listener table
+     * through multiple invocations of <CODE>addPropertyChangeListener</CODE>,
+     * then an equivalent number of
+     * <CODE>removePropertyChangeListener</CODE> invocations are required to remove
+     * all instances of that listener from the listener table.
+     * <P>
+     * Returns silently if the given listener is not found.
+     *
+     * <p><b>WARNING:</b> This method is omitted from this class in all subset
+     * Profiles of Java SE that do not include the {@code java.beans} package.
+     * </p>
+     *
+     * @param l  event listener (can be null)
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @deprecated The dependency on {@code PropertyChangeListener} creates a
+     *             significant impediment to future modularization of the Java
+     *             platform. This method will be removed in a future release.
+     *             The global {@code LogManager} can detect changes to the
+     *             logging configuration by overridding the {@link
+     *             #readConfiguration readConfiguration} method.
+     */
+    @Deprecated
+    public void removePropertyChangeListener(PropertyChangeListener l) throws SecurityException {
+        checkPermission();
+        if (l != null) {
+            PropertyChangeListener listener = l;
+            synchronized (listenerMap) {
+                Integer value = listenerMap.get(listener);
+                if (value != null) {
+                    // remove from map if registration count is 1, otherwise
+                    // just decrement its count
+                    int i = value.intValue();
+                    if (i == 1) {
+                        listenerMap.remove(listener);
+                    } else {
+                        assert i > 1;
+                        listenerMap.put(listener, i - 1);
+                    }
+                }
+            }
+        }
+    }
+
+    // LoggerContext maps from AppContext
+    private WeakHashMap<Object, LoggerContext> contextsMap = null;
+
+    // Returns the LoggerContext for the user code (i.e. application or AppContext).
+    // Loggers are isolated from each AppContext.
+    private LoggerContext getUserContext() {
+        // Android-changed: Remove AWT specific hooks.
+        return userContext;
+    }
+
+    // The system context.
+    final LoggerContext getSystemContext() {
+        return systemContext;
+    }
+
+    private List<LoggerContext> contexts() {
+        List<LoggerContext> cxs = new ArrayList<>();
+        cxs.add(getSystemContext());
+        cxs.add(getUserContext());
+        return cxs;
+    }
+
+    // Find or create a specified logger instance. If a logger has
+    // already been created with the given name it is returned.
+    // Otherwise a new logger instance is created and registered
+    // in the LogManager global namespace.
+    // This method will always return a non-null Logger object.
+    // Synchronization is not required here. All synchronization for
+    // adding a new Logger object is handled by addLogger().
+    //
+    // This method must delegate to the LogManager implementation to
+    // add a new Logger or return the one that has been added previously
+    // as a LogManager subclass may override the addLogger, getLogger,
+    // readConfiguration, and other methods.
+    Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
+        Logger result = getLogger(name);
+        if (result == null) {
+            // only allocate the new logger once
+            Logger newLogger = new Logger(name, resourceBundleName, caller, this, false);
+            do {
+                if (addLogger(newLogger)) {
+                    // We successfully added the new Logger that we
+                    // created above so return it without refetching.
+                    return newLogger;
+                }
+
+                // We didn't add the new Logger that we created above
+                // because another thread added a Logger with the same
+                // name after our null check above and before our call
+                // to addLogger(). We have to refetch the Logger because
+                // addLogger() returns a boolean instead of the Logger
+                // reference itself. However, if the thread that created
+                // the other Logger is not holding a strong reference to
+                // the other Logger, then it is possible for the other
+                // Logger to be GC'ed after we saw it in addLogger() and
+                // before we can refetch it. If it has been GC'ed then
+                // we'll just loop around and try again.
+                result = getLogger(name);
+            } while (result == null);
+        }
+        return result;
+    }
+
+    Logger demandSystemLogger(String name, String resourceBundleName) {
+        // Add a system logger in the system context's namespace
+        final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName);
+
+        // Add the system logger to the LogManager's namespace if not exist
+        // so that there is only one single logger of the given name.
+        // System loggers are visible to applications unless a logger of
+        // the same name has been added.
+        Logger logger;
+        do {
+            // First attempt to call addLogger instead of getLogger
+            // This would avoid potential bug in custom LogManager.getLogger
+            // implementation that adds a logger if does not exist
+            if (addLogger(sysLogger)) {
+                // successfully added the new system logger
+                logger = sysLogger;
+            } else {
+                logger = getLogger(name);
+            }
+        } while (logger == null);
+
+        // LogManager will set the sysLogger's handlers via LogManager.addLogger method.
+        if (logger != sysLogger && sysLogger.accessCheckedHandlers().length == 0) {
+            // if logger already exists but handlers not set
+            final Logger l = logger;
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
+                public Void run() {
+                    for (Handler hdl : l.accessCheckedHandlers()) {
+                        sysLogger.addHandler(hdl);
+                    }
+                    return null;
+                }
+            });
+        }
+        return sysLogger;
+    }
+
+    // Android-added: getClassInstance helper method, used in several places in this class.
+    private static Class getClassInstance(String cname) throws ClassNotFoundException {
+        try {
+            return ClassLoader.getSystemClassLoader().loadClass(cname);
+        } catch (ClassNotFoundException ex) {
+            return Thread.currentThread().getContextClassLoader().loadClass(cname);
+        }
+    }
+
+    // LoggerContext maintains the logger namespace per context.
+    // The default LogManager implementation has one system context and user
+    // context.  The system context is used to maintain the namespace for
+    // all system loggers and is queried by the system code.  If a system logger
+    // doesn't exist in the user context, it'll also be added to the user context.
+    // The user context is queried by the user code and all other loggers are
+    // added in the user context.
+    class LoggerContext {
+        // Table of named Loggers that maps names to Loggers.
+        private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
+        // Tree of named Loggers
+        private final LogNode root;
+        private LoggerContext() {
+            this.root = new LogNode(null, this);
+        }
+
+
+        // Tells whether default loggers are required in this context.
+        // If true, the default loggers will be lazily added.
+        final boolean requiresDefaultLoggers() {
+            final boolean requiresDefaultLoggers = (getOwner() == manager);
+            if (requiresDefaultLoggers) {
+                getOwner().ensureLogManagerInitialized();
+            }
+            return requiresDefaultLoggers;
+        }
+
+        // This context's LogManager.
+        final LogManager getOwner() {
+            return LogManager.this;
+        }
+
+        // This context owner's root logger, which if not null, and if
+        // the context requires default loggers, will be added to the context
+        // logger's tree.
+        final Logger getRootLogger() {
+            return getOwner().rootLogger;
+        }
+
+        // The global logger, which if not null, and if
+        // the context requires default loggers, will be added to the context
+        // logger's tree.
+        final Logger getGlobalLogger() {
+            // Android-changed: Fix SuppressWarnings from "deprecated" to "deprecation".
+            @SuppressWarnings("deprecation") // avoids initialization cycles.
+            final Logger global = Logger.global;
+            return global;
+        }
+
+        Logger demandLogger(String name, String resourceBundleName) {
+            // a LogManager subclass may have its own implementation to add and
+            // get a Logger.  So delegate to the LogManager to do the work.
+            final LogManager owner = getOwner();
+            return owner.demandLogger(name, resourceBundleName, null);
+        }
+
+
+        // Due to subtle deadlock issues getUserContext() no longer
+        // calls addLocalLogger(rootLogger);
+        // Therefore - we need to add the default loggers later on.
+        // Checks that the context is properly initialized
+        // This is necessary before calling e.g. find(name)
+        // or getLoggerNames()
+        //
+        private void ensureInitialized() {
+            if (requiresDefaultLoggers()) {
+                // Ensure that the root and global loggers are set.
+                ensureDefaultLogger(getRootLogger());
+                ensureDefaultLogger(getGlobalLogger());
+            }
+        }
+
+
+        synchronized Logger findLogger(String name) {
+            // ensure that this context is properly initialized before
+            // looking for loggers.
+            ensureInitialized();
+            LoggerWeakRef ref = namedLoggers.get(name);
+            if (ref == null) {
+                return null;
+            }
+            Logger logger = ref.get();
+            if (logger == null) {
+                // Hashtable holds stale weak reference
+                // to a logger which has been GC-ed.
+                ref.dispose();
+            }
+            return logger;
+        }
+
+        // This method is called before adding a logger to the
+        // context.
+        // 'logger' is the context that will be added.
+        // This method will ensure that the defaults loggers are added
+        // before adding 'logger'.
+        //
+        private void ensureAllDefaultLoggers(Logger logger) {
+            if (requiresDefaultLoggers()) {
+                final String name = logger.getName();
+                if (!name.isEmpty()) {
+                    ensureDefaultLogger(getRootLogger());
+                    if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
+                        ensureDefaultLogger(getGlobalLogger());
+                    }
+                }
+            }
+        }
+
+        private void ensureDefaultLogger(Logger logger) {
+            // Used for lazy addition of root logger and global logger
+            // to a LoggerContext.
+
+            // This check is simple sanity: we do not want that this
+            // method be called for anything else than Logger.global
+            // or owner.rootLogger.
+            if (!requiresDefaultLoggers() || logger == null
+                    || logger != Logger.global && logger != LogManager.this.rootLogger) {
+
+                // the case where we have a non null logger which is neither
+                // Logger.global nor manager.rootLogger indicates a serious
+                // issue - as ensureDefaultLogger should never be called
+                // with any other loggers than one of these two (or null - if
+                // e.g manager.rootLogger is not yet initialized)...
+                assert logger == null;
+
+                return;
+            }
+
+            // Adds the logger if it's not already there.
+            if (!namedLoggers.containsKey(logger.getName())) {
+                // It is important to prevent addLocalLogger to
+                // call ensureAllDefaultLoggers when we're in the process
+                // off adding one of those default loggers - as this would
+                // immediately cause a stack overflow.
+                // Therefore we must pass addDefaultLoggersIfNeeded=false,
+                // even if requiresDefaultLoggers is true.
+                addLocalLogger(logger, false);
+            }
+        }
+
+        boolean addLocalLogger(Logger logger) {
+            // no need to add default loggers if it's not required
+            return addLocalLogger(logger, requiresDefaultLoggers());
+        }
+
+        // Add a logger to this context.  This method will only set its level
+        // and process parent loggers.  It doesn't set its handlers.
+        synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) {
+            // addDefaultLoggersIfNeeded serves to break recursion when adding
+            // default loggers. If we're adding one of the default loggers
+            // (we're being called from ensureDefaultLogger()) then
+            // addDefaultLoggersIfNeeded will be false: we don't want to
+            // call ensureAllDefaultLoggers again.
+            //
+            // Note: addDefaultLoggersIfNeeded can also be false when
+            //       requiresDefaultLoggers is false - since calling
+            //       ensureAllDefaultLoggers would have no effect in this case.
+            if (addDefaultLoggersIfNeeded) {
+                ensureAllDefaultLoggers(logger);
+            }
+
+            final String name = logger.getName();
+            if (name == null) {
+                throw new NullPointerException();
+            }
+            LoggerWeakRef ref = namedLoggers.get(name);
+            if (ref != null) {
+                if (ref.get() == null) {
+                    // It's possible that the Logger was GC'ed after a
+                    // drainLoggerRefQueueBounded() call above so allow
+                    // a new one to be registered.
+                    ref.dispose();
+                } else {
+                    // We already have a registered logger with the given name.
+                    return false;
+                }
+            }
+
+            // We're adding a new logger.
+            // Note that we are creating a weak reference here.
+            final LogManager owner = getOwner();
+            logger.setLogManager(owner);
+            ref = owner.new LoggerWeakRef(logger);
+            namedLoggers.put(name, ref);
+
+            // Apply any initial level defined for the new logger, unless
+            // the logger's level is already initialized
+            Level level = owner.getLevelProperty(name + ".level", null);
+            if (level != null && !logger.isLevelInitialized()) {
+                doSetLevel(logger, level);
+            }
+
+            // instantiation of the handler is done in the LogManager.addLogger
+            // implementation as a handler class may be only visible to LogManager
+            // subclass for the custom log manager case
+            processParentHandlers(logger, name);
+
+            // Find the new node and its parent.
+            LogNode node = getNode(name);
+            node.loggerRef = ref;
+            Logger parent = null;
+            LogNode nodep = node.parent;
+            while (nodep != null) {
+                LoggerWeakRef nodeRef = nodep.loggerRef;
+                if (nodeRef != null) {
+                    parent = nodeRef.get();
+                    if (parent != null) {
+                        break;
+                    }
+                }
+                nodep = nodep.parent;
+            }
+
+            if (parent != null) {
+                doSetParent(logger, parent);
+            }
+            // Walk over the children and tell them we are their new parent.
+            node.walkAndSetParent(logger);
+            // new LogNode is ready so tell the LoggerWeakRef about it
+            ref.setNode(node);
+            return true;
+        }
+
+        synchronized void removeLoggerRef(String name, LoggerWeakRef ref) {
+            namedLoggers.remove(name, ref);
+        }
+
+        synchronized Enumeration<String> getLoggerNames() {
+            // ensure that this context is properly initialized before
+            // returning logger names.
+            ensureInitialized();
+            return namedLoggers.keys();
+        }
+
+        // If logger.getUseParentHandlers() returns 'true' and any of the logger's
+        // parents have levels or handlers defined, make sure they are instantiated.
+        private void processParentHandlers(final Logger logger, final String name) {
+            final LogManager owner = getOwner();
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
+                public Void run() {
+                    if (logger != owner.rootLogger) {
+                        boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
+                        if (!useParent) {
+                            logger.setUseParentHandlers(false);
+                        }
+                    }
+                    return null;
+                }
+            });
+
+            int ix = 1;
+            for (;;) {
+                int ix2 = name.indexOf(".", ix);
+                if (ix2 < 0) {
+                    break;
+                }
+                String pname = name.substring(0, ix2);
+                if (owner.getProperty(pname + ".level") != null ||
+                    owner.getProperty(pname + ".handlers") != null) {
+                    // This pname has a level/handlers definition.
+                    // Make sure it exists.
+                    demandLogger(pname, null);
+                }
+                ix = ix2+1;
+            }
+        }
+
+        // Gets a node in our tree of logger nodes.
+        // If necessary, create it.
+        LogNode getNode(String name) {
+            if (name == null || name.equals("")) {
+                return root;
+            }
+            LogNode node = root;
+            while (name.length() > 0) {
+                int ix = name.indexOf(".");
+                String head;
+                if (ix > 0) {
+                    head = name.substring(0, ix);
+                    name = name.substring(ix + 1);
+                } else {
+                    head = name;
+                    name = "";
+                }
+                if (node.children == null) {
+                    node.children = new HashMap<>();
+                }
+                LogNode child = node.children.get(head);
+                if (child == null) {
+                    child = new LogNode(node, this);
+                    node.children.put(head, child);
+                }
+                node = child;
+            }
+            return node;
+        }
+    }
+
+    final class SystemLoggerContext extends LoggerContext {
+        // Add a system logger in the system context's namespace as well as
+        // in the LogManager's namespace if not exist so that there is only
+        // one single logger of the given name.  System loggers are visible
+        // to applications unless a logger of the same name has been added.
+        @Override
+        Logger demandLogger(String name, String resourceBundleName) {
+            Logger result = findLogger(name);
+            if (result == null) {
+                // only allocate the new system logger once
+                Logger newLogger = new Logger(name, resourceBundleName, null, getOwner(), true);
+                do {
+                    if (addLocalLogger(newLogger)) {
+                        // We successfully added the new Logger that we
+                        // created above so return it without refetching.
+                        result = newLogger;
+                    } else {
+                        // We didn't add the new Logger that we created above
+                        // because another thread added a Logger with the same
+                        // name after our null check above and before our call
+                        // to addLogger(). We have to refetch the Logger because
+                        // addLogger() returns a boolean instead of the Logger
+                        // reference itself. However, if the thread that created
+                        // the other Logger is not holding a strong reference to
+                        // the other Logger, then it is possible for the other
+                        // Logger to be GC'ed after we saw it in addLogger() and
+                        // before we can refetch it. If it has been GC'ed then
+                        // we'll just loop around and try again.
+                        result = findLogger(name);
+                    }
+                } while (result == null);
+            }
+            return result;
+        }
+    }
+
+    // Add new per logger handlers.
+    // We need to raise privilege here. All our decisions will
+    // be made based on the logging configuration, which can
+    // only be modified by trusted code.
+    private void loadLoggerHandlers(final Logger logger, final String name,
+                                    final String handlersPropertyName)
+    {
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                String names[] = parseClassNames(handlersPropertyName);
+                for (int i = 0; i < names.length; i++) {
+                    String word = names[i];
+                    try {
+                        // Android-changed: Fall back from the system to the context classloader.
+                        // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
+                        Class<?> clz = getClassInstance(word);
+                        Handler hdl = (Handler) clz.newInstance();
+                        // Check if there is a property defining the
+                        // this handler's level.
+                        String levs = getProperty(word + ".level");
+                        if (levs != null) {
+                            Level l = Level.findLevel(levs);
+                            if (l != null) {
+                                hdl.setLevel(l);
+                            } else {
+                                // Probably a bad level. Drop through.
+                                System.err.println("Can't set level for " + word);
+                            }
+                        }
+                        // Add this Handler to the logger
+                        logger.addHandler(hdl);
+                    } catch (Exception ex) {
+                        System.err.println("Can't load log handler \"" + word + "\"");
+                        System.err.println("" + ex);
+                        ex.printStackTrace();
+                    }
+                }
+                return null;
+            }
+        });
+    }
+
+
+    // loggerRefQueue holds LoggerWeakRef objects for Logger objects
+    // that have been GC'ed.
+    private final ReferenceQueue<Logger> loggerRefQueue
+        = new ReferenceQueue<>();
+
+    // Package-level inner class.
+    // Helper class for managing WeakReferences to Logger objects.
+    //
+    // LogManager.namedLoggers
+    //     - has weak references to all named Loggers
+    //     - namedLoggers keeps the LoggerWeakRef objects for the named
+    //       Loggers around until we can deal with the book keeping for
+    //       the named Logger that is being GC'ed.
+    // LogManager.LogNode.loggerRef
+    //     - has a weak reference to a named Logger
+    //     - the LogNode will also keep the LoggerWeakRef objects for
+    //       the named Loggers around; currently LogNodes never go away.
+    // Logger.kids
+    //     - has a weak reference to each direct child Logger; this
+    //       includes anonymous and named Loggers
+    //     - anonymous Loggers are always children of the rootLogger
+    //       which is a strong reference; rootLogger.kids keeps the
+    //       LoggerWeakRef objects for the anonymous Loggers around
+    //       until we can deal with the book keeping.
+    //
+    final class LoggerWeakRef extends WeakReference<Logger> {
+        private String                name;       // for namedLoggers cleanup
+        private LogNode               node;       // for loggerRef cleanup
+        private WeakReference<Logger> parentRef;  // for kids cleanup
+        private boolean disposed = false;         // avoid calling dispose twice
+
+        LoggerWeakRef(Logger logger) {
+            super(logger, loggerRefQueue);
+
+            name = logger.getName();  // save for namedLoggers cleanup
+        }
+
+        // dispose of this LoggerWeakRef object
+        void dispose() {
+            // Avoid calling dispose twice. When a Logger is gc'ed, its
+            // LoggerWeakRef will be enqueued.
+            // However, a new logger of the same name may be added (or looked
+            // up) before the queue is drained. When that happens, dispose()
+            // will be called by addLocalLogger() or findLogger().
+            // Later when the queue is drained, dispose() will be called again
+            // for the same LoggerWeakRef. Marking LoggerWeakRef as disposed
+            // avoids processing the data twice (even though the code should
+            // now be reentrant).
+            synchronized(this) {
+                // Note to maintainers:
+                // Be careful not to call any method that tries to acquire
+                // another lock from within this block - as this would surely
+                // lead to deadlocks, given that dispose() can be called by
+                // multiple threads, and from within different synchronized
+                // methods/blocks.
+                if (disposed) return;
+                disposed = true;
+            }
+
+            final LogNode n = node;
+            if (n != null) {
+                // n.loggerRef can only be safely modified from within
+                // a lock on LoggerContext. removeLoggerRef is already
+                // synchronized on LoggerContext so calling
+                // n.context.removeLoggerRef from within this lock is safe.
+                synchronized (n.context) {
+                    // if we have a LogNode, then we were a named Logger
+                    // so clear namedLoggers weak ref to us
+                    n.context.removeLoggerRef(name, this);
+                    name = null;  // clear our ref to the Logger's name
+
+                    // LogNode may have been reused - so only clear
+                    // LogNode.loggerRef if LogNode.loggerRef == this
+                    if (n.loggerRef == this) {
+                        n.loggerRef = null;  // clear LogNode's weak ref to us
+                    }
+                    node = null;            // clear our ref to LogNode
+                }
+            }
+
+            if (parentRef != null) {
+                // this LoggerWeakRef has or had a parent Logger
+                Logger parent = parentRef.get();
+                if (parent != null) {
+                    // the parent Logger is still there so clear the
+                    // parent Logger's weak ref to us
+                    parent.removeChildLogger(this);
+                }
+                parentRef = null;  // clear our weak ref to the parent Logger
+            }
+        }
+
+        // set the node field to the specified value
+        void setNode(LogNode node) {
+            this.node = node;
+        }
+
+        // set the parentRef field to the specified value
+        void setParentRef(WeakReference<Logger> parentRef) {
+            this.parentRef = parentRef;
+        }
+    }
+
+    // Package-level method.
+    // Drain some Logger objects that have been GC'ed.
+    //
+    // drainLoggerRefQueueBounded() is called by addLogger() below
+    // and by Logger.getAnonymousLogger(String) so we'll drain up to
+    // MAX_ITERATIONS GC'ed Loggers for every Logger we add.
+    //
+    // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
+    // us about a 50/50 mix in increased weak ref counts versus
+    // decreased weak ref counts in the AnonLoggerWeakRefLeak test.
+    // Here are stats for cleaning up sets of 400 anonymous Loggers:
+    //   - test duration 1 minute
+    //   - sample size of 125 sets of 400
+    //   - average: 1.99 ms
+    //   - minimum: 0.57 ms
+    //   - maximum: 25.3 ms
+    //
+    // The same config gives us a better decreased weak ref count
+    // than increased weak ref count in the LoggerWeakRefLeak test.
+    // Here are stats for cleaning up sets of 400 named Loggers:
+    //   - test duration 2 minutes
+    //   - sample size of 506 sets of 400
+    //   - average: 0.57 ms
+    //   - minimum: 0.02 ms
+    //   - maximum: 10.9 ms
+    //
+    private final static int MAX_ITERATIONS = 400;
+    final void drainLoggerRefQueueBounded() {
+        for (int i = 0; i < MAX_ITERATIONS; i++) {
+            if (loggerRefQueue == null) {
+                // haven't finished loading LogManager yet
+                break;
+            }
+
+            LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll();
+            if (ref == null) {
+                break;
+            }
+            // a Logger object has been GC'ed so clean it up
+            ref.dispose();
+        }
+    }
+
+    /**
+     * Add a named logger.  This does nothing and returns false if a logger
+     * with the same name is already registered.
+     * <p>
+     * The Logger factory methods call this method to register each
+     * newly created Logger.
+     * <p>
+     * The application should retain its own reference to the Logger
+     * object to avoid it being garbage collected.  The LogManager
+     * may only retain a weak reference.
+     *
+     * @param   logger the new logger.
+     * @return  true if the argument logger was registered successfully,
+     *          false if a logger of that name already exists.
+     * @exception NullPointerException if the logger name is null.
+     */
+    public boolean addLogger(Logger logger) {
+        final String name = logger.getName();
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        drainLoggerRefQueueBounded();
+        LoggerContext cx = getUserContext();
+        if (cx.addLocalLogger(logger)) {
+            // Do we have a per logger handler too?
+            // Note: this will add a 200ms penalty
+            loadLoggerHandlers(logger, name, name + ".handlers");
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    // Private method to set a level on a logger.
+    // If necessary, we raise privilege before doing the call.
+    private static void doSetLevel(final Logger logger, final Level level) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            // There is no security manager, so things are easy.
+            logger.setLevel(level);
+            return;
+        }
+        // There is a security manager.  Raise privilege before
+        // calling setLevel.
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                logger.setLevel(level);
+                return null;
+            }});
+    }
+
+    // Private method to set a parent on a logger.
+    // If necessary, we raise privilege before doing the setParent call.
+    private static void doSetParent(final Logger logger, final Logger parent) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            // There is no security manager, so things are easy.
+            logger.setParent(parent);
+            return;
+        }
+        // There is a security manager.  Raise privilege before
+        // calling setParent.
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                logger.setParent(parent);
+                return null;
+            }});
+    }
+
+    /**
+     * Method to find a named logger.
+     * <p>
+     * Note that since untrusted code may create loggers with
+     * arbitrary names this method should not be relied on to
+     * find Loggers for security sensitive logging.
+     * It is also important to note that the Logger associated with the
+     * String {@code name} may be garbage collected at any time if there
+     * is no strong reference to the Logger. The caller of this method
+     * must check the return value for null in order to properly handle
+     * the case where the Logger has been garbage collected.
+     * <p>
+     * @param name name of the logger
+     * @return  matching logger or null if none is found
+     */
+    public Logger getLogger(String name) {
+        return getUserContext().findLogger(name);
+    }
+
+    /**
+     * Get an enumeration of known logger names.
+     * <p>
+     * Note:  Loggers may be added dynamically as new classes are loaded.
+     * This method only reports on the loggers that are currently registered.
+     * It is also important to note that this method only returns the name
+     * of a Logger, not a strong reference to the Logger itself.
+     * The returned String does nothing to prevent the Logger from being
+     * garbage collected. In particular, if the returned name is passed
+     * to {@code LogManager.getLogger()}, then the caller must check the
+     * return value from {@code LogManager.getLogger()} for null to properly
+     * handle the case where the Logger has been garbage collected in the
+     * time since its name was returned by this method.
+     * <p>
+     * @return  enumeration of logger name strings
+     */
+    public Enumeration<String> getLoggerNames() {
+        return getUserContext().getLoggerNames();
+    }
+
+    /**
+     * Reinitialize the logging properties and reread the logging configuration.
+     * <p>
+     * The same rules are used for locating the configuration properties
+     * as are used at startup.  So normally the logging properties will
+     * be re-read from the same file that was used at startup.
+     * <P>
+     * Any log level definitions in the new configuration file will be
+     * applied using Logger.setLevel(), if the target Logger exists.
+     * <p>
+     * A PropertyChangeEvent will be fired after the properties are read.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @exception  IOException if there are IO problems reading the configuration.
+     */
+    public void readConfiguration() throws IOException, SecurityException {
+        checkPermission();
+
+        // if a configuration class is specified, load it and use it.
+        String cname = System.getProperty("java.util.logging.config.class");
+        if (cname != null) {
+            try {
+                // Instantiate the named class.  It is its constructor's
+                // responsibility to initialize the logging configuration, by
+                // calling readConfiguration(InputStream) with a suitable stream.
+                // Android-changed: Extract logic into the getClassInstance() helper.
+                getClassInstance(cname).newInstance();
+                return;
+            } catch (Exception ex) {
+                System.err.println("Logging configuration class \"" + cname + "\" failed");
+                System.err.println("" + ex);
+                // keep going and useful config file.
+            }
+        }
+
+        String fname = System.getProperty("java.util.logging.config.file");
+        if (fname == null) {
+            fname = System.getProperty("java.home");
+            if (fname == null) {
+                throw new Error("Can't find java.home ??");
+            }
+            File f = new File(fname, "lib");
+            f = new File(f, "logging.properties");
+            fname = f.getCanonicalPath();
+        }
+
+        // BEGIN Android-changed: Look in the boot class-path jar files for the logging.properties.
+        // It may not be present in the file system.
+        /*
+        try (final InputStream in = new FileInputStream(fname)) {
+            final BufferedInputStream bin = new BufferedInputStream(in);
+            readConfiguration(bin);
+        }
+        */
+        InputStream in;
+        try {
+            in = new FileInputStream(fname);
+        } catch (Exception e) {
+            in = LogManager.class.getResourceAsStream("logging.properties");
+            if (in == null) {
+                throw e;
+            }
+        }
+
+        BufferedInputStream bin = new BufferedInputStream(in);
+        try {
+            readConfiguration(bin);
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+        // END Android-changed: Look in the boot class-path jar files for the logging.properties.
+    }
+
+    /**
+     * Reset the logging configuration.
+     * <p>
+     * For all named loggers, the reset operation removes and closes
+     * all Handlers and (except for the root logger) sets the level
+     * to null.  The root logger's level is set to Level.INFO.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     */
+
+    public void reset() throws SecurityException {
+        checkPermission();
+        synchronized (this) {
+            props = new Properties();
+            // Since we are doing a reset we no longer want to initialize
+            // the global handlers, if they haven't been initialized yet.
+            initializedGlobalHandlers = true;
+        }
+        for (LoggerContext cx : contexts()) {
+            Enumeration<String> enum_ = cx.getLoggerNames();
+            while (enum_.hasMoreElements()) {
+                String name = enum_.nextElement();
+                Logger logger = cx.findLogger(name);
+                if (logger != null) {
+                    resetLogger(logger);
+                }
+            }
+        }
+    }
+
+    // Private method to reset an individual target logger.
+    private void resetLogger(Logger logger) {
+        // Close all the Logger's handlers.
+        Handler[] targets = logger.getHandlers();
+        for (int i = 0; i < targets.length; i++) {
+            Handler h = targets[i];
+            logger.removeHandler(h);
+            try {
+                h.close();
+            } catch (Exception ex) {
+                // Problems closing a handler?  Keep going...
+            }
+        }
+        String name = logger.getName();
+        if (name != null && name.equals("")) {
+            // This is the root logger.
+            logger.setLevel(defaultLevel);
+        } else {
+            logger.setLevel(null);
+        }
+    }
+
+    // get a list of whitespace separated classnames from a property.
+    private String[] parseClassNames(String propertyName) {
+        String hands = getProperty(propertyName);
+        if (hands == null) {
+            return new String[0];
+        }
+        hands = hands.trim();
+        int ix = 0;
+        final List<String> result = new ArrayList<>();
+        while (ix < hands.length()) {
+            int end = ix;
+            while (end < hands.length()) {
+                if (Character.isWhitespace(hands.charAt(end))) {
+                    break;
+                }
+                if (hands.charAt(end) == ',') {
+                    break;
+                }
+                end++;
+            }
+            String word = hands.substring(ix, end);
+            ix = end+1;
+            word = word.trim();
+            if (word.length() == 0) {
+                continue;
+            }
+            result.add(word);
+        }
+        return result.toArray(new String[result.size()]);
+    }
+
+    /**
+     * Reinitialize the logging properties and reread the logging configuration
+     * from the given stream, which should be in java.util.Properties format.
+     * A PropertyChangeEvent will be fired after the properties are read.
+     * <p>
+     * Any log level definitions in the new configuration file will be
+     * applied using Logger.setLevel(), if the target Logger exists.
+     *
+     * @param ins       stream to read properties from
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @exception  IOException if there are problems reading from the stream.
+     */
+    public void readConfiguration(InputStream ins) throws IOException, SecurityException {
+        checkPermission();
+        reset();
+
+        // Load the properties
+        props.load(ins);
+        // Instantiate new configuration objects.
+        String names[] = parseClassNames("config");
+
+        for (int i = 0; i < names.length; i++) {
+            String word = names[i];
+            try {
+                // Android-changed: Fall back from the system to the context classloader.
+                // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
+                // clz.newInstance();
+                getClassInstance(word).newInstance();
+            } catch (Exception ex) {
+                System.err.println("Can't load config class \"" + word + "\"");
+                System.err.println("" + ex);
+                // ex.printStackTrace();
+            }
+        }
+
+        // Set levels on any pre-existing loggers, based on the new properties.
+        setLevelsOnExistingLoggers();
+
+        // Notify any interested parties that our properties have changed.
+        // We first take a copy of the listener map so that we aren't holding any
+        // locks when calling the listeners.
+        Map<Object,Integer> listeners = null;
+        synchronized (listenerMap) {
+            if (!listenerMap.isEmpty())
+                listeners = new HashMap<>(listenerMap);
+        }
+        if (listeners != null) {
+            assert Beans.isBeansPresent();
+            Object ev = Beans.newPropertyChangeEvent(LogManager.class, null, null, null);
+            for (Map.Entry<Object,Integer> entry : listeners.entrySet()) {
+                Object listener = entry.getKey();
+                int count = entry.getValue().intValue();
+                for (int i = 0; i < count; i++) {
+                    Beans.invokePropertyChange(listener, ev);
+                }
+            }
+        }
+
+
+        // Note that we need to reinitialize global handles when
+        // they are first referenced.
+        synchronized (this) {
+            initializedGlobalHandlers = false;
+        }
+    }
+
+    /**
+     * Get the value of a logging property.
+     * The method returns null if the property is not found.
+     * @param name      property name
+     * @return          property value
+     */
+    public String getProperty(String name) {
+        return props.getProperty(name);
+    }
+
+    // Package private method to get a String property.
+    // If the property is not defined we return the given
+    // default value.
+    String getStringProperty(String name, String defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        return val.trim();
+    }
+
+    // Package private method to get an integer property.
+    // If the property is not defined or cannot be parsed
+    // we return the given default value.
+    int getIntProperty(String name, int defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        try {
+            return Integer.parseInt(val.trim());
+        } catch (Exception ex) {
+            return defaultValue;
+        }
+    }
+
+    // Package private method to get a boolean property.
+    // If the property is not defined or cannot be parsed
+    // we return the given default value.
+    boolean getBooleanProperty(String name, boolean defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        val = val.toLowerCase();
+        if (val.equals("true") || val.equals("1")) {
+            return true;
+        } else if (val.equals("false") || val.equals("0")) {
+            return false;
+        }
+        return defaultValue;
+    }
+
+    // Package private method to get a Level property.
+    // If the property is not defined or cannot be parsed
+    // we return the given default value.
+    Level getLevelProperty(String name, Level defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        Level l = Level.findLevel(val.trim());
+        return l != null ? l : defaultValue;
+    }
+
+    // Package private method to get a filter property.
+    // We return an instance of the class named by the "name"
+    // property. If the property is not defined or has problems
+    // we return the defaultValue.
+    Filter getFilterProperty(String name, Filter defaultValue) {
+        String val = getProperty(name);
+        try {
+            if (val != null) {
+                // Android-changed: Fall back from the system to the context classloader.
+                // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
+                // return (Filter) clz.newInstance();
+                return (Filter) getClassInstance(val).newInstance();
+            }
+        } catch (Exception ex) {
+            // We got one of a variety of exceptions in creating the
+            // class or creating an instance.
+            // Drop through.
+        }
+        // We got an exception.  Return the defaultValue.
+        return defaultValue;
+    }
+
+
+    // Package private method to get a formatter property.
+    // We return an instance of the class named by the "name"
+    // property. If the property is not defined or has problems
+    // we return the defaultValue.
+    Formatter getFormatterProperty(String name, Formatter defaultValue) {
+        String val = getProperty(name);
+        try {
+            if (val != null) {
+                // Android-changed: Fall back from the system to the context classloader.
+                // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
+                // return (Formatter) clz.newInstance();
+                return (Formatter) getClassInstance(val).newInstance();
+            }
+        } catch (Exception ex) {
+            // We got one of a variety of exceptions in creating the
+            // class or creating an instance.
+            // Drop through.
+        }
+        // We got an exception.  Return the defaultValue.
+        return defaultValue;
+    }
+
+    // Private method to load the global handlers.
+    // We do the real work lazily, when the global handlers
+    // are first used.
+    private synchronized void initializeGlobalHandlers() {
+        if (initializedGlobalHandlers) {
+            return;
+        }
+
+        initializedGlobalHandlers = true;
+
+        if (deathImminent) {
+            // Aaargh...
+            // The VM is shutting down and our exit hook has been called.
+            // Avoid allocating global handlers.
+            return;
+        }
+        loadLoggerHandlers(rootLogger, null, "handlers");
+    }
+
+    private final Permission controlPermission = new LoggingPermission("control", null);
+
+    void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(controlPermission);
+    }
+
+    /**
+     * Check that the current context is trusted to modify the logging
+     * configuration.  This requires LoggingPermission("control").
+     * <p>
+     * If the check fails we throw a SecurityException, otherwise
+     * we return normally.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     */
+    public void checkAccess() throws SecurityException {
+        checkPermission();
+    }
+
+    // Nested class to represent a node in our tree of named loggers.
+    private static class LogNode {
+        HashMap<String,LogNode> children;
+        LoggerWeakRef loggerRef;
+        LogNode parent;
+        final LoggerContext context;
+
+        LogNode(LogNode parent, LoggerContext context) {
+            this.parent = parent;
+            this.context = context;
+        }
+
+        // Recursive method to walk the tree below a node and set
+        // a new parent logger.
+        void walkAndSetParent(Logger parent) {
+            if (children == null) {
+                return;
+            }
+            Iterator<LogNode> values = children.values().iterator();
+            while (values.hasNext()) {
+                LogNode node = values.next();
+                LoggerWeakRef ref = node.loggerRef;
+                Logger logger = (ref == null) ? null : ref.get();
+                if (logger == null) {
+                    node.walkAndSetParent(parent);
+                } else {
+                    doSetParent(logger, parent);
+                }
+            }
+        }
+    }
+
+    // We use a subclass of Logger for the root logger, so
+    // that we only instantiate the global handlers when they
+    // are first needed.
+    private final class RootLogger extends Logger {
+        private RootLogger() {
+            // We do not call the protected Logger two args constructor here,
+            // to avoid calling LogManager.getLogManager() from within the
+            // RootLogger constructor.
+            super("", null, null, LogManager.this, true);
+        }
+
+        @Override
+        public void log(LogRecord record) {
+            // Make sure that the global handlers have been instantiated.
+            initializeGlobalHandlers();
+            super.log(record);
+        }
+
+        @Override
+        public void addHandler(Handler h) {
+            initializeGlobalHandlers();
+            super.addHandler(h);
+        }
+
+        @Override
+        public void removeHandler(Handler h) {
+            initializeGlobalHandlers();
+            super.removeHandler(h);
+        }
+
+        @Override
+        Handler[] accessCheckedHandlers() {
+            initializeGlobalHandlers();
+            return super.accessCheckedHandlers();
+        }
+    }
+
+
+    // Private method to be called when the configuration has
+    // changed to apply any level settings to any pre-existing loggers.
+    synchronized private void setLevelsOnExistingLoggers() {
+        Enumeration<?> enum_ = props.propertyNames();
+        while (enum_.hasMoreElements()) {
+            String key = (String)enum_.nextElement();
+            if (!key.endsWith(".level")) {
+                // Not a level definition.
+                continue;
+            }
+            int ix = key.length() - 6;
+            String name = key.substring(0, ix);
+            Level level = getLevelProperty(key, null);
+            if (level == null) {
+                System.err.println("Bad level value for property: " + key);
+                continue;
+            }
+            for (LoggerContext cx : contexts()) {
+                Logger l = cx.findLogger(name);
+                if (l == null) {
+                    continue;
+                }
+                l.setLevel(level);
+            }
+        }
+    }
+
+    // Management Support
+    private static LoggingMXBean loggingMXBean = null;
+    // Android-removed: References to java.lang.management in javadoc.
+    /**
+     * String representation of the {@code ObjectName} for the management interface
+     * for the logging facility.
+     *
+     * @see java.util.logging.LoggingMXBean
+     *
+     * @since 1.5
+     */
+    public final static String LOGGING_MXBEAN_NAME
+        = "java.util.logging:type=Logging";
+
+    // Android-removed: References to java.lang.management in javadoc.
+    /**
+     * Returns <tt>LoggingMXBean</tt> for managing loggers.
+     *
+     * @return a {@link LoggingMXBean} object.
+     *
+     * @since 1.5
+     */
+    public static synchronized LoggingMXBean getLoggingMXBean() {
+        if (loggingMXBean == null) {
+            loggingMXBean =  new Logging();
+        }
+        return loggingMXBean;
+    }
+
+    /**
+     * A class that provides access to the java.beans.PropertyChangeListener
+     * and java.beans.PropertyChangeEvent without creating a static dependency
+     * on java.beans. This class can be removed once the addPropertyChangeListener
+     * and removePropertyChangeListener methods are removed.
+     */
+    private static class Beans {
+        private static final Class<?> propertyChangeListenerClass =
+            getClass("java.beans.PropertyChangeListener");
+
+        private static final Class<?> propertyChangeEventClass =
+            getClass("java.beans.PropertyChangeEvent");
+
+        private static final Method propertyChangeMethod =
+            getMethod(propertyChangeListenerClass,
+                      "propertyChange",
+                      propertyChangeEventClass);
+
+        private static final Constructor<?> propertyEventCtor =
+            getConstructor(propertyChangeEventClass,
+                           Object.class,
+                           String.class,
+                           Object.class,
+                           Object.class);
+
+        private static Class<?> getClass(String name) {
+            try {
+                return Class.forName(name, true, Beans.class.getClassLoader());
+            } catch (ClassNotFoundException e) {
+                return null;
+            }
+        }
+        private static Constructor<?> getConstructor(Class<?> c, Class<?>... types) {
+            try {
+                return (c == null) ? null : c.getDeclaredConstructor(types);
+            } catch (NoSuchMethodException x) {
+                throw new AssertionError(x);
+            }
+        }
+
+        private static Method getMethod(Class<?> c, String name, Class<?>... types) {
+            try {
+                return (c == null) ? null : c.getMethod(name, types);
+            } catch (NoSuchMethodException e) {
+                throw new AssertionError(e);
+            }
+        }
+
+        /**
+         * Returns {@code true} if java.beans is present.
+         */
+        static boolean isBeansPresent() {
+            return propertyChangeListenerClass != null &&
+                   propertyChangeEventClass != null;
+        }
+
+        /**
+         * Returns a new PropertyChangeEvent with the given source, property
+         * name, old and new values.
+         */
+        static Object newPropertyChangeEvent(Object source, String prop,
+                                             Object oldValue, Object newValue)
+        {
+            try {
+                return propertyEventCtor.newInstance(source, prop, oldValue, newValue);
+            } catch (InstantiationException | IllegalAccessException x) {
+                throw new AssertionError(x);
+            } catch (InvocationTargetException x) {
+                Throwable cause = x.getCause();
+                if (cause instanceof Error)
+                    throw (Error)cause;
+                if (cause instanceof RuntimeException)
+                    throw (RuntimeException)cause;
+                throw new AssertionError(x);
+            }
+        }
+
+        /**
+         * Invokes the given PropertyChangeListener's propertyChange method
+         * with the given event.
+         */
+        static void invokePropertyChange(Object listener, Object ev) {
+            try {
+                propertyChangeMethod.invoke(listener, ev);
+            } catch (IllegalAccessException x) {
+                throw new AssertionError(x);
+            } catch (InvocationTargetException x) {
+                Throwable cause = x.getCause();
+                if (cause instanceof Error)
+                    throw (Error)cause;
+                if (cause instanceof RuntimeException)
+                    throw (RuntimeException)cause;
+                throw new AssertionError(x);
+            }
+        }
+    }
+}
diff --git a/java/util/logging/LogRecord.java b/java/util/logging/LogRecord.java
new file mode 100644
index 0000000..3b0e518
--- /dev/null
+++ b/java/util/logging/LogRecord.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+import dalvik.system.VMStack;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.io.*;
+
+/**
+ * LogRecord objects are used to pass logging requests between
+ * the logging framework and individual log Handlers.
+ * <p>
+ * When a LogRecord is passed into the logging framework it
+ * logically belongs to the framework and should no longer be
+ * used or updated by the client application.
+ * <p>
+ * Note that if the client application has not specified an
+ * explicit source method name and source class name, then the
+ * LogRecord class will infer them automatically when they are
+ * first accessed (due to a call on getSourceMethodName or
+ * getSourceClassName) by analyzing the call stack.  Therefore,
+ * if a logging Handler wants to pass off a LogRecord to another
+ * thread, or to transmit it over RMI, and if it wishes to subsequently
+ * obtain method name or class name information it should call
+ * one of getSourceClassName or getSourceMethodName to force
+ * the values to be filled in.
+ * <p>
+ * <b> Serialization notes:</b>
+ * <ul>
+ * <li>The LogRecord class is serializable.
+ *
+ * <li> Because objects in the parameters array may not be serializable,
+ * during serialization all objects in the parameters array are
+ * written as the corresponding Strings (using Object.toString).
+ *
+ * <li> The ResourceBundle is not transmitted as part of the serialized
+ * form, but the resource bundle name is, and the recipient object's
+ * readObject method will attempt to locate a suitable resource bundle.
+ *
+ * </ul>
+ *
+ * @since 1.4
+ */
+
+public class LogRecord implements java.io.Serializable {
+    private static final AtomicLong globalSequenceNumber
+        = new AtomicLong(0);
+
+    /**
+     * The default value of threadID will be the current thread's
+     * thread id, for ease of correlation, unless it is greater than
+     * MIN_SEQUENTIAL_THREAD_ID, in which case we try harder to keep
+     * our promise to keep threadIDs unique by avoiding collisions due
+     * to 32-bit wraparound.  Unfortunately, LogRecord.getThreadID()
+     * returns int, while Thread.getId() returns long.
+     */
+    private static final int MIN_SEQUENTIAL_THREAD_ID = Integer.MAX_VALUE / 2;
+
+    private static final AtomicInteger nextThreadId
+        = new AtomicInteger(MIN_SEQUENTIAL_THREAD_ID);
+
+    private static final ThreadLocal<Integer> threadIds = new ThreadLocal<>();
+
+    /**
+     * @serial Logging message level
+     */
+    private Level level;
+
+    /**
+     * @serial Sequence number
+     */
+    private long sequenceNumber;
+
+    /**
+     * @serial Class that issued logging call
+     */
+    private String sourceClassName;
+
+    /**
+     * @serial Method that issued logging call
+     */
+    private String sourceMethodName;
+
+    /**
+     * @serial Non-localized raw message text
+     */
+    private String message;
+
+    /**
+     * @serial Thread ID for thread that issued logging call.
+     */
+    private int threadID;
+
+    /**
+     * @serial Event time in milliseconds since 1970
+     */
+    private long millis;
+
+    /**
+     * @serial The Throwable (if any) associated with log message
+     */
+    private Throwable thrown;
+
+    /**
+     * @serial Name of the source Logger.
+     */
+    private String loggerName;
+
+    /**
+     * @serial Resource bundle name to localized log message.
+     */
+    private String resourceBundleName;
+
+    private transient boolean needToInferCaller;
+    private transient Object parameters[];
+    private transient ResourceBundle resourceBundle;
+
+    /**
+     * Returns the default value for a new LogRecord's threadID.
+     */
+    private int defaultThreadID() {
+        long tid = Thread.currentThread().getId();
+        if (tid < MIN_SEQUENTIAL_THREAD_ID) {
+            return (int) tid;
+        } else {
+            Integer id = threadIds.get();
+            if (id == null) {
+                id = nextThreadId.getAndIncrement();
+                threadIds.set(id);
+            }
+            return id;
+        }
+    }
+
+    /**
+     * Construct a LogRecord with the given level and message values.
+     * <p>
+     * The sequence property will be initialized with a new unique value.
+     * These sequence values are allocated in increasing order within a VM.
+     * <p>
+     * The millis property will be initialized to the current time.
+     * <p>
+     * The thread ID property will be initialized with a unique ID for
+     * the current thread.
+     * <p>
+     * All other properties will be initialized to "null".
+     *
+     * @param level  a logging level value
+     * @param msg  the raw non-localized logging message (may be null)
+     */
+    public LogRecord(Level level, String msg) {
+        // Make sure level isn't null, by calling random method.
+        level.getClass();
+        this.level = level;
+        message = msg;
+        // Assign a thread ID and a unique sequence number.
+        sequenceNumber = globalSequenceNumber.getAndIncrement();
+        threadID = defaultThreadID();
+        millis = System.currentTimeMillis();
+        needToInferCaller = true;
+   }
+
+    /**
+     * Get the source Logger's name.
+     *
+     * @return source logger name (may be null)
+     */
+    public String getLoggerName() {
+        return loggerName;
+    }
+
+    /**
+     * Set the source Logger's name.
+     *
+     * @param name   the source logger name (may be null)
+     */
+    public void setLoggerName(String name) {
+        loggerName = name;
+    }
+
+    /**
+     * Get the localization resource bundle
+     * <p>
+     * This is the ResourceBundle that should be used to localize
+     * the message string before formatting it.  The result may
+     * be null if the message is not localizable, or if no suitable
+     * ResourceBundle is available.
+     * @return the localization resource bundle
+     */
+    public ResourceBundle getResourceBundle() {
+        return resourceBundle;
+    }
+
+    /**
+     * Set the localization resource bundle.
+     *
+     * @param bundle  localization bundle (may be null)
+     */
+    public void setResourceBundle(ResourceBundle bundle) {
+        resourceBundle = bundle;
+    }
+
+    /**
+     * Get the localization resource bundle name
+     * <p>
+     * This is the name for the ResourceBundle that should be
+     * used to localize the message string before formatting it.
+     * The result may be null if the message is not localizable.
+     * @return the localization resource bundle name
+     */
+    public String getResourceBundleName() {
+        return resourceBundleName;
+    }
+
+    /**
+     * Set the localization resource bundle name.
+     *
+     * @param name  localization bundle name (may be null)
+     */
+    public void setResourceBundleName(String name) {
+        resourceBundleName = name;
+    }
+
+    /**
+     * Get the logging message level, for example Level.SEVERE.
+     * @return the logging message level
+     */
+    public Level getLevel() {
+        return level;
+    }
+
+    /**
+     * Set the logging message level, for example Level.SEVERE.
+     * @param level the logging message level
+     */
+    public void setLevel(Level level) {
+        if (level == null) {
+            throw new NullPointerException();
+        }
+        this.level = level;
+    }
+
+    /**
+     * Get the sequence number.
+     * <p>
+     * Sequence numbers are normally assigned in the LogRecord
+     * constructor, which assigns unique sequence numbers to
+     * each new LogRecord in increasing order.
+     * @return the sequence number
+     */
+    public long getSequenceNumber() {
+        return sequenceNumber;
+    }
+
+    /**
+     * Set the sequence number.
+     * <p>
+     * Sequence numbers are normally assigned in the LogRecord constructor,
+     * so it should not normally be necessary to use this method.
+     * @param seq the sequence number
+     */
+    public void setSequenceNumber(long seq) {
+        sequenceNumber = seq;
+    }
+
+    /**
+     * Get the  name of the class that (allegedly) issued the logging request.
+     * <p>
+     * Note that this sourceClassName is not verified and may be spoofed.
+     * This information may either have been provided as part of the
+     * logging call, or it may have been inferred automatically by the
+     * logging framework.  In the latter case, the information may only
+     * be approximate and may in fact describe an earlier call on the
+     * stack frame.
+     * <p>
+     * May be null if no information could be obtained.
+     *
+     * @return the source class name
+     */
+    public String getSourceClassName() {
+        if (needToInferCaller) {
+            inferCaller();
+        }
+        return sourceClassName;
+    }
+
+    /**
+     * Set the name of the class that (allegedly) issued the logging request.
+     *
+     * @param sourceClassName the source class name (may be null)
+     */
+    public void setSourceClassName(String sourceClassName) {
+        this.sourceClassName = sourceClassName;
+        needToInferCaller = false;
+    }
+
+    /**
+     * Get the  name of the method that (allegedly) issued the logging request.
+     * <p>
+     * Note that this sourceMethodName is not verified and may be spoofed.
+     * This information may either have been provided as part of the
+     * logging call, or it may have been inferred automatically by the
+     * logging framework.  In the latter case, the information may only
+     * be approximate and may in fact describe an earlier call on the
+     * stack frame.
+     * <p>
+     * May be null if no information could be obtained.
+     *
+     * @return the source method name
+     */
+    public String getSourceMethodName() {
+        if (needToInferCaller) {
+            inferCaller();
+        }
+        return sourceMethodName;
+    }
+
+    /**
+     * Set the name of the method that (allegedly) issued the logging request.
+     *
+     * @param sourceMethodName the source method name (may be null)
+     */
+    public void setSourceMethodName(String sourceMethodName) {
+        this.sourceMethodName = sourceMethodName;
+        needToInferCaller = false;
+    }
+
+    /**
+     * Get the "raw" log message, before localization or formatting.
+     * <p>
+     * May be null, which is equivalent to the empty string "".
+     * <p>
+     * This message may be either the final text or a localization key.
+     * <p>
+     * During formatting, if the source logger has a localization
+     * ResourceBundle and if that ResourceBundle has an entry for
+     * this message string, then the message string is replaced
+     * with the localized value.
+     *
+     * @return the raw message string
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    /**
+     * Set the "raw" log message, before localization or formatting.
+     *
+     * @param message the raw message string (may be null)
+     */
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    /**
+     * Get the parameters to the log message.
+     *
+     * @return the log message parameters.  May be null if
+     *                  there are no parameters.
+     */
+    public Object[] getParameters() {
+        return parameters;
+    }
+
+    /**
+     * Set the parameters to the log message.
+     *
+     * @param parameters the log message parameters. (may be null)
+     */
+    public void setParameters(Object parameters[]) {
+        this.parameters = parameters;
+    }
+
+    /**
+     * Get an identifier for the thread where the message originated.
+     * <p>
+     * This is a thread identifier within the Java VM and may or
+     * may not map to any operating system ID.
+     *
+     * @return thread ID
+     */
+    public int getThreadID() {
+        return threadID;
+    }
+
+    /**
+     * Set an identifier for the thread where the message originated.
+     * @param threadID  the thread ID
+     */
+    public void setThreadID(int threadID) {
+        this.threadID = threadID;
+    }
+
+    /**
+     * Get event time in milliseconds since 1970.
+     *
+     * @return event time in millis since 1970
+     */
+    public long getMillis() {
+        return millis;
+    }
+
+    /**
+     * Set event time.
+     *
+     * @param millis event time in millis since 1970
+     */
+    public void setMillis(long millis) {
+        this.millis = millis;
+    }
+
+    /**
+     * Get any throwable associated with the log record.
+     * <p>
+     * If the event involved an exception, this will be the
+     * exception object. Otherwise null.
+     *
+     * @return a throwable
+     */
+    public Throwable getThrown() {
+        return thrown;
+    }
+
+    /**
+     * Set a throwable associated with the log event.
+     *
+     * @param thrown  a throwable (may be null)
+     */
+    public void setThrown(Throwable thrown) {
+        this.thrown = thrown;
+    }
+
+    private static final long serialVersionUID = 5372048053134512534L;
+
+    /**
+     * @serialData Default fields, followed by a two byte version number
+     * (major byte, followed by minor byte), followed by information on
+     * the log record parameter array.  If there is no parameter array,
+     * then -1 is written.  If there is a parameter array (possible of zero
+     * length) then the array length is written as an integer, followed
+     * by String values for each parameter.  If a parameter is null, then
+     * a null String is written.  Otherwise the output of Object.toString()
+     * is written.
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        // We have to call defaultWriteObject first.
+        out.defaultWriteObject();
+
+        // Write our version number.
+        out.writeByte(1);
+        out.writeByte(0);
+        if (parameters == null) {
+            out.writeInt(-1);
+            return;
+        }
+        out.writeInt(parameters.length);
+        // Write string values for the parameters.
+        for (int i = 0; i < parameters.length; i++) {
+            if (parameters[i] == null) {
+                out.writeObject(null);
+            } else {
+                out.writeObject(parameters[i].toString());
+            }
+        }
+    }
+
+    private void readObject(ObjectInputStream in)
+                        throws IOException, ClassNotFoundException {
+        // We have to call defaultReadObject first.
+        in.defaultReadObject();
+
+        // Read version number.
+        byte major = in.readByte();
+        byte minor = in.readByte();
+        if (major != 1) {
+            throw new IOException("LogRecord: bad version: " + major + "." + minor);
+        }
+        int len = in.readInt();
+        if (len < -1) {
+            throw new NegativeArraySizeException();
+        } else if (len == -1) {
+            parameters = null;
+        } else if (len < 255) {
+            parameters = new Object[len];
+            for (int i = 0; i < parameters.length; i++) {
+                parameters[i] = in.readObject();
+            }
+        } else {
+            List<Object> params = new ArrayList<>(Math.min(len, 1024));
+            for (int i = 0; i < len; i++) {
+                params.add(in.readObject());
+            }
+            parameters = params.toArray(new Object[params.size()]);
+        }
+        // If necessary, try to regenerate the resource bundle.
+        if (resourceBundleName != null) {
+            try {
+                // use system class loader to ensure the ResourceBundle
+                // instance is a different instance than null loader uses
+                final ResourceBundle bundle =
+                        ResourceBundle.getBundle(resourceBundleName,
+                                Locale.getDefault(),
+                                ClassLoader.getSystemClassLoader());
+                resourceBundle = bundle;
+            } catch (MissingResourceException ex) {
+                // Android-changed: Fall back to context classloader before giving up.
+                /*
+                // This is not a good place to throw an exception,
+                // so we simply leave the resourceBundle null.
+                resourceBundle = null;
+                */
+                try {
+                    resourceBundle = ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(),
+                            Thread.currentThread().getContextClassLoader());
+                } catch (MissingResourceException innerE){
+                    // This is not a good place to throw an exception,
+                    // so we simply leave the resourceBundle null.
+                    resourceBundle = null;
+                }
+            }
+        }
+
+        needToInferCaller = false;
+    }
+
+    // Private method to infer the caller's class and method names
+    private void inferCaller() {
+        needToInferCaller = false;
+        // BEGIN Android-changed: Use VMStack.getThreadStackTrace.
+        /*
+        JavaLangAccess access = SharedSecrets.getJavaLangAccess();
+        Throwable throwable = new Throwable();
+        int depth = access.getStackTraceDepth(throwable);
+        */
+        StackTraceElement[] stack = VMStack.getThreadStackTrace(Thread.currentThread());
+        int depth = stack.length;
+        // END Android-changed: Use VMStack.getThreadStackTrace.
+
+        boolean lookingForLogger = true;
+        for (int ix = 0; ix < depth; ix++) {
+            // Calling getStackTraceElement directly prevents the VM
+            // from paying the cost of building the entire stack frame.
+            //
+            // Android-changed: Use value from previous getThreadStackTrace call.
+            // StackTraceElement frame =
+            //     access.getStackTraceElement(throwable, ix);
+            StackTraceElement frame = stack[ix];
+            String cname = frame.getClassName();
+            boolean isLoggerImpl = isLoggerImplFrame(cname);
+            if (lookingForLogger) {
+                // Skip all frames until we have found the first logger frame.
+                if (isLoggerImpl) {
+                    lookingForLogger = false;
+                }
+            } else {
+                if (!isLoggerImpl) {
+                    // skip reflection call
+                    if (!cname.startsWith("java.lang.reflect.") && !cname.startsWith("sun.reflect.")) {
+                       // We've found the relevant frame.
+                       setSourceClassName(cname);
+                       setSourceMethodName(frame.getMethodName());
+                       return;
+                    }
+                }
+            }
+        }
+        // We haven't found a suitable frame, so just punt.  This is
+        // OK as we are only committed to making a "best effort" here.
+    }
+
+    private boolean isLoggerImplFrame(String cname) {
+        // the log record could be created for a platform logger
+        return (cname.equals("java.util.logging.Logger") ||
+                cname.startsWith("java.util.logging.LoggingProxyImpl") ||
+                cname.startsWith("sun.util.logging."));
+    }
+}
diff --git a/java/util/logging/Logger.annotated.java b/java/util/logging/Logger.annotated.java
new file mode 100644
index 0000000..f3a25cb
--- /dev/null
+++ b/java/util/logging/Logger.annotated.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package java.util.logging;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.function.Supplier;
+import java.util.MissingResourceException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Logger {
+
+protected Logger(@libcore.util.Nullable java.lang.String name, @libcore.util.Nullable java.lang.String resourceBundleName) { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.util.logging.Logger getGlobal() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.logging.Logger getLogger(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.logging.Logger getLogger(@libcore.util.NonNull java.lang.String name, @libcore.util.Nullable java.lang.String resourceBundleName) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.logging.Logger getAnonymousLogger() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.logging.Logger getAnonymousLogger(@libcore.util.Nullable java.lang.String resourceBundleName) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ResourceBundle getResourceBundle() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getResourceBundleName() { throw new RuntimeException("Stub!"); }
+
+public void setFilter(@libcore.util.Nullable java.util.logging.Filter newFilter) throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.logging.Filter getFilter() { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.LogRecord record) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Object param1) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String msg, [email protected] Object @libcore.util.Nullable [] params) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Throwable thrown) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.Throwable thrown, @libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Object param1) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg, [email protected] Object @libcore.util.Nullable [] params) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Throwable thrown) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.Throwable thrown, @libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String bundleName, @libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String bundleName, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Object param1) { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String bundleName, @libcore.util.Nullable java.lang.String msg, [email protected] Object @libcore.util.Nullable [] params) { throw new RuntimeException("Stub!"); }
+
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.util.ResourceBundle bundle, @libcore.util.Nullable java.lang.String msg, [email protected] Object @libcore.util.Nullable ... params) { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String bundleName, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Throwable thrown) { throw new RuntimeException("Stub!"); }
+
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.util.ResourceBundle bundle, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Throwable thrown) { throw new RuntimeException("Stub!"); }
+
+public void entering(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod) { throw new RuntimeException("Stub!"); }
+
+public void entering(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.Object param1) { throw new RuntimeException("Stub!"); }
+
+public void entering(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, [email protected] Object @libcore.util.Nullable [] params) { throw new RuntimeException("Stub!"); }
+
+public void exiting(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod) { throw new RuntimeException("Stub!"); }
+
+public void exiting(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.Object result) { throw new RuntimeException("Stub!"); }
+
+public void throwing(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.Throwable thrown) { throw new RuntimeException("Stub!"); }
+
+public void severe(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void warning(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void info(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void config(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void fine(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void finer(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void finest(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void severe(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void warning(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void info(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void config(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void fine(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void finer(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void finest(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void setLevel(@libcore.util.Nullable java.util.logging.Level newLevel) throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.logging.Level getLevel() { throw new RuntimeException("Stub!"); }
+
+public boolean isLoggable(@libcore.util.NonNull java.util.logging.Level level) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
+public void addHandler(@libcore.util.NonNull java.util.logging.Handler handler) throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public void removeHandler(@libcore.util.Nullable java.util.logging.Handler handler) throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public [email protected] Handler @libcore.util.NonNull [] getHandlers() { throw new RuntimeException("Stub!"); }
+
+public void setUseParentHandlers(boolean useParentHandlers) { throw new RuntimeException("Stub!"); }
+
+public boolean getUseParentHandlers() { throw new RuntimeException("Stub!"); }
+
+public void setResourceBundle(@libcore.util.NonNull java.util.ResourceBundle bundle) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.logging.Logger getParent() { throw new RuntimeException("Stub!"); }
+
+public void setParent(@libcore.util.NonNull java.util.logging.Logger parent) { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.lang.String GLOBAL_LOGGER_NAME = "global";
+
+@Deprecated @libcore.util.NonNull public static final java.util.logging.Logger global;
+static { global = null; }
+}
diff --git a/java/util/logging/Logger.java b/java/util/logging/Logger.java
new file mode 100644
index 0000000..61bbe4e
--- /dev/null
+++ b/java/util/logging/Logger.java
@@ -0,0 +1,2188 @@
+/*
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.lang.ref.WeakReference;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Supplier;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+/**
+ * A Logger object is used to log messages for a specific
+ * system or application component.  Loggers are normally named,
+ * using a hierarchical dot-separated namespace.  Logger names
+ * can be arbitrary strings, but they should normally be based on
+ * the package name or class name of the logged component, such
+ * as java.net or javax.swing.  In addition it is possible to create
+ * "anonymous" Loggers that are not stored in the Logger namespace.
+ * <p>
+ * Logger objects may be obtained by calls on one of the getLogger
+ * factory methods.  These will either create a new Logger or
+ * return a suitable existing Logger. It is important to note that
+ * the Logger returned by one of the {@code getLogger} factory methods
+ * may be garbage collected at any time if a strong reference to the
+ * Logger is not kept.
+ * <p>
+ * Logging messages will be forwarded to registered Handler
+ * objects, which can forward the messages to a variety of
+ * destinations, including consoles, files, OS logs, etc.
+ * <p>
+ * Each Logger keeps track of a "parent" Logger, which is its
+ * nearest existing ancestor in the Logger namespace.
+ * <p>
+ * Each Logger has a "Level" associated with it.  This reflects
+ * a minimum Level that this logger cares about.  If a Logger's
+ * level is set to <tt>null</tt>, then its effective level is inherited
+ * from its parent, which may in turn obtain it recursively from its
+ * parent, and so on up the tree.
+ * <p>
+ * The log level can be configured based on the properties from the
+ * logging configuration file, as described in the description
+ * of the LogManager class.  However it may also be dynamically changed
+ * by calls on the Logger.setLevel method.  If a logger's level is
+ * changed the change may also affect child loggers, since any child
+ * logger that has <tt>null</tt> as its level will inherit its
+ * effective level from its parent.
+ * <p>
+ * On each logging call the Logger initially performs a cheap
+ * check of the request level (e.g., SEVERE or FINE) against the
+ * effective log level of the logger.  If the request level is
+ * lower than the log level, the logging call returns immediately.
+ * <p>
+ * After passing this initial (cheap) test, the Logger will allocate
+ * a LogRecord to describe the logging message.  It will then call a
+ * Filter (if present) to do a more detailed check on whether the
+ * record should be published.  If that passes it will then publish
+ * the LogRecord to its output Handlers.  By default, loggers also
+ * publish to their parent's Handlers, recursively up the tree.
+ * <p>
+ * Each Logger may have a {@code ResourceBundle} associated with it.
+ * The {@code ResourceBundle} may be specified by name, using the
+ * {@link #getLogger(java.lang.String, java.lang.String)} factory
+ * method, or by value - using the {@link
+ * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
+ * This bundle will be used for localizing logging messages.
+ * If a Logger does not have its own {@code ResourceBundle} or resource bundle
+ * name, then it will inherit the {@code ResourceBundle} or resource bundle name
+ * from its parent, recursively up the tree.
+ * <p>
+ * Most of the logger output methods take a "msg" argument.  This
+ * msg argument may be either a raw value or a localization key.
+ * During formatting, if the logger has (or inherits) a localization
+ * {@code ResourceBundle} and if the {@code ResourceBundle} has a mapping for
+ * the msg string, then the msg string is replaced by the localized value.
+ * Otherwise the original msg string is used.  Typically, formatters use
+ * java.text.MessageFormat style formatting to format parameters, so
+ * for example a format string "{0} {1}" would format two parameters
+ * as strings.
+ * <p>
+ * A set of methods alternatively take a "msgSupplier" instead of a "msg"
+ * argument.  These methods take a {@link Supplier}{@code <String>} function
+ * which is invoked to construct the desired log message only when the message
+ * actually is to be logged based on the effective log level thus eliminating
+ * unnecessary message construction. For example, if the developer wants to
+ * log system health status for diagnosis, with the String-accepting version,
+ * the code would look like:
+ <pre><code>
+
+   class DiagnosisMessages {
+     static String systemHealthStatus() {
+       // collect system health information
+       ...
+     }
+   }
+   ...
+   logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus());
+</code></pre>
+ * With the above code, the health status is collected unnecessarily even when
+ * the log level FINER is disabled. With the Supplier-accepting version as
+ * below, the status will only be collected when the log level FINER is
+ * enabled.
+ <pre><code>
+
+   logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus);
+</code></pre>
+ * <p>
+ * When looking for a {@code ResourceBundle}, the logger will first look at
+ * whether a bundle was specified using {@link
+ * #setResourceBundle(java.util.ResourceBundle) setResourceBundle}, and then
+ * only whether a resource bundle name was specified through the {@link
+ * #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
+ * If no {@code ResourceBundle} or no resource bundle name is found,
+ * then it will use the nearest {@code ResourceBundle} or resource bundle
+ * name inherited from its parent tree.<br>
+ * When a {@code ResourceBundle} was inherited or specified through the
+ * {@link
+ * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method, then
+ * that {@code ResourceBundle} will be used. Otherwise if the logger only
+ * has or inherited a resource bundle name, then that resource bundle name
+ * will be mapped to a {@code ResourceBundle} object, using the default Locale
+ * at the time of logging.
+ * <br id="ResourceBundleMapping">When mapping resource bundle names to
+ * {@code ResourceBundle} objects, the logger will first try to use the
+ * Thread's {@linkplain java.lang.Thread#getContextClassLoader() context class
+ * loader} to map the given resource bundle name to a {@code ResourceBundle}.
+ * If the thread context class loader is {@code null}, it will try the
+ * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system class loader}
+ * instead.  If the {@code ResourceBundle} is still not found, it will use the
+ * class loader of the first caller of the {@link
+ * #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
+ * <p>
+ * Formatting (including localization) is the responsibility of
+ * the output Handler, which will typically call a Formatter.
+ * <p>
+ * Note that formatting need not occur synchronously.  It may be delayed
+ * until a LogRecord is actually written to an external sink.
+ * <p>
+ * The logging methods are grouped in five main categories:
+ * <ul>
+ * <li><p>
+ *     There are a set of "log" methods that take a log level, a message
+ *     string, and optionally some parameters to the message string.
+ * <li><p>
+ *     There are a set of "logp" methods (for "log precise") that are
+ *     like the "log" methods, but also take an explicit source class name
+ *     and method name.
+ * <li><p>
+ *     There are a set of "logrb" method (for "log with resource bundle")
+ *     that are like the "logp" method, but also take an explicit resource
+ *     bundle object for use in localizing the log message.
+ * <li><p>
+ *     There are convenience methods for tracing method entries (the
+ *     "entering" methods), method returns (the "exiting" methods) and
+ *     throwing exceptions (the "throwing" methods).
+ * <li><p>
+ *     Finally, there are a set of convenience methods for use in the
+ *     very simplest cases, when a developer simply wants to log a
+ *     simple string at a given log level.  These methods are named
+ *     after the standard Level names ("severe", "warning", "info", etc.)
+ *     and take a single argument, a message string.
+ * </ul>
+ * <p>
+ * For the methods that do not take an explicit source name and
+ * method name, the Logging framework will make a "best effort"
+ * to determine which class and method called into the logging method.
+ * However, it is important to realize that this automatically inferred
+ * information may only be approximate (or may even be quite wrong!).
+ * Virtual machines are allowed to do extensive optimizations when
+ * JITing and may entirely remove stack frames, making it impossible
+ * to reliably locate the calling class and method.
+ * <P>
+ * All methods on Logger are multi-thread safe.
+ * <p>
+ * <b>Subclassing Information:</b> Note that a LogManager class may
+ * provide its own implementation of named Loggers for any point in
+ * the namespace.  Therefore, any subclasses of Logger (unless they
+ * are implemented in conjunction with a new LogManager class) should
+ * take care to obtain a Logger instance from the LogManager class and
+ * should delegate operations such as "isLoggable" and "log(LogRecord)"
+ * to that instance.  Note that in order to intercept all logging
+ * output, subclasses need only override the log(LogRecord) method.
+ * All the other logging methods are implemented as calls on this
+ * log(LogRecord) method.
+ *
+ * @since 1.4
+ */
+public class Logger {
+    private static final Handler emptyHandlers[] = new Handler[0];
+    private static final int offValue = Level.OFF.intValue();
+
+    static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging";
+
+    // This class is immutable and it is important that it remains so.
+    private static final class LoggerBundle {
+        final String resourceBundleName; // Base name of the bundle.
+        final ResourceBundle userBundle; // Bundle set through setResourceBundle.
+        private LoggerBundle(String resourceBundleName, ResourceBundle bundle) {
+            this.resourceBundleName = resourceBundleName;
+            this.userBundle = bundle;
+        }
+        boolean isSystemBundle() {
+            return SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName);
+        }
+        static LoggerBundle get(String name, ResourceBundle bundle) {
+            if (name == null && bundle == null) {
+                return NO_RESOURCE_BUNDLE;
+            } else if (SYSTEM_LOGGER_RB_NAME.equals(name) && bundle == null) {
+                return SYSTEM_BUNDLE;
+            } else {
+                return new LoggerBundle(name, bundle);
+            }
+        }
+    }
+
+    // This instance will be shared by all loggers created by the system
+    // code
+    private static final LoggerBundle SYSTEM_BUNDLE =
+            new LoggerBundle(SYSTEM_LOGGER_RB_NAME, null);
+
+    // This instance indicates that no resource bundle has been specified yet,
+    // and it will be shared by all loggers which have no resource bundle.
+    private static final LoggerBundle NO_RESOURCE_BUNDLE =
+            new LoggerBundle(null, null);
+
+    private volatile LogManager manager;
+    private String name;
+    private final CopyOnWriteArrayList<Handler> handlers =
+        new CopyOnWriteArrayList<>();
+    private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE;
+    private volatile boolean useParentHandlers = true;
+    private volatile Filter filter;
+    private boolean anonymous;
+
+    // Cache to speed up behavior of findResourceBundle:
+    private ResourceBundle catalog;     // Cached resource bundle
+    private String catalogName;         // name associated with catalog
+    private Locale catalogLocale;       // locale associated with catalog
+
+    // The fields relating to parent-child relationships and levels
+    // are managed under a separate lock, the treeLock.
+    private static final Object treeLock = new Object();
+    // We keep weak references from parents to children, but strong
+    // references from children to parents.
+    private volatile Logger parent;    // our nearest parent.
+    private ArrayList<LogManager.LoggerWeakRef> kids;   // WeakReferences to loggers that have us as parent
+    private volatile Level levelObject;
+    private volatile int levelValue;  // current effective level value
+    private WeakReference<ClassLoader> callersClassLoaderRef;
+    private final boolean isSystemLogger;
+
+    /**
+     * GLOBAL_LOGGER_NAME is a name for the global logger.
+     *
+     * @since 1.6
+     */
+    public static final String GLOBAL_LOGGER_NAME = "global";
+
+    /**
+     * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME.
+     *
+     * @return global logger object
+     * @since 1.7
+     */
+    public static final Logger getGlobal() {
+        // In order to break a cyclic dependence between the LogManager
+        // and Logger static initializers causing deadlocks, the global
+        // logger is created with a special constructor that does not
+        // initialize its log manager.
+        //
+        // If an application calls Logger.getGlobal() before any logger
+        // has been initialized, it is therefore possible that the
+        // LogManager class has not been initialized yet, and therefore
+        // Logger.global.manager will be null.
+        //
+        // In order to finish the initialization of the global logger, we
+        // will therefore call LogManager.getLogManager() here.
+        //
+        // To prevent race conditions we also need to call
+        // LogManager.getLogManager() unconditionally here.
+        // Indeed we cannot rely on the observed value of global.manager,
+        // because global.manager will become not null somewhere during
+        // the initialization of LogManager.
+        // If two threads are calling getGlobal() concurrently, one thread
+        // will see global.manager null and call LogManager.getLogManager(),
+        // but the other thread could come in at a time when global.manager
+        // is already set although ensureLogManagerInitialized is not finished
+        // yet...
+        // Calling LogManager.getLogManager() unconditionally will fix that.
+
+        LogManager.getLogManager();
+
+        // Now the global LogManager should be initialized,
+        // and the global logger should have been added to
+        // it, unless we were called within the constructor of a LogManager
+        // subclass installed as LogManager, in which case global.manager
+        // would still be null, and global will be lazily initialized later on.
+
+        return global;
+    }
+
+    /**
+     * The "global" Logger object is provided as a convenience to developers
+     * who are making casual use of the Logging package.  Developers
+     * who are making serious use of the logging package (for example
+     * in products) should create and use their own Logger objects,
+     * with appropriate names, so that logging can be controlled on a
+     * suitable per-Logger granularity. Developers also need to keep a
+     * strong reference to their Logger objects to prevent them from
+     * being garbage collected.
+     * <p>
+     * @deprecated Initialization of this field is prone to deadlocks.
+     * The field must be initialized by the Logger class initialization
+     * which may cause deadlocks with the LogManager class initialization.
+     * In such cases two class initialization wait for each other to complete.
+     * The preferred way to get the global logger object is via the call
+     * <code>Logger.getGlobal()</code>.
+     * For compatibility with old JDK versions where the
+     * <code>Logger.getGlobal()</code> is not available use the call
+     * <code>Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)</code>
+     * or <code>Logger.getLogger("global")</code>.
+     */
+    @Deprecated
+    public static final Logger global = new Logger(GLOBAL_LOGGER_NAME);
+
+    /**
+     * Protected method to construct a logger for a named subsystem.
+     * <p>
+     * The logger will be initially configured with a null Level
+     * and with useParentHandlers set to true.
+     *
+     * @param   name    A name for the logger.  This should
+     *                          be a dot-separated name and should normally
+     *                          be based on the package name or class name
+     *                          of the subsystem, such as java.net
+     *                          or javax.swing.  It may be null for anonymous Loggers.
+     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
+     *                          messages for this logger.  May be null if none
+     *                          of the messages require localization.
+     * @throws MissingResourceException if the resourceBundleName is non-null and
+     *             no corresponding resource can be found.
+     */
+    protected Logger(String name, String resourceBundleName) {
+        this(name, resourceBundleName, null, LogManager.getLogManager(), false);
+    }
+
+    Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager, boolean isSystemLogger) {
+        this.manager = manager;
+        this.isSystemLogger = isSystemLogger;
+        setupResourceInfo(resourceBundleName, caller);
+        this.name = name;
+        levelValue = Level.INFO.intValue();
+    }
+
+    private void setCallersClassLoaderRef(Class<?> caller) {
+        ClassLoader callersClassLoader = ((caller != null)
+                                         ? caller.getClassLoader()
+                                         : null);
+        if (callersClassLoader != null) {
+            this.callersClassLoaderRef = new WeakReference<>(callersClassLoader);
+        }
+    }
+
+    private ClassLoader getCallersClassLoader() {
+        return (callersClassLoaderRef != null)
+                ? callersClassLoaderRef.get()
+                : null;
+    }
+
+    // This constructor is used only to create the global Logger.
+    // It is needed to break a cyclic dependence between the LogManager
+    // and Logger static initializers causing deadlocks.
+    private Logger(String name) {
+        // The manager field is not initialized here.
+        this.name = name;
+        this.isSystemLogger = true;
+        levelValue = Level.INFO.intValue();
+    }
+
+    // It is called from LoggerContext.addLocalLogger() when the logger
+    // is actually added to a LogManager.
+    void setLogManager(LogManager manager) {
+        this.manager = manager;
+    }
+
+    private void checkPermission() throws SecurityException {
+        if (!anonymous) {
+            if (manager == null) {
+                // Complete initialization of the global Logger.
+                manager = LogManager.getLogManager();
+            }
+            manager.checkPermission();
+        }
+    }
+
+    // Until all JDK code converted to call sun.util.logging.PlatformLogger
+    // (see 7054233), we need to determine if Logger.getLogger is to add
+    // a system logger or user logger.
+    //
+    // As an interim solution, if the immediate caller whose caller loader is
+    // null, we assume it's a system logger and add it to the system context.
+    // These system loggers only set the resource bundle to the given
+    // resource bundle name (rather than the default system resource bundle).
+    private static class SystemLoggerHelper {
+        static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck");
+        private static boolean getBooleanProperty(final String key) {
+            String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
+                @Override
+                public String run() {
+                    return System.getProperty(key);
+                }
+            });
+            return Boolean.valueOf(s);
+        }
+    }
+
+    private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
+        LogManager manager = LogManager.getLogManager();
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null && !SystemLoggerHelper.disableCallerCheck) {
+            if (caller.getClassLoader() == null) {
+                return manager.demandSystemLogger(name, resourceBundleName);
+            }
+        }
+        return manager.demandLogger(name, resourceBundleName, caller);
+        // ends up calling new Logger(name, resourceBundleName, caller)
+        // iff the logger doesn't exist already
+    }
+
+    /**
+     * Find or create a logger for a named subsystem.  If a logger has
+     * already been created with the given name it is returned.  Otherwise
+     * a new logger is created.
+     * <p>
+     * If a new logger is created its log level will be configured
+     * based on the LogManager configuration and it will configured
+     * to also send logging output to its parent's Handlers.  It will
+     * be registered in the LogManager global namespace.
+     * <p>
+     * Note: The LogManager may only retain a weak reference to the newly
+     * created Logger. It is important to understand that a previously
+     * created Logger with the given name may be garbage collected at any
+     * time if there is no strong reference to the Logger. In particular,
+     * this means that two back-to-back calls like
+     * {@code getLogger("MyLogger").log(...)} may use different Logger
+     * objects named "MyLogger" if there is no strong reference to the
+     * Logger named "MyLogger" elsewhere in the program.
+     *
+     * @param   name            A name for the logger.  This should
+     *                          be a dot-separated name and should normally
+     *                          be based on the package name or class name
+     *                          of the subsystem, such as java.net
+     *                          or javax.swing
+     * @return a suitable Logger
+     * @throws NullPointerException if the name is null.
+     */
+
+    // Synchronization is not required here. All synchronization for
+    // adding a new Logger object is handled by LogManager.addLogger().
+    @CallerSensitive
+    public static Logger getLogger(String name) {
+        // This method is intentionally not a wrapper around a call
+        // to getLogger(name, resourceBundleName). If it were then
+        // this sequence:
+        //
+        //     getLogger("Foo", "resourceBundleForFoo");
+        //     getLogger("Foo");
+        //
+        // would throw an IllegalArgumentException in the second call
+        // because the wrapper would result in an attempt to replace
+        // the existing "resourceBundleForFoo" with null.
+        return demandLogger(name, null, Reflection.getCallerClass());
+    }
+
+    /**
+     * Find or create a logger for a named subsystem.  If a logger has
+     * already been created with the given name it is returned.  Otherwise
+     * a new logger is created.
+     * <p>
+     * If a new logger is created its log level will be configured
+     * based on the LogManager and it will configured to also send logging
+     * output to its parent's Handlers.  It will be registered in
+     * the LogManager global namespace.
+     * <p>
+     * Note: The LogManager may only retain a weak reference to the newly
+     * created Logger. It is important to understand that a previously
+     * created Logger with the given name may be garbage collected at any
+     * time if there is no strong reference to the Logger. In particular,
+     * this means that two back-to-back calls like
+     * {@code getLogger("MyLogger", ...).log(...)} may use different Logger
+     * objects named "MyLogger" if there is no strong reference to the
+     * Logger named "MyLogger" elsewhere in the program.
+     * <p>
+     * If the named Logger already exists and does not yet have a
+     * localization resource bundle then the given resource bundle
+     * name is used.  If the named Logger already exists and has
+     * a different resource bundle name then an IllegalArgumentException
+     * is thrown.
+     * <p>
+     * @param   name    A name for the logger.  This should
+     *                          be a dot-separated name and should normally
+     *                          be based on the package name or class name
+     *                          of the subsystem, such as java.net
+     *                          or javax.swing
+     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
+     *                          messages for this logger. May be {@code null}
+     *                          if none of the messages require localization.
+     * @return a suitable Logger
+     * @throws MissingResourceException if the resourceBundleName is non-null and
+     *             no corresponding resource can be found.
+     * @throws IllegalArgumentException if the Logger already exists and uses
+     *             a different resource bundle name; or if
+     *             {@code resourceBundleName} is {@code null} but the named
+     *             logger has a resource bundle set.
+     * @throws NullPointerException if the name is null.
+     */
+
+    // Synchronization is not required here. All synchronization for
+    // adding a new Logger object is handled by LogManager.addLogger().
+    @CallerSensitive
+    public static Logger getLogger(String name, String resourceBundleName) {
+        Class<?> callerClass = Reflection.getCallerClass();
+        Logger result = demandLogger(name, resourceBundleName, callerClass);
+
+        // MissingResourceException or IllegalArgumentException can be
+        // thrown by setupResourceInfo().
+        // We have to set the callers ClassLoader here in case demandLogger
+        // above found a previously created Logger.  This can happen, for
+        // example, if Logger.getLogger(name) is called and subsequently
+        // Logger.getLogger(name, resourceBundleName) is called.  In this case
+        // we won't necessarily have the correct classloader saved away, so
+        // we need to set it here, too.
+
+        result.setupResourceInfo(resourceBundleName, callerClass);
+        return result;
+    }
+
+    // package-private
+    // Add a platform logger to the system context.
+    // i.e. caller of sun.util.logging.PlatformLogger.getLogger
+    static Logger getPlatformLogger(String name) {
+        LogManager manager = LogManager.getLogManager();
+
+        // all loggers in the system context will default to
+        // the system logger's resource bundle
+        Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME);
+        return result;
+    }
+
+    /**
+     * Create an anonymous Logger.  The newly created Logger is not
+     * registered in the LogManager namespace.  There will be no
+     * access checks on updates to the logger.
+     * <p>
+     * This factory method is primarily intended for use from applets.
+     * Because the resulting Logger is anonymous it can be kept private
+     * by the creating class.  This removes the need for normal security
+     * checks, which in turn allows untrusted applet code to update
+     * the control state of the Logger.  For example an applet can do
+     * a setLevel or an addHandler on an anonymous Logger.
+     * <p>
+     * Even although the new logger is anonymous, it is configured
+     * to have the root logger ("") as its parent.  This means that
+     * by default it inherits its effective level and handlers
+     * from the root logger. Changing its parent via the
+     * {@link #setParent(java.util.logging.Logger) setParent} method
+     * will still require the security permission specified by that method.
+     * <p>
+     *
+     * @return a newly created private Logger
+     */
+    public static Logger getAnonymousLogger() {
+        return getAnonymousLogger(null);
+    }
+
+    /**
+     * Create an anonymous Logger.  The newly created Logger is not
+     * registered in the LogManager namespace.  There will be no
+     * access checks on updates to the logger.
+     * <p>
+     * This factory method is primarily intended for use from applets.
+     * Because the resulting Logger is anonymous it can be kept private
+     * by the creating class.  This removes the need for normal security
+     * checks, which in turn allows untrusted applet code to update
+     * the control state of the Logger.  For example an applet can do
+     * a setLevel or an addHandler on an anonymous Logger.
+     * <p>
+     * Even although the new logger is anonymous, it is configured
+     * to have the root logger ("") as its parent.  This means that
+     * by default it inherits its effective level and handlers
+     * from the root logger.  Changing its parent via the
+     * {@link #setParent(java.util.logging.Logger) setParent} method
+     * will still require the security permission specified by that method.
+     * <p>
+     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
+     *                          messages for this logger.
+     *          May be null if none of the messages require localization.
+     * @return a newly created private Logger
+     * @throws MissingResourceException if the resourceBundleName is non-null and
+     *             no corresponding resource can be found.
+     */
+
+    // Synchronization is not required here. All synchronization for
+    // adding a new anonymous Logger object is handled by doSetParent().
+    @CallerSensitive
+    public static Logger getAnonymousLogger(String resourceBundleName) {
+        LogManager manager = LogManager.getLogManager();
+        // cleanup some Loggers that have been GC'ed
+        manager.drainLoggerRefQueueBounded();
+        Logger result = new Logger(null, resourceBundleName,
+                                   Reflection.getCallerClass(), manager, false);
+        result.anonymous = true;
+        Logger root = manager.getLogger("");
+        result.doSetParent(root);
+        return result;
+    }
+
+    /**
+     * Retrieve the localization resource bundle for this
+     * logger.
+     * This method will return a {@code ResourceBundle} that was either
+     * set by the {@link
+     * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or
+     * <a href="#ResourceBundleMapping">mapped from the
+     * the resource bundle name</a> set via the {@link
+     * Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory
+     * method for the current default locale.
+     * <br>Note that if the result is {@code null}, then the Logger will use a resource
+     * bundle or resource bundle name inherited from its parent.
+     *
+     * @return localization bundle (may be {@code null})
+     */
+    public ResourceBundle getResourceBundle() {
+        return findResourceBundle(getResourceBundleName(), true);
+    }
+
+    /**
+     * Retrieve the localization resource bundle name for this
+     * logger.
+     * This is either the name specified through the {@link
+     * #getLogger(java.lang.String, java.lang.String) getLogger} factory method,
+     * or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the
+     * ResourceBundle set through {@link
+     * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
+     * <br>Note that if the result is {@code null}, then the Logger will use a resource
+     * bundle or resource bundle name inherited from its parent.
+     *
+     * @return localization bundle name (may be {@code null})
+     */
+    public String getResourceBundleName() {
+        return loggerBundle.resourceBundleName;
+    }
+
+    /**
+     * Set a filter to control output on this Logger.
+     * <P>
+     * After passing the initial "level" check, the Logger will
+     * call this Filter to check if a log record should really
+     * be published.
+     *
+     * @param   newFilter  a filter object (may be null)
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void setFilter(Filter newFilter) throws SecurityException {
+        checkPermission();
+        filter = newFilter;
+    }
+
+    /**
+     * Get the current filter for this Logger.
+     *
+     * @return  a filter object (may be null)
+     */
+    public Filter getFilter() {
+        return filter;
+    }
+
+    /**
+     * Log a LogRecord.
+     * <p>
+     * All the other logging methods in this class call through
+     * this method to actually perform any logging.  Subclasses can
+     * override this single method to capture all log activity.
+     *
+     * @param record the LogRecord to be published
+     */
+    public void log(LogRecord record) {
+        if (!isLoggable(record.getLevel())) {
+            return;
+        }
+        Filter theFilter = filter;
+        if (theFilter != null && !theFilter.isLoggable(record)) {
+            return;
+        }
+
+        // Post the LogRecord to all our Handlers, and then to
+        // our parents' handlers, all the way up the tree.
+
+        Logger logger = this;
+        while (logger != null) {
+            final Handler[] loggerHandlers = isSystemLogger
+                ? logger.accessCheckedHandlers()
+                : logger.getHandlers();
+
+            for (Handler handler : loggerHandlers) {
+                handler.publish(record);
+            }
+
+            final boolean useParentHdls = isSystemLogger
+                ? logger.useParentHandlers
+                : logger.getUseParentHandlers();
+
+            if (!useParentHdls) {
+                break;
+            }
+
+            logger = isSystemLogger ? logger.parent : logger.getParent();
+        }
+    }
+
+    // private support method for logging.
+    // We fill in the logger name, resource bundle name, and
+    // resource bundle and then call "void log(LogRecord)".
+    private void doLog(LogRecord lr) {
+        lr.setLoggerName(name);
+        final LoggerBundle lb = getEffectiveLoggerBundle();
+        final ResourceBundle  bundle = lb.userBundle;
+        final String ebname = lb.resourceBundleName;
+        if (ebname != null && bundle != null) {
+            lr.setResourceBundleName(ebname);
+            lr.setResourceBundle(bundle);
+        }
+        log(lr);
+    }
+
+
+    //================================================================
+    // Start of convenience methods WITHOUT className and methodName
+    //================================================================
+
+    /**
+     * Log a message, with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void log(Level level, String msg) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, which is only to be constructed if the logging level
+     * is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since 1.8
+     */
+    public void log(Level level, Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, with one object parameter.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   param1  parameter to the message
+     */
+    public void log(Level level, String msg, Object param1) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        Object params[] = { param1 };
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, with an array of object arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  array of parameters to the message
+     */
+    public void log(Level level, String msg, Object params[]) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with log message.
+     */
+    public void log(Level level, String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    /**
+     * Log a lazily constructed message, with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message level then the
+     * message is constructed by invoking the provided supplier function. The
+     * message and the given {@link Throwable} are then stored in a {@link
+     * LogRecord} which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   thrown  Throwable associated with log message.
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    //================================================================
+    // Start of convenience methods WITH className and methodName
+    //================================================================
+
+    /**
+     * Log a message, specifying source class and method,
+     * with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        doLog(lr);
+    }
+
+    /**
+     * Log a lazily constructed message, specifying source class and method,
+     * with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                     Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, specifying source class and method,
+     * with a single object parameter to the log message.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg      The string message (or a key in the message catalog)
+     * @param   param1    Parameter to the log message.
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                                                String msg, Object param1) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        Object params[] = { param1 };
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, specifying source class and method,
+     * with an array of object arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  Array of parameters to the message
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                                                String msg, Object params[]) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, specifying source class and method,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with log message.
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                     String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    /**
+     * Log a lazily constructed message, specifying source class and method,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message level then the
+     * message is constructed by invoking the provided supplier function. The
+     * message and the given {@link Throwable} are then stored in a {@link
+     * LogRecord} which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   thrown  Throwable associated with log message.
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                     Throwable thrown, Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+
+    //=========================================================================
+    // Start of convenience methods WITH className, methodName and bundle name.
+    //=========================================================================
+
+    // Private support method for logging for "logrb" methods.
+    // We fill in the logger name, resource bundle name, and
+    // resource bundle and then call "void log(LogRecord)".
+    private void doLog(LogRecord lr, String rbname) {
+        lr.setLoggerName(name);
+        if (rbname != null) {
+            lr.setResourceBundleName(rbname);
+            lr.setResourceBundle(findResourceBundle(rbname, false));
+        }
+        log(lr);
+    }
+
+    // Private support method for logging for "logrb" methods.
+    private void doLog(LogRecord lr, ResourceBundle rb) {
+        lr.setLoggerName(name);
+        if (rb != null) {
+            lr.setResourceBundleName(rb.getBaseBundleName());
+            lr.setResourceBundle(rb);
+        }
+        log(lr);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name
+     * with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null
+     * @param   msg     The string message (or a key in the message catalog)
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     * java.lang.String, java.util.ResourceBundle, java.lang.String,
+     * java.lang.Object...)} instead.
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                String bundleName, String msg) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name,
+     * with a single object parameter to the log message.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null
+     * @param   msg      The string message (or a key in the message catalog)
+     * @param   param1    Parameter to the log message.
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     *   java.lang.String, java.util.ResourceBundle, java.lang.String,
+     *   java.lang.Object...)} instead
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                String bundleName, String msg, Object param1) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        Object params[] = { param1 };
+        lr.setParameters(params);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name,
+     * with an array of object arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null.
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  Array of parameters to the message
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     *      java.lang.String, java.util.ResourceBundle, java.lang.String,
+     *      java.lang.Object...)} instead.
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                String bundleName, String msg, Object params[]) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setParameters(params);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle,
+     * with an optional list of message parameters.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * The {@code msg} string is localized using the given resource bundle.
+     * If the resource bundle is {@code null}, then the {@code msg} string is not
+     * localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    Name of the class that issued the logging request
+     * @param   sourceMethod   Name of the method that issued the logging request
+     * @param   bundle         Resource bundle to localize {@code msg},
+     *                         can be {@code null}.
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  Parameters to the message (optional, may be none).
+     * @since 1.8
+     */
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                      ResourceBundle bundle, String msg, Object... params) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        if (params != null && params.length != 0) {
+            lr.setParameters(params);
+        }
+        doLog(lr, bundle);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with log message.
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     *     java.lang.String, java.util.ResourceBundle, java.lang.String,
+     *     java.lang.Throwable)} instead.
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                        String bundleName, String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * The {@code msg} string is localized using the given resource bundle.
+     * If the resource bundle is {@code null}, then the {@code msg} string is not
+     * localized.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    Name of the class that issued the logging request
+     * @param   sourceMethod   Name of the method that issued the logging request
+     * @param   bundle         Resource bundle to localize {@code msg},
+     *                         can be {@code null}
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with the log message.
+     * @since 1.8
+     */
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                      ResourceBundle bundle, String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr, bundle);
+    }
+
+    //======================================================================
+    // Start of convenience methods for logging method entries and returns.
+    //======================================================================
+
+    /**
+     * Log a method entry.
+     * <p>
+     * This is a convenience method that can be used to log entry
+     * to a method.  A LogRecord with message "ENTRY", log level
+     * FINER, and the given sourceMethod and sourceClass is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that is being entered
+     */
+    public void entering(String sourceClass, String sourceMethod) {
+        logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
+    }
+
+    /**
+     * Log a method entry, with one parameter.
+     * <p>
+     * This is a convenience method that can be used to log entry
+     * to a method.  A LogRecord with message "ENTRY {0}", log level
+     * FINER, and the given sourceMethod, sourceClass, and parameter
+     * is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that is being entered
+     * @param   param1         parameter to the method being entered
+     */
+    public void entering(String sourceClass, String sourceMethod, Object param1) {
+        logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1);
+    }
+
+    /**
+     * Log a method entry, with an array of parameters.
+     * <p>
+     * This is a convenience method that can be used to log entry
+     * to a method.  A LogRecord with message "ENTRY" (followed by a
+     * format {N} indicator for each entry in the parameter array),
+     * log level FINER, and the given sourceMethod, sourceClass, and
+     * parameters is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that is being entered
+     * @param   params         array of parameters to the method being entered
+     */
+    public void entering(String sourceClass, String sourceMethod, Object params[]) {
+        String msg = "ENTRY";
+        if (params == null ) {
+           logp(Level.FINER, sourceClass, sourceMethod, msg);
+           return;
+        }
+        if (!isLoggable(Level.FINER)) return;
+        for (int i = 0; i < params.length; i++) {
+            msg = msg + " {" + i + "}";
+        }
+        logp(Level.FINER, sourceClass, sourceMethod, msg, params);
+    }
+
+    /**
+     * Log a method return.
+     * <p>
+     * This is a convenience method that can be used to log returning
+     * from a method.  A LogRecord with message "RETURN", log level
+     * FINER, and the given sourceMethod and sourceClass is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of the method
+     */
+    public void exiting(String sourceClass, String sourceMethod) {
+        logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
+    }
+
+
+    /**
+     * Log a method return, with result object.
+     * <p>
+     * This is a convenience method that can be used to log returning
+     * from a method.  A LogRecord with message "RETURN {0}", log level
+     * FINER, and the gives sourceMethod, sourceClass, and result
+     * object is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of the method
+     * @param   result  Object that is being returned
+     */
+    public void exiting(String sourceClass, String sourceMethod, Object result) {
+        logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
+    }
+
+    /**
+     * Log throwing an exception.
+     * <p>
+     * This is a convenience method to log that a method is
+     * terminating by throwing an exception.  The logging is done
+     * using the FINER level.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.  The
+     * LogRecord's message is set to "THROW".
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod  name of the method.
+     * @param   thrown  The Throwable that is being thrown.
+     */
+    public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
+        if (!isLoggable(Level.FINER)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(Level.FINER, "THROW");
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    //=======================================================================
+    // Start of simple convenience methods using level names as method names
+    //=======================================================================
+
+    /**
+     * Log a SEVERE message.
+     * <p>
+     * If the logger is currently enabled for the SEVERE message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void severe(String msg) {
+        log(Level.SEVERE, msg);
+    }
+
+    /**
+     * Log a WARNING message.
+     * <p>
+     * If the logger is currently enabled for the WARNING message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void warning(String msg) {
+        log(Level.WARNING, msg);
+    }
+
+    /**
+     * Log an INFO message.
+     * <p>
+     * If the logger is currently enabled for the INFO message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void info(String msg) {
+        log(Level.INFO, msg);
+    }
+
+    /**
+     * Log a CONFIG message.
+     * <p>
+     * If the logger is currently enabled for the CONFIG message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void config(String msg) {
+        log(Level.CONFIG, msg);
+    }
+
+    /**
+     * Log a FINE message.
+     * <p>
+     * If the logger is currently enabled for the FINE message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void fine(String msg) {
+        log(Level.FINE, msg);
+    }
+
+    /**
+     * Log a FINER message.
+     * <p>
+     * If the logger is currently enabled for the FINER message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void finer(String msg) {
+        log(Level.FINER, msg);
+    }
+
+    /**
+     * Log a FINEST message.
+     * <p>
+     * If the logger is currently enabled for the FINEST message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void finest(String msg) {
+        log(Level.FINEST, msg);
+    }
+
+    //=======================================================================
+    // Start of simple convenience methods using level names as method names
+    // and use Supplier<String>
+    //=======================================================================
+
+    /**
+     * Log a SEVERE message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the SEVERE message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void severe(Supplier<String> msgSupplier) {
+        log(Level.SEVERE, msgSupplier);
+    }
+
+    /**
+     * Log a WARNING message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the WARNING message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void warning(Supplier<String> msgSupplier) {
+        log(Level.WARNING, msgSupplier);
+    }
+
+    /**
+     * Log a INFO message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the INFO message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void info(Supplier<String> msgSupplier) {
+        log(Level.INFO, msgSupplier);
+    }
+
+    /**
+     * Log a CONFIG message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the CONFIG message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void config(Supplier<String> msgSupplier) {
+        log(Level.CONFIG, msgSupplier);
+    }
+
+    /**
+     * Log a FINE message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the FINE message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void fine(Supplier<String> msgSupplier) {
+        log(Level.FINE, msgSupplier);
+    }
+
+    /**
+     * Log a FINER message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the FINER message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void finer(Supplier<String> msgSupplier) {
+        log(Level.FINER, msgSupplier);
+    }
+
+    /**
+     * Log a FINEST message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the FINEST message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void finest(Supplier<String> msgSupplier) {
+        log(Level.FINEST, msgSupplier);
+    }
+
+    //================================================================
+    // End of convenience methods
+    //================================================================
+
+    /**
+     * Set the log level specifying which message levels will be
+     * logged by this logger.  Message levels lower than this
+     * value will be discarded.  The level value Level.OFF
+     * can be used to turn off logging.
+     * <p>
+     * If the new level is null, it means that this node should
+     * inherit its level from its nearest ancestor with a specific
+     * (non-null) level value.
+     *
+     * @param newLevel   the new value for the log level (may be null)
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void setLevel(Level newLevel) throws SecurityException {
+        checkPermission();
+        synchronized (treeLock) {
+            levelObject = newLevel;
+            updateEffectiveLevel();
+        }
+    }
+
+    final boolean isLevelInitialized() {
+        return levelObject != null;
+    }
+
+    /**
+     * Get the log Level that has been specified for this Logger.
+     * The result may be null, which means that this logger's
+     * effective level will be inherited from its parent.
+     *
+     * @return  this Logger's level
+     */
+    public Level getLevel() {
+        return levelObject;
+    }
+
+    /**
+     * Check if a message of the given level would actually be logged
+     * by this logger.  This check is based on the Loggers effective level,
+     * which may be inherited from its parent.
+     *
+     * @param   level   a message logging level
+     * @return  true if the given message level is currently being logged.
+     */
+    public boolean isLoggable(Level level) {
+        if (level.intValue() < levelValue || levelValue == offValue) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Get the name for this logger.
+     * @return logger name.  Will be null for anonymous Loggers.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Add a log Handler to receive logging messages.
+     * <p>
+     * By default, Loggers also send their output to their parent logger.
+     * Typically the root Logger is configured with a set of Handlers
+     * that essentially act as default handlers for all loggers.
+     *
+     * @param   handler a logging Handler
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void addHandler(Handler handler) throws SecurityException {
+        // Check for null handler
+        handler.getClass();
+        checkPermission();
+        handlers.add(handler);
+    }
+
+    /**
+     * Remove a log Handler.
+     * <P>
+     * Returns silently if the given Handler is not found or is null
+     *
+     * @param   handler a logging Handler
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void removeHandler(Handler handler) throws SecurityException {
+        checkPermission();
+        if (handler == null) {
+            return;
+        }
+        handlers.remove(handler);
+    }
+
+    /**
+     * Get the Handlers associated with this logger.
+     * <p>
+     * @return  an array of all registered Handlers
+     */
+    public Handler[] getHandlers() {
+        return accessCheckedHandlers();
+    }
+
+    // This method should ideally be marked final - but unfortunately
+    // it needs to be overridden by LogManager.RootLogger
+    Handler[] accessCheckedHandlers() {
+        return handlers.toArray(emptyHandlers);
+    }
+
+    /**
+     * Specify whether or not this logger should send its output
+     * to its parent Logger.  This means that any LogRecords will
+     * also be written to the parent's Handlers, and potentially
+     * to its parent, recursively up the namespace.
+     *
+     * @param useParentHandlers   true if output is to be sent to the
+     *          logger's parent.
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void setUseParentHandlers(boolean useParentHandlers) {
+        checkPermission();
+        this.useParentHandlers = useParentHandlers;
+    }
+
+    /**
+     * Discover whether or not this logger is sending its output
+     * to its parent logger.
+     *
+     * @return  true if output is to be sent to the logger's parent
+     */
+    public boolean getUseParentHandlers() {
+        return useParentHandlers;
+    }
+
+    private static ResourceBundle findSystemResourceBundle(final Locale locale) {
+        // the resource bundle is in a restricted package
+        return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
+            @Override
+            public ResourceBundle run() {
+                try {
+                    return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME,
+                                                    locale,
+                                                    ClassLoader.getSystemClassLoader());
+                } catch (MissingResourceException e) {
+                    throw new InternalError(e.toString());
+                }
+            }
+        });
+    }
+
+    /**
+     * Private utility method to map a resource bundle name to an
+     * actual resource bundle, using a simple one-entry cache.
+     * Returns null for a null name.
+     * May also return null if we can't find the resource bundle and
+     * there is no suitable previous cached value.
+     *
+     * @param name the ResourceBundle to locate
+     * @param userCallersClassLoader if true search using the caller's ClassLoader
+     * @return ResourceBundle specified by name or null if not found
+     */
+    private synchronized ResourceBundle findResourceBundle(String name,
+                                                           boolean useCallersClassLoader) {
+        // For all lookups, we first check the thread context class loader
+        // if it is set.  If not, we use the system classloader.  If we
+        // still haven't found it we use the callersClassLoaderRef if it
+        // is set and useCallersClassLoader is true.  We set
+        // callersClassLoaderRef initially upon creating the logger with a
+        // non-null resource bundle name.
+
+        // Return a null bundle for a null name.
+        if (name == null) {
+            return null;
+        }
+
+        Locale currentLocale = Locale.getDefault();
+        final LoggerBundle lb = loggerBundle;
+
+        // Normally we should hit on our simple one entry cache.
+        if (lb.userBundle != null &&
+                name.equals(lb.resourceBundleName)) {
+            return lb.userBundle;
+        } else if (catalog != null && currentLocale.equals(catalogLocale)
+                && name.equals(catalogName)) {
+            return catalog;
+        }
+
+        if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
+            catalog = findSystemResourceBundle(currentLocale);
+            catalogName = name;
+            catalogLocale = currentLocale;
+            return catalog;
+        }
+
+        // Use the thread's context ClassLoader.  If there isn't one, use the
+        // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl == null) {
+            cl = ClassLoader.getSystemClassLoader();
+        }
+        try {
+            catalog = ResourceBundle.getBundle(name, currentLocale, cl);
+            catalogName = name;
+            catalogLocale = currentLocale;
+            return catalog;
+        } catch (MissingResourceException ex) {
+            // We can't find the ResourceBundle in the default
+            // ClassLoader.  Drop through.
+        }
+
+        if (useCallersClassLoader) {
+            // Try with the caller's ClassLoader
+            ClassLoader callersClassLoader = getCallersClassLoader();
+
+            if (callersClassLoader == null || callersClassLoader == cl) {
+                return null;
+            }
+
+            try {
+                catalog = ResourceBundle.getBundle(name, currentLocale,
+                                                   callersClassLoader);
+                catalogName = name;
+                catalogLocale = currentLocale;
+                return catalog;
+            } catch (MissingResourceException ex) {
+                return null; // no luck
+            }
+        } else {
+            return null;
+        }
+    }
+
+    // Private utility method to initialize our one entry
+    // resource bundle name cache and the callers ClassLoader
+    // Note: for consistency reasons, we are careful to check
+    // that a suitable ResourceBundle exists before setting the
+    // resourceBundleName field.
+    // Synchronized to prevent races in setting the fields.
+    private synchronized void setupResourceInfo(String name,
+                                                Class<?> callersClass) {
+        final LoggerBundle lb = loggerBundle;
+        if (lb.resourceBundleName != null) {
+            // this Logger already has a ResourceBundle
+
+            if (lb.resourceBundleName.equals(name)) {
+                // the names match so there is nothing more to do
+                return;
+            }
+
+            // cannot change ResourceBundles once they are set
+            throw new IllegalArgumentException(
+                lb.resourceBundleName + " != " + name);
+        }
+
+        if (name == null) {
+            return;
+        }
+
+        setCallersClassLoaderRef(callersClass);
+        if (isSystemLogger && getCallersClassLoader() != null) {
+            checkPermission();
+        }
+        if (findResourceBundle(name, true) == null) {
+            // We've failed to find an expected ResourceBundle.
+            // unset the caller's ClassLoader since we were unable to find the
+            // the bundle using it
+            this.callersClassLoaderRef = null;
+            throw new MissingResourceException("Can't find " + name + " bundle",
+                                                name, "");
+        }
+
+        // if lb.userBundle is not null we won't reach this line.
+        assert lb.userBundle == null;
+        loggerBundle = LoggerBundle.get(name, null);
+    }
+
+    /**
+     * Sets a resource bundle on this logger.
+     * All messages will be logged using the given resource bundle for its
+     * specific {@linkplain ResourceBundle#getLocale locale}.
+     * @param bundle The resource bundle that this logger shall use.
+     * @throws NullPointerException if the given bundle is {@code null}.
+     * @throws IllegalArgumentException if the given bundle doesn't have a
+     *         {@linkplain ResourceBundle#getBaseBundleName base name},
+     *         or if this logger already has a resource bundle set but
+     *         the given bundle has a different base name.
+     * @throws SecurityException if a security manager exists,
+     *         this logger is not anonymous, and the caller
+     *         does not have LoggingPermission("control").
+     * @since 1.8
+     */
+    public void setResourceBundle(ResourceBundle bundle) {
+        checkPermission();
+
+        // Will throw NPE if bundle is null.
+        final String baseName = bundle.getBaseBundleName();
+
+        // bundle must have a name
+        if (baseName == null || baseName.isEmpty()) {
+            throw new IllegalArgumentException("resource bundle must have a name");
+        }
+
+        synchronized (this) {
+            LoggerBundle lb = loggerBundle;
+            final boolean canReplaceResourceBundle = lb.resourceBundleName == null
+                    || lb.resourceBundleName.equals(baseName);
+
+            if (!canReplaceResourceBundle) {
+                throw new IllegalArgumentException("can't replace resource bundle");
+            }
+
+
+            loggerBundle = LoggerBundle.get(baseName, bundle);
+        }
+    }
+
+    /**
+     * Return the parent for this Logger.
+     * <p>
+     * This method returns the nearest extant parent in the namespace.
+     * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
+     * has been created but no logger "a.b.c" exists, then a call of
+     * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
+     * <p>
+     * The result will be null if it is called on the root Logger
+     * in the namespace.
+     *
+     * @return nearest existing parent Logger
+     */
+    public Logger getParent() {
+        // Note: this used to be synchronized on treeLock.  However, this only
+        // provided memory semantics, as there was no guarantee that the caller
+        // would synchronize on treeLock (in fact, there is no way for external
+        // callers to so synchronize).  Therefore, we have made parent volatile
+        // instead.
+        return parent;
+    }
+
+    /**
+     * Set the parent for this Logger.  This method is used by
+     * the LogManager to update a Logger when the namespace changes.
+     * <p>
+     * It should not be called from application code.
+     * <p>
+     * @param  parent   the new parent logger
+     * @throws  SecurityException  if a security manager exists and if
+     *          the caller does not have LoggingPermission("control").
+     */
+    public void setParent(Logger parent) {
+        if (parent == null) {
+            throw new NullPointerException();
+        }
+
+        // check permission for all loggers, including anonymous loggers
+        if (manager == null) {
+            manager = LogManager.getLogManager();
+        }
+        manager.checkPermission();
+
+        doSetParent(parent);
+    }
+
+    // Private method to do the work for parenting a child
+    // Logger onto a parent logger.
+    private void doSetParent(Logger newParent) {
+
+        // System.err.println("doSetParent \"" + getName() + "\" \""
+        //                              + newParent.getName() + "\"");
+
+        synchronized (treeLock) {
+
+            // Remove ourself from any previous parent.
+            LogManager.LoggerWeakRef ref = null;
+            if (parent != null) {
+                // assert parent.kids != null;
+                for (Iterator<LogManager.LoggerWeakRef> iter = parent.kids.iterator(); iter.hasNext(); ) {
+                    ref = iter.next();
+                    Logger kid =  ref.get();
+                    if (kid == this) {
+                        // ref is used down below to complete the reparenting
+                        iter.remove();
+                        break;
+                    } else {
+                        ref = null;
+                    }
+                }
+                // We have now removed ourself from our parents' kids.
+            }
+
+            // Set our new parent.
+            parent = newParent;
+            if (parent.kids == null) {
+                parent.kids = new ArrayList<>(2);
+            }
+            if (ref == null) {
+                // we didn't have a previous parent
+                ref = manager.new LoggerWeakRef(this);
+            }
+            ref.setParentRef(new WeakReference<>(parent));
+            parent.kids.add(ref);
+
+            // As a result of the reparenting, the effective level
+            // may have changed for us and our children.
+            updateEffectiveLevel();
+
+        }
+    }
+
+    // Package-level method.
+    // Remove the weak reference for the specified child Logger from the
+    // kid list. We should only be called from LoggerWeakRef.dispose().
+    final void removeChildLogger(LogManager.LoggerWeakRef child) {
+        synchronized (treeLock) {
+            for (Iterator<LogManager.LoggerWeakRef> iter = kids.iterator(); iter.hasNext(); ) {
+                LogManager.LoggerWeakRef ref = iter.next();
+                if (ref == child) {
+                    iter.remove();
+                    return;
+                }
+            }
+        }
+    }
+
+    // Recalculate the effective level for this node and
+    // recursively for our children.
+
+    private void updateEffectiveLevel() {
+        // assert Thread.holdsLock(treeLock);
+
+        // Figure out our current effective level.
+        int newLevelValue;
+        if (levelObject != null) {
+            newLevelValue = levelObject.intValue();
+        } else {
+            if (parent != null) {
+                newLevelValue = parent.levelValue;
+            } else {
+                // This may happen during initialization.
+                newLevelValue = Level.INFO.intValue();
+            }
+        }
+
+        // If our effective value hasn't changed, we're done.
+        if (levelValue == newLevelValue) {
+            return;
+        }
+
+        levelValue = newLevelValue;
+
+        // System.err.println("effective level: \"" + getName() + "\" := " + level);
+
+        // Recursively update the level on each of our kids.
+        if (kids != null) {
+            for (int i = 0; i < kids.size(); i++) {
+                LogManager.LoggerWeakRef ref = kids.get(i);
+                Logger kid =  ref.get();
+                if (kid != null) {
+                    kid.updateEffectiveLevel();
+                }
+            }
+        }
+    }
+
+
+    // Private method to get the potentially inherited
+    // resource bundle and resource bundle name for this Logger.
+    // This method never returns null.
+    private LoggerBundle getEffectiveLoggerBundle() {
+        final LoggerBundle lb = loggerBundle;
+        if (lb.isSystemBundle()) {
+            return SYSTEM_BUNDLE;
+        }
+
+        // first take care of this logger
+        final ResourceBundle b = getResourceBundle();
+        if (b != null && b == lb.userBundle) {
+            return lb;
+        } else if (b != null) {
+            // either lb.userBundle is null or getResourceBundle() is
+            // overriden
+            final String rbName = getResourceBundleName();
+            return LoggerBundle.get(rbName, b);
+        }
+
+        // no resource bundle was specified on this logger, look up the
+        // parent stack.
+        Logger target = this.parent;
+        while (target != null) {
+            final LoggerBundle trb = target.loggerBundle;
+            if (trb.isSystemBundle()) {
+                return SYSTEM_BUNDLE;
+            }
+            if (trb.userBundle != null) {
+                return trb;
+            }
+            final String rbName = isSystemLogger
+                // ancestor of a system logger is expected to be a system logger.
+                // ignore resource bundle name if it's not.
+                ? (target.isSystemLogger ? trb.resourceBundleName : null)
+                : target.getResourceBundleName();
+            if (rbName != null) {
+                return LoggerBundle.get(rbName,
+                        findResourceBundle(rbName, true));
+            }
+            target = isSystemLogger ? target.parent : target.getParent();
+        }
+        return NO_RESOURCE_BUNDLE;
+    }
+
+}
diff --git a/java/util/logging/Logging.java b/java/util/logging/Logging.java
new file mode 100644
index 0000000..740a533
--- /dev/null
+++ b/java/util/logging/Logging.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+import java.util.Enumeration;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Logging is the implementation class of LoggingMXBean.
+ *
+ * The <tt>LoggingMXBean</tt> interface provides a standard
+ * method for management access to the individual
+ * {@code Logger} objects available at runtime.
+ *
+ * @author Ron Mann
+ * @author Mandy Chung
+ * @since 1.5
+ *
+ * @see javax.management
+ * @see Logger
+ * @see LogManager
+ */
+class Logging implements LoggingMXBean {
+
+    private static LogManager logManager = LogManager.getLogManager();
+
+    /** Constructor of Logging which is the implementation class
+     *  of LoggingMXBean.
+     */
+    Logging() {
+    }
+
+    public List<String> getLoggerNames() {
+        Enumeration<String> loggers = logManager.getLoggerNames();
+        ArrayList<String> array = new ArrayList<>();
+
+        for (; loggers.hasMoreElements();) {
+            array.add(loggers.nextElement());
+        }
+        return array;
+    }
+
+    private static String EMPTY_STRING = "";
+    public String getLoggerLevel(String loggerName) {
+        Logger l = logManager.getLogger(loggerName);
+        if (l == null) {
+            return null;
+        }
+
+        Level level = l.getLevel();
+        if (level == null) {
+            return EMPTY_STRING;
+        } else {
+            return level.getLevelName();
+        }
+    }
+
+    public void setLoggerLevel(String loggerName, String levelName) {
+        if (loggerName == null) {
+            throw new NullPointerException("loggerName is null");
+        }
+
+        Logger logger = logManager.getLogger(loggerName);
+        if (logger == null) {
+            throw new IllegalArgumentException("Logger " + loggerName +
+                "does not exist");
+        }
+
+        Level level = null;
+        if (levelName != null) {
+            // parse will throw IAE if logLevel is invalid
+            level = Level.findLevel(levelName);
+            if (level == null) {
+                throw new IllegalArgumentException("Unknown level \"" + levelName + "\"");
+            }
+        }
+
+        logger.setLevel(level);
+    }
+
+    public String getParentLoggerName( String loggerName ) {
+        Logger l = logManager.getLogger( loggerName );
+        if (l == null) {
+            return null;
+        }
+
+        Logger p = l.getParent();
+        if (p == null) {
+            // root logger
+            return EMPTY_STRING;
+        } else {
+            return p.getName();
+        }
+    }
+}
diff --git a/java/util/logging/LoggingMXBean.java b/java/util/logging/LoggingMXBean.java
new file mode 100644
index 0000000..14777c0
--- /dev/null
+++ b/java/util/logging/LoggingMXBean.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+// Android-removed: References to java.lang.management in javadoc.
+
+/**
+ * The management interface for the logging facility.
+ *
+ * <p>There is a single global instance of the <tt>LoggingMXBean</tt>.
+ *
+ * The {@code javax.management.ObjectName ObjectName} that uniquely identifies
+ * the management interface for logging within the {@code MBeanServer} is:
+ * <pre>
+ *    {@link LogManager#LOGGING_MXBEAN_NAME java.util.logging:type=Logging}
+ * </pre>
+ * <p>
+ *
+ * @author  Ron Mann
+ * @author  Mandy Chung
+ * @since   1.5
+ *
+ */
+public interface LoggingMXBean {
+
+    /**
+     * Returns the list of currently registered logger names. This method
+     * calls {@link LogManager#getLoggerNames} and returns a list
+     * of the logger names.
+     *
+     * @return A list of <tt>String</tt> each of which is a
+     *         currently registered <tt>Logger</tt> name.
+     */
+    public java.util.List<String> getLoggerNames();
+
+    /**
+     * Gets the name of the log level associated with the specified logger.
+     * If the specified logger does not exist, <tt>null</tt>
+     * is returned.
+     * This method first finds the logger of the given name and
+     * then returns the name of the log level by calling:
+     * <blockquote>
+     *   {@link Logger#getLevel Logger.getLevel()}.{@link Level#getName getName()};
+     * </blockquote>
+     *
+     * <p>
+     * If the <tt>Level</tt> of the specified logger is <tt>null</tt>,
+     * which means that this logger's effective level is inherited
+     * from its parent, an empty string will be returned.
+     *
+     * @param loggerName The name of the <tt>Logger</tt> to be retrieved.
+     *
+     * @return The name of the log level of the specified logger; or
+     *         an empty string if the log level of the specified logger
+     *         is <tt>null</tt>.  If the specified logger does not
+     *         exist, <tt>null</tt> is returned.
+     *
+     * @see Logger#getLevel
+     */
+    public String getLoggerLevel(String loggerName);
+
+    /**
+     * Sets the specified logger to the specified new level.
+     * If the <tt>levelName</tt> is not <tt>null</tt>, the level
+     * of the specified logger is set to the parsed <tt>Level</tt>
+     * matching the <tt>levelName</tt>.
+     * If the <tt>levelName</tt> is <tt>null</tt>, the level
+     * of the specified logger is set to <tt>null</tt> and
+     * the effective level of the logger is inherited from
+     * its nearest ancestor with a specific (non-null) level value.
+     *
+     * @param loggerName The name of the <tt>Logger</tt> to be set.
+     *                   Must be non-null.
+     * @param levelName The name of the level to set on the specified logger,
+     *                 or <tt>null</tt> if setting the level to inherit
+     *                 from its nearest ancestor.
+     *
+     * @throws IllegalArgumentException if the specified logger
+     * does not exist, or <tt>levelName</tt> is not a valid level name.
+     *
+     * @throws SecurityException if a security manager exists and if
+     * the caller does not have LoggingPermission("control").
+     *
+     * @see Logger#setLevel
+     */
+    public void setLoggerLevel(String loggerName, String levelName);
+
+    /**
+     * Returns the name of the parent for the specified logger.
+     * If the specified logger does not exist, <tt>null</tt> is returned.
+     * If the specified logger is the root <tt>Logger</tt> in the namespace,
+     * the result will be an empty string.
+     *
+     * @param loggerName The name of a <tt>Logger</tt>.
+     *
+     * @return the name of the nearest existing parent logger;
+     *         an empty string if the specified logger is the root logger.
+     *         If the specified logger does not exist, <tt>null</tt>
+     *         is returned.
+     */
+    public String getParentLoggerName(String loggerName);
+}
diff --git a/java/util/logging/LoggingPermission.java b/java/util/logging/LoggingPermission.java
new file mode 100644
index 0000000..5cea7a5
--- /dev/null
+++ b/java/util/logging/LoggingPermission.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class LoggingPermission extends java.security.BasicPermission {
+
+    public LoggingPermission(String name, String actions) throws IllegalArgumentException {
+        super("", "");
+    }
+}
diff --git a/java/util/logging/LoggingProxyImpl.java b/java/util/logging/LoggingProxyImpl.java
new file mode 100644
index 0000000..61fcb7b
--- /dev/null
+++ b/java/util/logging/LoggingProxyImpl.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+import sun.util.logging.LoggingProxy;
+
+/**
+ * Implementation of LoggingProxy when java.util.logging classes exist.
+ */
+class LoggingProxyImpl implements LoggingProxy {
+    static final LoggingProxy INSTANCE = new LoggingProxyImpl();
+
+    private LoggingProxyImpl() { }
+
+    @Override
+    public Object getLogger(String name) {
+        // always create a platform logger with the resource bundle name
+        return Logger.getPlatformLogger(name);
+    }
+
+    @Override
+    public Object getLevel(Object logger) {
+        return ((Logger) logger).getLevel();
+    }
+
+    @Override
+    public void setLevel(Object logger, Object newLevel) {
+        ((Logger) logger).setLevel((Level) newLevel);
+    }
+
+    @Override
+    public boolean isLoggable(Object logger, Object level) {
+        return ((Logger) logger).isLoggable((Level) level);
+    }
+
+    @Override
+    public void log(Object logger, Object level, String msg) {
+        ((Logger) logger).log((Level) level, msg);
+    }
+
+    @Override
+    public void log(Object logger, Object level, String msg, Throwable t) {
+        ((Logger) logger).log((Level) level, msg, t);
+    }
+
+    @Override
+    public void log(Object logger, Object level, String msg, Object... params) {
+        ((Logger) logger).log((Level) level, msg, params);
+    }
+
+    @Override
+    public java.util.List<String> getLoggerNames() {
+        return LogManager.getLoggingMXBean().getLoggerNames();
+    }
+
+    @Override
+    public String getLoggerLevel(String loggerName) {
+        return LogManager.getLoggingMXBean().getLoggerLevel(loggerName);
+    }
+
+    @Override
+    public void setLoggerLevel(String loggerName, String levelName) {
+        LogManager.getLoggingMXBean().setLoggerLevel(loggerName, levelName);
+    }
+
+    @Override
+    public String getParentLoggerName(String loggerName) {
+        return LogManager.getLoggingMXBean().getParentLoggerName(loggerName);
+    }
+
+    @Override
+    public Object parseLevel(String levelName) {
+        Level level = Level.findLevel(levelName);
+        if (level == null) {
+            throw new IllegalArgumentException("Unknown level \"" + levelName + "\"");
+        }
+        return level;
+    }
+
+    @Override
+    public String getLevelName(Object level) {
+        return ((Level) level).getLevelName();
+    }
+
+    @Override
+    public int getLevelValue(Object level) {
+        return ((Level) level).intValue();
+    }
+
+    @Override
+    public String getProperty(String key) {
+        return LogManager.getLogManager().getProperty(key);
+    }
+}
diff --git a/java/util/logging/MemoryHandler.java b/java/util/logging/MemoryHandler.java
new file mode 100644
index 0000000..704c155
--- /dev/null
+++ b/java/util/logging/MemoryHandler.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+/**
+ * <tt>Handler</tt> that buffers requests in a circular buffer in memory.
+ * <p>
+ * Normally this <tt>Handler</tt> simply stores incoming <tt>LogRecords</tt>
+ * into its memory buffer and discards earlier records.  This buffering
+ * is very cheap and avoids formatting costs.  On certain trigger
+ * conditions, the <tt>MemoryHandler</tt> will push out its current buffer
+ * contents to a target <tt>Handler</tt>, which will typically publish
+ * them to the outside world.
+ * <p>
+ * There are three main models for triggering a push of the buffer:
+ * <ul>
+ * <li>
+ * An incoming <tt>LogRecord</tt> has a type that is greater than
+ * a pre-defined level, the <tt>pushLevel</tt>. </li>
+ * <li>
+ * An external class calls the <tt>push</tt> method explicitly. </li>
+ * <li>
+ * A subclass overrides the <tt>log</tt> method and scans each incoming
+ * <tt>LogRecord</tt> and calls <tt>push</tt> if a record matches some
+ * desired criteria. </li>
+ * </ul>
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>MemoryHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * If no default value is defined then a RuntimeException is thrown.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.ALL</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.size
+ *        defines the buffer size (defaults to 1000). </li>
+ * <li>   &lt;handler-name&gt;.push
+ *        defines the <tt>pushLevel</tt> (defaults to <tt>level.SEVERE</tt>). </li>
+ * <li>   &lt;handler-name&gt;.target
+ *        specifies the name of the target <tt>Handler </tt> class.
+ *        (no default). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code MemoryHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.MemoryHandler.level=INFO </li>
+ * <li>   java.util.logging.MemoryHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * @since 1.4
+ */
+
+public class MemoryHandler extends Handler {
+    private final static int DEFAULT_SIZE = 1000;
+    private volatile Level pushLevel;
+    private int size;
+    private Handler target;
+    private LogRecord buffer[];
+    int start, count;
+
+    // Private method to configure a MemoryHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        pushLevel = manager.getLevelProperty(cname +".push", Level.SEVERE);
+        size = manager.getIntProperty(cname + ".size", DEFAULT_SIZE);
+        if (size <= 0) {
+            size = DEFAULT_SIZE;
+        }
+        setLevel(manager.getLevelProperty(cname +".level", Level.ALL));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new SimpleFormatter()));
+    }
+
+    /**
+     * Create a <tt>MemoryHandler</tt> and configure it based on
+     * <tt>LogManager</tt> configuration properties.
+     */
+    public MemoryHandler() {
+        sealed = false;
+        configure();
+        sealed = true;
+
+        LogManager manager = LogManager.getLogManager();
+        String handlerName = getClass().getName();
+        String targetName = manager.getProperty(handlerName+".target");
+        if (targetName == null) {
+            throw new RuntimeException("The handler " + handlerName
+                    + " does not specify a target");
+        }
+        Class<?> clz;
+        try {
+            clz = ClassLoader.getSystemClassLoader().loadClass(targetName);
+            target = (Handler) clz.newInstance();
+        // Android-changed: Fall back to the context classloader before giving up.
+        // } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+        //     throw new RuntimeException("MemoryHandler can't load handler target \"" + targetName + "\"" , e);
+        } catch (Exception e) {
+            try {
+                clz = Thread.currentThread().getContextClassLoader()
+                        .loadClass(targetName);
+                target = (Handler) clz.newInstance();
+            } catch (Exception innerE) {
+                throw new RuntimeException("MemoryHandler can't load handler target \"" +
+                        targetName + "\"" , innerE);
+            }
+        }
+        init();
+    }
+
+    // Initialize.  Size is a count of LogRecords.
+    private void init() {
+        buffer = new LogRecord[size];
+        start = 0;
+        count = 0;
+    }
+
+    /**
+     * Create a <tt>MemoryHandler</tt>.
+     * <p>
+     * The <tt>MemoryHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given <tt>pushLevel</tt>
+     * argument and buffer size argument are used.
+     *
+     * @param target  the Handler to which to publish output.
+     * @param size    the number of log records to buffer (must be greater than zero)
+     * @param pushLevel  message level to push on
+     *
+     * @throws IllegalArgumentException if {@code size is <= 0}
+     */
+    public MemoryHandler(Handler target, int size, Level pushLevel) {
+        if (target == null || pushLevel == null) {
+            throw new NullPointerException();
+        }
+        if (size <= 0) {
+            throw new IllegalArgumentException();
+        }
+        sealed = false;
+        configure();
+        sealed = true;
+        this.target = target;
+        this.pushLevel = pushLevel;
+        this.size = size;
+        init();
+    }
+
+    /**
+     * Store a <tt>LogRecord</tt> in an internal buffer.
+     * <p>
+     * If there is a <tt>Filter</tt>, its <tt>isLoggable</tt>
+     * method is called to check if the given log record is loggable.
+     * If not we return.  Otherwise the given record is copied into
+     * an internal circular buffer.  Then the record's level property is
+     * compared with the <tt>pushLevel</tt>. If the given level is
+     * greater than or equal to the <tt>pushLevel</tt> then <tt>push</tt>
+     * is called to write all buffered records to the target output
+     * <tt>Handler</tt>.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        int ix = (start+count)%buffer.length;
+        buffer[ix] = record;
+        if (count < buffer.length) {
+            count++;
+        } else {
+            start++;
+            start %= buffer.length;
+        }
+        if (record.getLevel().intValue() >= pushLevel.intValue()) {
+            push();
+        }
+    }
+
+    /**
+     * Push any buffered output to the target <tt>Handler</tt>.
+     * <p>
+     * The buffer is then cleared.
+     */
+    public synchronized void push() {
+        for (int i = 0; i < count; i++) {
+            int ix = (start+i)%buffer.length;
+            LogRecord record = buffer[ix];
+            target.publish(record);
+        }
+        // Empty the buffer.
+        start = 0;
+        count = 0;
+    }
+
+    /**
+     * Causes a flush on the target <tt>Handler</tt>.
+     * <p>
+     * Note that the current contents of the <tt>MemoryHandler</tt>
+     * buffer are <b>not</b> written out.  That requires a "push".
+     */
+    @Override
+    public void flush() {
+        target.flush();
+    }
+
+    /**
+     * Close the <tt>Handler</tt> and free all associated resources.
+     * This will also close the target <tt>Handler</tt>.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    @Override
+    public void close() throws SecurityException {
+        target.close();
+        setLevel(Level.OFF);
+    }
+
+    /**
+     * Set the <tt>pushLevel</tt>.  After a <tt>LogRecord</tt> is copied
+     * into our internal buffer, if its level is greater than or equal to
+     * the <tt>pushLevel</tt>, then <tt>push</tt> will be called.
+     *
+     * @param newLevel the new value of the <tt>pushLevel</tt>
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setPushLevel(Level newLevel) throws SecurityException {
+        if (newLevel == null) {
+            throw new NullPointerException();
+        }
+        checkPermission();
+        pushLevel = newLevel;
+    }
+
+    /**
+     * Get the <tt>pushLevel</tt>.
+     *
+     * @return the value of the <tt>pushLevel</tt>
+     */
+    public Level getPushLevel() {
+        return pushLevel;
+    }
+
+    /**
+     * Check if this <tt>Handler</tt> would actually log a given
+     * <tt>LogRecord</tt> into its internal buffer.
+     * <p>
+     * This method checks if the <tt>LogRecord</tt> has an appropriate level and
+     * whether it satisfies any <tt>Filter</tt>.  However it does <b>not</b>
+     * check whether the <tt>LogRecord</tt> would result in a "push" of the
+     * buffer contents. It will return false if the <tt>LogRecord</tt> is null.
+     * <p>
+     * @param record  a <tt>LogRecord</tt>
+     * @return true if the <tt>LogRecord</tt> would be logged.
+     *
+     */
+    @Override
+    public boolean isLoggable(LogRecord record) {
+        return super.isLoggable(record);
+    }
+}
diff --git a/java/util/logging/SimpleFormatter.java b/java/util/logging/SimpleFormatter.java
new file mode 100644
index 0000000..12412f1
--- /dev/null
+++ b/java/util/logging/SimpleFormatter.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.text.*;
+import java.util.Date;
+import sun.util.logging.LoggingSupport;
+
+/**
+ * Print a brief summary of the {@code LogRecord} in a human readable
+ * format.  The summary will typically be 1 or 2 lines.
+ *
+ * <p>
+ * <a name="formatting">
+ * <b>Configuration:</b></a>
+ * The {@code SimpleFormatter} is initialized with the
+ * <a href="../Formatter.html#syntax">format string</a>
+ * specified in the {@code java.util.logging.SimpleFormatter.format}
+ * property to {@linkplain #format format} the log messages.
+ * This property can be defined
+ * in the {@linkplain LogManager#getProperty logging properties}
+ * configuration file
+ * or as a system property.  If this property is set in both
+ * the logging properties and system properties,
+ * the format string specified in the system property will be used.
+ * If this property is not defined or the given format string
+ * is {@linkplain java.util.IllegalFormatException illegal},
+ * the default format is implementation-specific.
+ *
+ * @since 1.4
+ * @see java.util.Formatter
+ */
+
+public class SimpleFormatter extends Formatter {
+
+    // format string for printing the log record
+    private static final String format = LoggingSupport.getSimpleFormat();
+    private final Date dat = new Date();
+
+    /**
+     * Format the given LogRecord.
+     * <p>
+     * The formatting can be customized by specifying the
+     * <a href="../Formatter.html#syntax">format string</a>
+     * in the <a href="#formatting">
+     * {@code java.util.logging.SimpleFormatter.format}</a> property.
+     * The given {@code LogRecord} will be formatted as if by calling:
+     * <pre>
+     *    {@link String#format String.format}(format, date, source, logger, level, message, thrown);
+     * </pre>
+     * where the arguments are:<br>
+     * <ol>
+     * <li>{@code format} - the {@link java.util.Formatter
+     *     java.util.Formatter} format string specified in the
+     *     {@code java.util.logging.SimpleFormatter.format} property
+     *     or the default format.</li>
+     * <li>{@code date} - a {@link Date} object representing
+     *     {@linkplain LogRecord#getMillis event time} of the log record.</li>
+     * <li>{@code source} - a string representing the caller, if available;
+     *     otherwise, the logger's name.</li>
+     * <li>{@code logger} - the logger's name.</li>
+     * <li>{@code level} - the {@linkplain Level#getLocalizedName
+     *     log level}.</li>
+     * <li>{@code message} - the formatted log message
+     *     returned from the {@link Formatter#formatMessage(LogRecord)}
+     *     method.  It uses {@link java.text.MessageFormat java.text}
+     *     formatting and does not use the {@code java.util.Formatter
+     *     format} argument.</li>
+     * <li>{@code thrown} - a string representing
+     *     the {@linkplain LogRecord#getThrown throwable}
+     *     associated with the log record and its backtrace
+     *     beginning with a newline character, if any;
+     *     otherwise, an empty string.</li>
+     * </ol>
+     *
+     * <p>Some example formats:<br>
+     * <ul>
+     * <li> {@code java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"}
+     *     <p>This prints 1 line with the log level ({@code 4$}),
+     *     the log message ({@code 5$}) and the timestamp ({@code 1$}) in
+     *     a square bracket.
+     *     <pre>
+     *     WARNING: warning message [Tue Mar 22 13:11:31 PDT 2011]
+     *     </pre></li>
+     * <li> {@code java.util.logging.SimpleFormatter.format="%1$tc %2$s%n%4$s: %5$s%6$s%n"}
+     *     <p>This prints 2 lines where the first line includes
+     *     the timestamp ({@code 1$}) and the source ({@code 2$});
+     *     the second line includes the log level ({@code 4$}) and
+     *     the log message ({@code 5$}) followed with the throwable
+     *     and its backtrace ({@code 6$}), if any:
+     *     <pre>
+     *     Tue Mar 22 13:11:31 PDT 2011 MyClass fatal
+     *     SEVERE: several message with an exception
+     *     java.lang.IllegalArgumentException: invalid argument
+     *             at MyClass.mash(MyClass.java:9)
+     *             at MyClass.crunch(MyClass.java:6)
+     *             at MyClass.main(MyClass.java:3)
+     *     </pre></li>
+     * <li> {@code java.util.logging.SimpleFormatter.format="%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp %2$s%n%4$s: %5$s%n"}
+     *      <p>This prints 2 lines similar to the example above
+     *         with a different date/time formatting and does not print
+     *         the throwable and its backtrace:
+     *     <pre>
+     *     Mar 22, 2011 1:11:31 PM MyClass fatal
+     *     SEVERE: several message with an exception
+     *     </pre></li>
+     * </ul>
+     * <p>This method can also be overridden in a subclass.
+     * It is recommended to use the {@link Formatter#formatMessage}
+     * convenience method to localize and format the message field.
+     *
+     * @param record the log record to be formatted.
+     * @return a formatted log record
+     */
+    public synchronized String format(LogRecord record) {
+        dat.setTime(record.getMillis());
+        String source;
+        if (record.getSourceClassName() != null) {
+            source = record.getSourceClassName();
+            if (record.getSourceMethodName() != null) {
+               source += " " + record.getSourceMethodName();
+            }
+        } else {
+            source = record.getLoggerName();
+        }
+        String message = formatMessage(record);
+        String throwable = "";
+        if (record.getThrown() != null) {
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            pw.println();
+            record.getThrown().printStackTrace(pw);
+            pw.close();
+            throwable = sw.toString();
+        }
+        return String.format(format,
+                             dat,
+                             source,
+                             record.getLoggerName(),
+                             record.getLevel().getLocalizedLevelName(),
+                             message,
+                             throwable);
+    }
+}
diff --git a/java/util/logging/SocketHandler.java b/java/util/logging/SocketHandler.java
new file mode 100644
index 0000000..2561e90
--- /dev/null
+++ b/java/util/logging/SocketHandler.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.net.*;
+import libcore.net.NetworkSecurityPolicy;
+
+/**
+ * Simple network logging <tt>Handler</tt>.
+ * <p>
+ * <tt>LogRecords</tt> are published to a network stream connection.  By default
+ * the <tt>XMLFormatter</tt> class is used for formatting.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>SocketHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.ALL</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.XMLFormatter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * <li>   &lt;handler-name&gt;.host
+ *        specifies the target host name to connect to (no default). </li>
+ * <li>   &lt;handler-name&gt;.port
+ *        specifies the target TCP port to use (no default). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code SocketHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.SocketHandler.level=INFO </li>
+ * <li>   java.util.logging.SocketHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * The output IO stream is buffered, but is flushed after each
+ * <tt>LogRecord</tt> is written.
+ *
+ * @since 1.4
+ */
+
+public class SocketHandler extends StreamHandler {
+    private Socket sock;
+    private String host;
+    private int port;
+
+    // Private method to configure a SocketHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        setLevel(manager.getLevelProperty(cname +".level", Level.ALL));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new XMLFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+        port = manager.getIntProperty(cname + ".port", 0);
+        host = manager.getStringProperty(cname + ".host", null);
+    }
+
+
+    /**
+     * Create a <tt>SocketHandler</tt>, using only <tt>LogManager</tt> properties
+     * (or their defaults).
+     * @throws IllegalArgumentException if the host or port are invalid or
+     *          are not specified as LogManager properties.
+     * @throws IOException if we are unable to connect to the target
+     *         host and port.
+     */
+    public SocketHandler() throws IOException {
+        // We are going to use the logging defaults.
+        sealed = false;
+        configure();
+
+        try {
+            connect();
+        } catch (IOException ix) {
+            System.err.println("SocketHandler: connect failed to " + host + ":" + port);
+            throw ix;
+        }
+        sealed = true;
+    }
+
+    /**
+     * Construct a <tt>SocketHandler</tt> using a specified host and port.
+     *
+     * The <tt>SocketHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given target host
+     * and port arguments are used. If the host argument is empty, but not
+     * null String then the localhost is used.
+     *
+     * @param host target host.
+     * @param port target port.
+     *
+     * @throws IllegalArgumentException if the host or port are invalid.
+     * @throws IOException if we are unable to connect to the target
+     *         host and port.
+     */
+    public SocketHandler(String host, int port) throws IOException {
+        sealed = false;
+        configure();
+        sealed = true;
+        this.port = port;
+        this.host = host;
+        connect();
+    }
+
+    private void connect() throws IOException {
+        // Check the arguments are valid.
+        if (port == 0) {
+            throw new IllegalArgumentException("Bad port: " + port);
+        }
+        if (host == null) {
+            throw new IllegalArgumentException("Null host name: " + host);
+        }
+
+        // Android-added: Enforce cleartext policy.
+        if (!NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()) {
+            throw new IOException("Cleartext traffic not permitted");
+        }
+
+        // Try to open a new socket.
+        sock = new Socket(host, port);
+        OutputStream out = sock.getOutputStream();
+        BufferedOutputStream bout = new BufferedOutputStream(out);
+        setOutputStream(bout);
+    }
+
+    /**
+     * Close this output stream.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    @Override
+    public synchronized void close() throws SecurityException {
+        super.close();
+        if (sock != null) {
+            try {
+                sock.close();
+            } catch (IOException ix) {
+                // drop through.
+            }
+        }
+        sock = null;
+    }
+
+    /**
+     * Format and publish a <tt>LogRecord</tt>.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        super.publish(record);
+        flush();
+    }
+}
diff --git a/java/util/logging/StreamHandler.java b/java/util/logging/StreamHandler.java
new file mode 100644
index 0000000..3b5a276
--- /dev/null
+++ b/java/util/logging/StreamHandler.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+
+/**
+ * Stream based logging <tt>Handler</tt>.
+ * <p>
+ * This is primarily intended as a base class or support class to
+ * be used in implementing other logging <tt>Handlers</tt>.
+ * <p>
+ * <tt>LogRecords</tt> are published to a given <tt>java.io.OutputStream</tt>.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>StreamHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.INFO</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *         (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.SimpleFormatter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code StreamHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.StreamHandler.level=INFO </li>
+ * <li>   java.util.logging.StreamHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * @since 1.4
+ */
+
+public class StreamHandler extends Handler {
+    private OutputStream output;
+    private boolean doneHeader;
+    private volatile Writer writer;
+
+    // Private method to configure a StreamHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        setLevel(manager.getLevelProperty(cname +".level", Level.INFO));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new SimpleFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+    }
+
+    /**
+     * Create a <tt>StreamHandler</tt>, with no current output stream.
+     */
+    public StreamHandler() {
+        sealed = false;
+        configure();
+        sealed = true;
+    }
+
+    /**
+     * Create a <tt>StreamHandler</tt> with a given <tt>Formatter</tt>
+     * and output stream.
+     * <p>
+     * @param out         the target output stream
+     * @param formatter   Formatter to be used to format output
+     */
+    public StreamHandler(OutputStream out, Formatter formatter) {
+        sealed = false;
+        configure();
+        setFormatter(formatter);
+        setOutputStream(out);
+        sealed = true;
+    }
+
+    /**
+     * Change the output stream.
+     * <P>
+     * If there is a current output stream then the <tt>Formatter</tt>'s
+     * tail string is written and the stream is flushed and closed.
+     * Then the output stream is replaced with the new output stream.
+     *
+     * @param out   New output stream.  May not be null.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    protected synchronized void setOutputStream(OutputStream out) throws SecurityException {
+        if (out == null) {
+            throw new NullPointerException();
+        }
+        flushAndClose();
+        output = out;
+        doneHeader = false;
+        String encoding = getEncoding();
+        if (encoding == null) {
+            writer = new OutputStreamWriter(output);
+        } else {
+            try {
+                writer = new OutputStreamWriter(output, encoding);
+            } catch (UnsupportedEncodingException ex) {
+                // This shouldn't happen.  The setEncoding method
+                // should have validated that the encoding is OK.
+                throw new Error("Unexpected exception " + ex);
+            }
+        }
+    }
+
+    /**
+     * Set (or change) the character encoding used by this <tt>Handler</tt>.
+     * <p>
+     * The encoding should be set before any <tt>LogRecords</tt> are written
+     * to the <tt>Handler</tt>.
+     *
+     * @param encoding  The name of a supported character encoding.
+     *        May be null, to indicate the default platform encoding.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  UnsupportedEncodingException if the named encoding is
+     *          not supported.
+     */
+    @Override
+    public synchronized void setEncoding(String encoding)
+                        throws SecurityException, java.io.UnsupportedEncodingException {
+        super.setEncoding(encoding);
+        if (output == null) {
+            return;
+        }
+        // Replace the current writer with a writer for the new encoding.
+        flush();
+        if (encoding == null) {
+            writer = new OutputStreamWriter(output);
+        } else {
+            writer = new OutputStreamWriter(output, encoding);
+        }
+    }
+
+    /**
+     * Format and publish a <tt>LogRecord</tt>.
+     * <p>
+     * The <tt>StreamHandler</tt> first checks if there is an <tt>OutputStream</tt>
+     * and if the given <tt>LogRecord</tt> has at least the required log level.
+     * If not it silently returns.  If so, it calls any associated
+     * <tt>Filter</tt> to check if the record should be published.  If so,
+     * it calls its <tt>Formatter</tt> to format the record and then writes
+     * the result to the current output stream.
+     * <p>
+     * If this is the first <tt>LogRecord</tt> to be written to a given
+     * <tt>OutputStream</tt>, the <tt>Formatter</tt>'s "head" string is
+     * written to the stream before the <tt>LogRecord</tt> is written.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        String msg;
+        try {
+            msg = getFormatter().format(record);
+        } catch (Exception ex) {
+            // We don't want to throw an exception here, but we
+            // report the exception to any registered ErrorManager.
+            reportError(null, ex, ErrorManager.FORMAT_FAILURE);
+            return;
+        }
+
+        try {
+            if (!doneHeader) {
+                writer.write(getFormatter().getHead(this));
+                doneHeader = true;
+            }
+            writer.write(msg);
+        } catch (Exception ex) {
+            // We don't want to throw an exception here, but we
+            // report the exception to any registered ErrorManager.
+            reportError(null, ex, ErrorManager.WRITE_FAILURE);
+        }
+    }
+
+
+    /**
+     * Check if this <tt>Handler</tt> would actually log a given <tt>LogRecord</tt>.
+     * <p>
+     * This method checks if the <tt>LogRecord</tt> has an appropriate level and
+     * whether it satisfies any <tt>Filter</tt>.  It will also return false if
+     * no output stream has been assigned yet or the LogRecord is null.
+     * <p>
+     * @param record  a <tt>LogRecord</tt>
+     * @return true if the <tt>LogRecord</tt> would be logged.
+     *
+     */
+    @Override
+    public boolean isLoggable(LogRecord record) {
+        if (writer == null || record == null) {
+            return false;
+        }
+        return super.isLoggable(record);
+    }
+
+    /**
+     * Flush any buffered messages.
+     */
+    @Override
+    public synchronized void flush() {
+        if (writer != null) {
+            try {
+                writer.flush();
+            } catch (Exception ex) {
+                // We don't want to throw an exception here, but we
+                // report the exception to any registered ErrorManager.
+                reportError(null, ex, ErrorManager.FLUSH_FAILURE);
+            }
+        }
+    }
+
+    private synchronized void flushAndClose() throws SecurityException {
+        checkPermission();
+        if (writer != null) {
+            try {
+                if (!doneHeader) {
+                    writer.write(getFormatter().getHead(this));
+                    doneHeader = true;
+                }
+                writer.write(getFormatter().getTail(this));
+                writer.flush();
+                writer.close();
+            } catch (Exception ex) {
+                // We don't want to throw an exception here, but we
+                // report the exception to any registered ErrorManager.
+                reportError(null, ex, ErrorManager.CLOSE_FAILURE);
+            }
+            writer = null;
+            output = null;
+        }
+    }
+
+    /**
+     * Close the current output stream.
+     * <p>
+     * The <tt>Formatter</tt>'s "tail" string is written to the stream before it
+     * is closed.  In addition, if the <tt>Formatter</tt>'s "head" string has not
+     * yet been written to the stream, it will be written before the
+     * "tail" string.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     */
+    @Override
+    public synchronized void close() throws SecurityException {
+        flushAndClose();
+    }
+}
diff --git a/java/util/logging/XMLFormatter.java b/java/util/logging/XMLFormatter.java
new file mode 100644
index 0000000..ab95f58
--- /dev/null
+++ b/java/util/logging/XMLFormatter.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.*;
+
+/**
+ * Format a LogRecord into a standard XML format.
+ * <p>
+ * The DTD specification is provided as Appendix A to the
+ * Java Logging APIs specification.
+ * <p>
+ * The XMLFormatter can be used with arbitrary character encodings,
+ * but it is recommended that it normally be used with UTF-8.  The
+ * character encoding can be set on the output Handler.
+ *
+ * @since 1.4
+ */
+
+public class XMLFormatter extends Formatter {
+    private LogManager manager = LogManager.getLogManager();
+
+    // Append a two digit number.
+    private void a2(StringBuilder sb, int x) {
+        if (x < 10) {
+            sb.append('0');
+        }
+        sb.append(x);
+    }
+
+    // Append the time and date in ISO 8601 format
+    private void appendISO8601(StringBuilder sb, long millis) {
+        GregorianCalendar cal = new GregorianCalendar();
+        cal.setTimeInMillis(millis);
+        sb.append(cal.get(Calendar.YEAR));
+        sb.append('-');
+        a2(sb, cal.get(Calendar.MONTH) + 1);
+        sb.append('-');
+        a2(sb, cal.get(Calendar.DAY_OF_MONTH));
+        sb.append('T');
+        a2(sb, cal.get(Calendar.HOUR_OF_DAY));
+        sb.append(':');
+        a2(sb, cal.get(Calendar.MINUTE));
+        sb.append(':');
+        a2(sb, cal.get(Calendar.SECOND));
+    }
+
+    // Append to the given StringBuilder an escaped version of the
+    // given text string where XML special characters have been escaped.
+    // For a null string we append "<null>"
+    private void escape(StringBuilder sb, String text) {
+        if (text == null) {
+            text = "<null>";
+        }
+        for (int i = 0; i < text.length(); i++) {
+            char ch = text.charAt(i);
+            if (ch == '<') {
+                sb.append("&lt;");
+            } else if (ch == '>') {
+                sb.append("&gt;");
+            } else if (ch == '&') {
+                sb.append("&amp;");
+            } else {
+                sb.append(ch);
+            }
+        }
+    }
+
+    /**
+     * Format the given message to XML.
+     * <p>
+     * This method can be overridden in a subclass.
+     * It is recommended to use the {@link Formatter#formatMessage}
+     * convenience method to localize and format the message field.
+     *
+     * @param record the log record to be formatted.
+     * @return a formatted log record
+     */
+    public String format(LogRecord record) {
+        StringBuilder sb = new StringBuilder(500);
+        sb.append("<record>\n");
+
+        sb.append("  <date>");
+        appendISO8601(sb, record.getMillis());
+        sb.append("</date>\n");
+
+        sb.append("  <millis>");
+        sb.append(record.getMillis());
+        sb.append("</millis>\n");
+
+        sb.append("  <sequence>");
+        sb.append(record.getSequenceNumber());
+        sb.append("</sequence>\n");
+
+        String name = record.getLoggerName();
+        if (name != null) {
+            sb.append("  <logger>");
+            escape(sb, name);
+            sb.append("</logger>\n");
+        }
+
+        sb.append("  <level>");
+        escape(sb, record.getLevel().toString());
+        sb.append("</level>\n");
+
+        if (record.getSourceClassName() != null) {
+            sb.append("  <class>");
+            escape(sb, record.getSourceClassName());
+            sb.append("</class>\n");
+        }
+
+        if (record.getSourceMethodName() != null) {
+            sb.append("  <method>");
+            escape(sb, record.getSourceMethodName());
+            sb.append("</method>\n");
+        }
+
+        sb.append("  <thread>");
+        sb.append(record.getThreadID());
+        sb.append("</thread>\n");
+
+        if (record.getMessage() != null) {
+            // Format the message string and its accompanying parameters.
+            String message = formatMessage(record);
+            sb.append("  <message>");
+            escape(sb, message);
+            sb.append("</message>");
+            sb.append("\n");
+        // Android-added: Include empty <message/> tag. http://b/25861348#comment17
+        } else {
+            sb.append("<message/>");
+            sb.append("\n");
+        }
+
+        // If the message is being localized, output the key, resource
+        // bundle name, and params.
+        ResourceBundle bundle = record.getResourceBundle();
+        try {
+            if (bundle != null && bundle.getString(record.getMessage()) != null) {
+                sb.append("  <key>");
+                escape(sb, record.getMessage());
+                sb.append("</key>\n");
+                sb.append("  <catalog>");
+                escape(sb, record.getResourceBundleName());
+                sb.append("</catalog>\n");
+            }
+        } catch (Exception ex) {
+            // The message is not in the catalog.  Drop through.
+        }
+
+        Object parameters[] = record.getParameters();
+        //  Check to see if the parameter was not a messagetext format
+        //  or was not null or empty
+        if ( parameters != null && parameters.length != 0
+                && record.getMessage().indexOf("{") == -1 ) {
+            for (int i = 0; i < parameters.length; i++) {
+                sb.append("  <param>");
+                try {
+                    escape(sb, parameters[i].toString());
+                } catch (Exception ex) {
+                    sb.append("???");
+                }
+                sb.append("</param>\n");
+            }
+        }
+
+        if (record.getThrown() != null) {
+            // Report on the state of the throwable.
+            Throwable th = record.getThrown();
+            sb.append("  <exception>\n");
+            sb.append("    <message>");
+            escape(sb, th.toString());
+            sb.append("</message>\n");
+            StackTraceElement trace[] = th.getStackTrace();
+            for (int i = 0; i < trace.length; i++) {
+                StackTraceElement frame = trace[i];
+                sb.append("    <frame>\n");
+                sb.append("      <class>");
+                escape(sb, frame.getClassName());
+                sb.append("</class>\n");
+                sb.append("      <method>");
+                escape(sb, frame.getMethodName());
+                sb.append("</method>\n");
+                // Check for a line number.
+                if (frame.getLineNumber() >= 0) {
+                    sb.append("      <line>");
+                    sb.append(frame.getLineNumber());
+                    sb.append("</line>\n");
+                }
+                sb.append("    </frame>\n");
+            }
+            sb.append("  </exception>\n");
+        }
+
+        sb.append("</record>\n");
+        return sb.toString();
+    }
+
+    /**
+     * Return the header string for a set of XML formatted records.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  a valid XML string
+     */
+    public String getHead(Handler h) {
+        StringBuilder sb = new StringBuilder();
+        String encoding;
+        sb.append("<?xml version=\"1.0\"");
+
+        if (h != null) {
+            encoding = h.getEncoding();
+        } else {
+            encoding = null;
+        }
+
+        if (encoding == null) {
+            // Figure out the default encoding.
+            encoding = java.nio.charset.Charset.defaultCharset().name();
+        }
+        // Try to map the encoding name to a canonical name.
+        try {
+            Charset cs = Charset.forName(encoding);
+            encoding = cs.name();
+        } catch (Exception ex) {
+            // We hit problems finding a canonical name.
+            // Just use the raw encoding name.
+        }
+
+        sb.append(" encoding=\"");
+        sb.append(encoding);
+        sb.append("\"");
+        sb.append(" standalone=\"no\"?>\n");
+        sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">\n");
+        sb.append("<log>\n");
+        return sb.toString();
+    }
+
+    /**
+     * Return the tail string for a set of XML formatted records.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  a valid XML string
+     */
+    public String getTail(Handler h) {
+        return "</log>\n";
+    }
+}
diff --git a/java/util/prefs/AbstractPreferences.java b/java/util/prefs/AbstractPreferences.java
new file mode 100644
index 0000000..71616ee
--- /dev/null
+++ b/java/util/prefs/AbstractPreferences.java
@@ -0,0 +1,1669 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.util.*;
+import java.io.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+// These imports needed only as a workaround for a JavaDoc bug
+import java.lang.Integer;
+import java.lang.Long;
+import java.lang.Float;
+import java.lang.Double;
+
+/**
+ * This class provides a skeletal implementation of the {@link Preferences}
+ * class, greatly easing the task of implementing it.
+ *
+ * <p><strong>This class is for <tt>Preferences</tt> implementers only.
+ * Normal users of the <tt>Preferences</tt> facility should have no need to
+ * consult this documentation.  The {@link Preferences} documentation
+ * should suffice.</strong>
+ *
+ * <p>Implementors must override the nine abstract service-provider interface
+ * (SPI) methods: {@link #getSpi(String)}, {@link #putSpi(String,String)},
+ * {@link #removeSpi(String)}, {@link #childSpi(String)}, {@link
+ * #removeNodeSpi()}, {@link #keysSpi()}, {@link #childrenNamesSpi()}, {@link
+ * #syncSpi()} and {@link #flushSpi()}.  All of the concrete methods specify
+ * precisely how they are implemented atop these SPI methods.  The implementor
+ * may, at his discretion, override one or more of the concrete methods if the
+ * default implementation is unsatisfactory for any reason, such as
+ * performance.
+ *
+ * <p>The SPI methods fall into three groups concerning exception
+ * behavior. The <tt>getSpi</tt> method should never throw exceptions, but it
+ * doesn't really matter, as any exception thrown by this method will be
+ * intercepted by {@link #get(String,String)}, which will return the specified
+ * default value to the caller.  The <tt>removeNodeSpi, keysSpi,
+ * childrenNamesSpi, syncSpi</tt> and <tt>flushSpi</tt> methods are specified
+ * to throw {@link BackingStoreException}, and the implementation is required
+ * to throw this checked exception if it is unable to perform the operation.
+ * The exception propagates outward, causing the corresponding API method
+ * to fail.
+ *
+ * <p>The remaining SPI methods {@link #putSpi(String,String)}, {@link
+ * #removeSpi(String)} and {@link #childSpi(String)} have more complicated
+ * exception behavior.  They are not specified to throw
+ * <tt>BackingStoreException</tt>, as they can generally obey their contracts
+ * even if the backing store is unavailable.  This is true because they return
+ * no information and their effects are not required to become permanent until
+ * a subsequent call to {@link Preferences#flush()} or
+ * {@link Preferences#sync()}. Generally speaking, these SPI methods should not
+ * throw exceptions.  In some implementations, there may be circumstances
+ * under which these calls cannot even enqueue the requested operation for
+ * later processing.  Even under these circumstances it is generally better to
+ * simply ignore the invocation and return, rather than throwing an
+ * exception.  Under these circumstances, however, all subsequent invocations
+ * of <tt>flush()</tt> and <tt>sync</tt> should return <tt>false</tt>, as
+ * returning <tt>true</tt> would imply that all previous operations had
+ * successfully been made permanent.
+ *
+ * <p>There is one circumstance under which <tt>putSpi, removeSpi and
+ * childSpi</tt> <i>should</i> throw an exception: if the caller lacks
+ * sufficient privileges on the underlying operating system to perform the
+ * requested operation.  This will, for instance, occur on most systems
+ * if a non-privileged user attempts to modify system preferences.
+ * (The required privileges will vary from implementation to
+ * implementation.  On some implementations, they are the right to modify the
+ * contents of some directory in the file system; on others they are the right
+ * to modify contents of some key in a registry.)  Under any of these
+ * circumstances, it would generally be undesirable to let the program
+ * continue executing as if these operations would become permanent at a later
+ * time.  While implementations are not required to throw an exception under
+ * these circumstances, they are encouraged to do so.  A {@link
+ * SecurityException} would be appropriate.
+ *
+ * <p>Most of the SPI methods require the implementation to read or write
+ * information at a preferences node.  The implementor should beware of the
+ * fact that another VM may have concurrently deleted this node from the
+ * backing store.  It is the implementation's responsibility to recreate the
+ * node if it has been deleted.
+ *
+ * <p>Implementation note: In Sun's default <tt>Preferences</tt>
+ * implementations, the user's identity is inherited from the underlying
+ * operating system and does not change for the lifetime of the virtual
+ * machine.  It is recognized that server-side <tt>Preferences</tt>
+ * implementations may have the user identity change from request to request,
+ * implicitly passed to <tt>Preferences</tt> methods via the use of a
+ * static {@link ThreadLocal} instance.  Authors of such implementations are
+ * <i>strongly</i> encouraged to determine the user at the time preferences
+ * are accessed (for example by the {@link #get(String,String)} or {@link
+ * #put(String,String)} method) rather than permanently associating a user
+ * with each <tt>Preferences</tt> instance.  The latter behavior conflicts
+ * with normal <tt>Preferences</tt> usage and would lead to great confusion.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+public abstract class AbstractPreferences extends Preferences {
+    /**
+     * Our name relative to parent.
+     */
+    private final String name;
+
+    /**
+     * Our absolute path name.
+     */
+    private final String absolutePath;
+
+    /**
+     * Our parent node.
+     */
+    final AbstractPreferences parent;
+
+    /**
+     * Our root node.
+     */
+    private final AbstractPreferences root; // Relative to this node
+
+    /**
+     * This field should be <tt>true</tt> if this node did not exist in the
+     * backing store prior to the creation of this object.  The field
+     * is initialized to false, but may be set to true by a subclass
+     * constructor (and should not be modified thereafter).  This field
+     * indicates whether a node change event should be fired when
+     * creation is complete.
+     */
+    protected boolean newNode = false;
+
+    /**
+     * All known unremoved children of this node.  (This "cache" is consulted
+     * prior to calling childSpi() or getChild().
+     */
+    private Map<String, AbstractPreferences> kidCache = new HashMap<>();
+
+    /**
+     * This field is used to keep track of whether or not this node has
+     * been removed.  Once it's set to true, it will never be reset to false.
+     */
+    private boolean removed = false;
+
+    /**
+     * Registered preference change listeners.
+     */
+    // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    // It's not clear if this change provides overall benefit; it might be
+    // reverted in future. Discussion: http://b/111195881
+    // private PreferenceChangeListener[] prefListeners =
+    //     new PreferenceChangeListener[0];
+    private final ArrayList<PreferenceChangeListener> prefListeners = new ArrayList<>();
+
+    /**
+     * Registered node change listeners.
+     */
+    // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    // private NodeChangeListener[] nodeListeners = new NodeChangeListener[0];
+    private final ArrayList<NodeChangeListener> nodeListeners = new ArrayList<>();
+
+    /**
+     * An object whose monitor is used to lock this node.  This object
+     * is used in preference to the node itself to reduce the likelihood of
+     * intentional or unintentional denial of service due to a locked node.
+     * To avoid deadlock, a node is <i>never</i> locked by a thread that
+     * holds a lock on a descendant of that node.
+     */
+    protected final Object lock = new Object();
+
+    /**
+     * Creates a preference node with the specified parent and the specified
+     * name relative to its parent.
+     *
+     * @param parent the parent of this preference node, or null if this
+     *               is the root.
+     * @param name the name of this preference node, relative to its parent,
+     *             or <tt>""</tt> if this is the root.
+     * @throws IllegalArgumentException if <tt>name</tt> contains a slash
+     *          (<tt>'/'</tt>),  or <tt>parent</tt> is <tt>null</tt> and
+     *          name isn't <tt>""</tt>.
+     */
+    protected AbstractPreferences(AbstractPreferences parent, String name) {
+        if (parent==null) {
+            if (!name.equals(""))
+                throw new IllegalArgumentException("Root name '"+name+
+                                                   "' must be \"\"");
+            this.absolutePath = "/";
+            root = this;
+        } else {
+            if (name.indexOf('/') != -1)
+                throw new IllegalArgumentException("Name '" + name +
+                                                 "' contains '/'");
+            if (name.equals(""))
+              throw new IllegalArgumentException("Illegal name: empty string");
+
+            root = parent.root;
+            absolutePath = (parent==root ? "/" + name
+                                         : parent.absolutePath() + "/" + name);
+        }
+        this.name = name;
+        this.parent = parent;
+    }
+
+    /**
+     * Implements the <tt>put</tt> method as per the specification in
+     * {@link Preferences#put(String,String)}.
+     *
+     * <p>This implementation checks that the key and value are legal,
+     * obtains this preference node's lock, checks that the node
+     * has not been removed, invokes {@link #putSpi(String,String)}, and if
+     * there are any preference change listeners, enqueues a notification
+     * event for processing by the event dispatch thread.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *       <tt>MAX_KEY_LENGTH</tt> or if <tt>value.length</tt> exceeds
+     *       <tt>MAX_VALUE_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void put(String key, String value) {
+        if (key==null || value==null)
+            throw new NullPointerException();
+        if (key.length() > MAX_KEY_LENGTH)
+            throw new IllegalArgumentException("Key too long: "+key);
+        if (value.length() > MAX_VALUE_LENGTH)
+            throw new IllegalArgumentException("Value too long: "+value);
+
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            putSpi(key, value);
+            enqueuePreferenceChangeEvent(key, value);
+        }
+    }
+
+    /**
+     * Implements the <tt>get</tt> method as per the specification in
+     * {@link Preferences#get(String,String)}.
+     *
+     * <p>This implementation first checks to see if <tt>key</tt> is
+     * <tt>null</tt> throwing a <tt>NullPointerException</tt> if this is
+     * the case.  Then it obtains this preference node's lock,
+     * checks that the node has not been removed, invokes {@link
+     * #getSpi(String)}, and returns the result, unless the <tt>getSpi</tt>
+     * invocation returns <tt>null</tt> or throws an exception, in which case
+     * this invocation returns <tt>def</tt>.
+     *
+     * @param key key whose associated value is to be returned.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>.
+     * @return the value associated with <tt>key</tt>, or <tt>def</tt>
+     *         if no value is associated with <tt>key</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if key is <tt>null</tt>.  (A
+     *         <tt>null</tt> default <i>is</i> permitted.)
+     */
+    public String get(String key, String def) {
+        if (key==null)
+            throw new NullPointerException("Null key");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            String result = null;
+            try {
+                result = getSpi(key);
+            } catch (Exception e) {
+                // Ignoring exception causes default to be returned
+            }
+            return (result==null ? def : result);
+        }
+    }
+
+    /**
+     * Implements the <tt>remove(String)</tt> method as per the specification
+     * in {@link Preferences#remove(String)}.
+     *
+     * <p>This implementation obtains this preference node's lock,
+     * checks that the node has not been removed, invokes
+     * {@link #removeSpi(String)} and if there are any preference
+     * change listeners, enqueues a notification event for processing by the
+     * event dispatch thread.
+     *
+     * @param key key whose mapping is to be removed from the preference node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException {@inheritDoc}.
+     */
+    public void remove(String key) {
+        Objects.requireNonNull(key, "Specified key cannot be null");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            removeSpi(key);
+            enqueuePreferenceChangeEvent(key, null);
+        }
+    }
+
+    /**
+     * Implements the <tt>clear</tt> method as per the specification in
+     * {@link Preferences#clear()}.
+     *
+     * <p>This implementation obtains this preference node's lock,
+     * invokes {@link #keys()} to obtain an array of keys, and
+     * iterates over the array invoking {@link #remove(String)} on each key.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void clear() throws BackingStoreException {
+        synchronized(lock) {
+            String[] keys = keys();
+            for (int i=0; i<keys.length; i++)
+                remove(keys[i]);
+        }
+    }
+
+    /**
+     * Implements the <tt>putInt</tt> method as per the specification in
+     * {@link Preferences#putInt(String,int)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Integer#toString(int)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putInt(String key, int value) {
+        put(key, Integer.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getInt</tt> method as per the specification in
+     * {@link Preferences#getInt(String,int)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to an <tt>int</tt> with
+     * {@link Integer#parseInt(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as an int.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as an int.
+     * @return the int value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         an int.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public int getInt(String key, int def) {
+        int result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Integer.parseInt(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putLong</tt> method as per the specification in
+     * {@link Preferences#putLong(String,long)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Long#toString(long)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putLong(String key, long value) {
+        put(key, Long.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getLong</tt> method as per the specification in
+     * {@link Preferences#getLong(String,long)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to a <tt>long</tt> with
+     * {@link Long#parseLong(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as a long.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a long.
+     * @return the long value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a long.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public long getLong(String key, long def) {
+        long result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putBoolean</tt> method as per the specification in
+     * {@link Preferences#putBoolean(String,boolean)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link String#valueOf(boolean)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putBoolean(String key, boolean value) {
+        put(key, String.valueOf(value));
+    }
+
+    /**
+     * Implements the <tt>getBoolean</tt> method as per the specification in
+     * {@link Preferences#getBoolean(String,boolean)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, it is compared with
+     * <tt>"true"</tt> using {@link String#equalsIgnoreCase(String)}.  If the
+     * comparison returns <tt>true</tt>, this invocation returns
+     * <tt>true</tt>.  Otherwise, the original return value is compared with
+     * <tt>"false"</tt>, again using {@link String#equalsIgnoreCase(String)}.
+     * If the comparison returns <tt>true</tt>, this invocation returns
+     * <tt>false</tt>.  Otherwise, this invocation returns <tt>def</tt>.
+     *
+     * @param key key whose associated value is to be returned as a boolean.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a boolean.
+     * @return the boolean value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a boolean.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public boolean getBoolean(String key, boolean def) {
+        boolean result = def;
+        String value = get(key, null);
+        if (value != null) {
+            if (value.equalsIgnoreCase("true"))
+                result = true;
+            else if (value.equalsIgnoreCase("false"))
+                result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putFloat</tt> method as per the specification in
+     * {@link Preferences#putFloat(String,float)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Float#toString(float)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putFloat(String key, float value) {
+        put(key, Float.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getFloat</tt> method as per the specification in
+     * {@link Preferences#getFloat(String,float)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to an <tt>float</tt> with
+     * {@link Float#parseFloat(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as a float.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a float.
+     * @return the float value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a float.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public float getFloat(String key, float def) {
+        float result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Float.parseFloat(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putDouble</tt> method as per the specification in
+     * {@link Preferences#putDouble(String,double)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Double#toString(double)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putDouble(String key, double value) {
+        put(key, Double.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getDouble</tt> method as per the specification in
+     * {@link Preferences#getDouble(String,double)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to an <tt>double</tt> with
+     * {@link Double#parseDouble(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as a double.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a double.
+     * @return the double value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a double.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public double getDouble(String key, double def) {
+        double result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Double.parseDouble(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putByteArray</tt> method as per the specification in
+     * {@link Preferences#putByteArray(String,byte[])}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if key.length() exceeds MAX_KEY_LENGTH
+     *         or if value.length exceeds MAX_VALUE_LENGTH*3/4.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putByteArray(String key, byte[] value) {
+        put(key, Base64.byteArrayToBase64(value));
+    }
+
+    /**
+     * Implements the <tt>getByteArray</tt> method as per the specification in
+     * {@link Preferences#getByteArray(String,byte[])}.
+     *
+     * @param key key whose associated value is to be returned as a byte array.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a byte array.
+     * @return the byte array value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a byte array.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.  (A
+     *         <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
+     */
+    public byte[] getByteArray(String key, byte[] def) {
+        byte[] result = def;
+        String value = get(key, null);
+        try {
+            if (value != null)
+                result = Base64.base64ToByteArray(value);
+        }
+        catch (RuntimeException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>keys</tt> method as per the specification in
+     * {@link Preferences#keys()}.
+     *
+     * <p>This implementation obtains this preference node's lock, checks that
+     * the node has not been removed and invokes {@link #keysSpi()}.
+     *
+     * @return an array of the keys that have an associated value in this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public String[] keys() throws BackingStoreException {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            return keysSpi();
+        }
+    }
+
+    /**
+     * Implements the <tt>children</tt> method as per the specification in
+     * {@link Preferences#childrenNames()}.
+     *
+     * <p>This implementation obtains this preference node's lock, checks that
+     * the node has not been removed, constructs a <tt>TreeSet</tt> initialized
+     * to the names of children already cached (the children in this node's
+     * "child-cache"), invokes {@link #childrenNamesSpi()}, and adds all of the
+     * returned child-names into the set.  The elements of the tree set are
+     * dumped into a <tt>String</tt> array using the <tt>toArray</tt> method,
+     * and this array is returned.
+     *
+     * @return the names of the children of this preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #cachedChildren()
+     */
+    public String[] childrenNames() throws BackingStoreException {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            Set<String> s = new TreeSet<>(kidCache.keySet());
+            for (String kid : childrenNamesSpi())
+                s.add(kid);
+            return s.toArray(EMPTY_STRING_ARRAY);
+        }
+    }
+
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    /**
+     * Returns all known unremoved children of this node.
+     *
+     * @return all known unremoved children of this node.
+     */
+    protected final AbstractPreferences[] cachedChildren() {
+        return kidCache.values().toArray(EMPTY_ABSTRACT_PREFS_ARRAY);
+    }
+
+    private static final AbstractPreferences[] EMPTY_ABSTRACT_PREFS_ARRAY
+        = new AbstractPreferences[0];
+
+    /**
+     * Implements the <tt>parent</tt> method as per the specification in
+     * {@link Preferences#parent()}.
+     *
+     * <p>This implementation obtains this preference node's lock, checks that
+     * the node has not been removed and returns the parent value that was
+     * passed to this node's constructor.
+     *
+     * @return the parent of this preference node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public Preferences parent() {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            return parent;
+        }
+    }
+
+    /**
+     * Implements the <tt>node</tt> method as per the specification in
+     * {@link Preferences#node(String)}.
+     *
+     * <p>This implementation obtains this preference node's lock and checks
+     * that the node has not been removed.  If <tt>path</tt> is <tt>""</tt>,
+     * this node is returned; if <tt>path</tt> is <tt>"/"</tt>, this node's
+     * root is returned.  If the first character in <tt>path</tt> is
+     * not <tt>'/'</tt>, the implementation breaks <tt>path</tt> into
+     * tokens and recursively traverses the path from this node to the
+     * named node, "consuming" a name and a slash from <tt>path</tt> at
+     * each step of the traversal.  At each step, the current node is locked
+     * and the node's child-cache is checked for the named node.  If it is
+     * not found, the name is checked to make sure its length does not
+     * exceed <tt>MAX_NAME_LENGTH</tt>.  Then the {@link #childSpi(String)}
+     * method is invoked, and the result stored in this node's child-cache.
+     * If the newly created <tt>Preferences</tt> object's {@link #newNode}
+     * field is <tt>true</tt> and there are any node change listeners,
+     * a notification event is enqueued for processing by the event dispatch
+     * thread.
+     *
+     * <p>When there are no more tokens, the last value found in the
+     * child-cache or returned by <tt>childSpi</tt> is returned by this
+     * method.  If during the traversal, two <tt>"/"</tt> tokens occur
+     * consecutively, or the final token is <tt>"/"</tt> (rather than a name),
+     * an appropriate <tt>IllegalArgumentException</tt> is thrown.
+     *
+     * <p> If the first character of <tt>path</tt> is <tt>'/'</tt>
+     * (indicating an absolute path name) this preference node's
+     * lock is dropped prior to breaking <tt>path</tt> into tokens, and
+     * this method recursively traverses the path starting from the root
+     * (rather than starting from this node).  The traversal is otherwise
+     * identical to the one described for relative path names.  Dropping
+     * the lock on this node prior to commencing the traversal at the root
+     * node is essential to avoid the possibility of deadlock, as per the
+     * {@link #lock locking invariant}.
+     *
+     * @param path the path name of the preference node to return.
+     * @return the specified preference node.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public Preferences node(String path) {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            if (path.equals(""))
+                return this;
+            if (path.equals("/"))
+                return root;
+            if (path.charAt(0) != '/')
+                return node(new StringTokenizer(path, "/", true));
+        }
+
+        // Absolute path.  Note that we've dropped our lock to avoid deadlock
+        return root.node(new StringTokenizer(path.substring(1), "/", true));
+    }
+
+    /**
+     * tokenizer contains <name> {'/' <name>}*
+     */
+    private Preferences node(StringTokenizer path) {
+        String token = path.nextToken();
+        if (token.equals("/"))  // Check for consecutive slashes
+            throw new IllegalArgumentException("Consecutive slashes in path");
+        synchronized(lock) {
+            AbstractPreferences child = kidCache.get(token);
+            if (child == null) {
+                if (token.length() > MAX_NAME_LENGTH)
+                    throw new IllegalArgumentException(
+                        "Node name " + token + " too long");
+                child = childSpi(token);
+                if (child.newNode)
+                    enqueueNodeAddedEvent(child);
+                kidCache.put(token, child);
+            }
+            if (!path.hasMoreTokens())
+                return child;
+            path.nextToken();  // Consume slash
+            if (!path.hasMoreTokens())
+                throw new IllegalArgumentException("Path ends with slash");
+            return child.node(path);
+        }
+    }
+
+    /**
+     * Implements the <tt>nodeExists</tt> method as per the specification in
+     * {@link Preferences#nodeExists(String)}.
+     *
+     * <p>This implementation is very similar to {@link #node(String)},
+     * except that {@link #getChild(String)} is used instead of {@link
+     * #childSpi(String)}.
+     *
+     * @param path the path name of the node whose existence is to be checked.
+     * @return true if the specified node exists.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method and
+     *         <tt>pathname</tt> is not the empty string (<tt>""</tt>).
+     */
+    public boolean nodeExists(String path)
+        throws BackingStoreException
+    {
+        synchronized(lock) {
+            if (path.equals(""))
+                return !removed;
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            if (path.equals("/"))
+                return true;
+            if (path.charAt(0) != '/')
+                return nodeExists(new StringTokenizer(path, "/", true));
+        }
+
+        // Absolute path.  Note that we've dropped our lock to avoid deadlock
+        return root.nodeExists(new StringTokenizer(path.substring(1), "/",
+                                                   true));
+    }
+
+    /**
+     * tokenizer contains <name> {'/' <name>}*
+     */
+    private boolean nodeExists(StringTokenizer path)
+        throws BackingStoreException
+    {
+        String token = path.nextToken();
+        if (token.equals("/"))  // Check for consecutive slashes
+            throw new IllegalArgumentException("Consecutive slashes in path");
+        synchronized(lock) {
+            AbstractPreferences child = kidCache.get(token);
+            if (child == null)
+                child = getChild(token);
+            if (child==null)
+                return false;
+            if (!path.hasMoreTokens())
+                return true;
+            path.nextToken();  // Consume slash
+            if (!path.hasMoreTokens())
+                throw new IllegalArgumentException("Path ends with slash");
+            return child.nodeExists(path);
+        }
+    }
+
+    /**
+
+     * Implements the <tt>removeNode()</tt> method as per the specification in
+     * {@link Preferences#removeNode()}.
+     *
+     * <p>This implementation checks to see that this node is the root; if so,
+     * it throws an appropriate exception.  Then, it locks this node's parent,
+     * and calls a recursive helper method that traverses the subtree rooted at
+     * this node.  The recursive method locks the node on which it was called,
+     * checks that it has not already been removed, and then ensures that all
+     * of its children are cached: The {@link #childrenNamesSpi()} method is
+     * invoked and each returned child name is checked for containment in the
+     * child-cache.  If a child is not already cached, the {@link
+     * #childSpi(String)} method is invoked to create a <tt>Preferences</tt>
+     * instance for it, and this instance is put into the child-cache.  Then
+     * the helper method calls itself recursively on each node contained in its
+     * child-cache.  Next, it invokes {@link #removeNodeSpi()}, marks itself
+     * as removed, and removes itself from its parent's child-cache.  Finally,
+     * if there are any node change listeners, it enqueues a notification
+     * event for processing by the event dispatch thread.
+     *
+     * <p>Note that the helper method is always invoked with all ancestors up
+     * to the "closest non-removed ancestor" locked.
+     *
+     * @throws IllegalStateException if this node (or an ancestor) has already
+     *         been removed with the {@link #removeNode()} method.
+     * @throws UnsupportedOperationException if this method is invoked on
+     *         the root node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    public void removeNode() throws BackingStoreException {
+        if (this==root)
+            throw new UnsupportedOperationException("Can't remove the root!");
+        synchronized(parent.lock) {
+            removeNode2();
+            parent.kidCache.remove(name);
+        }
+    }
+
+    /*
+     * Called with locks on all nodes on path from parent of "removal root"
+     * to this (including the former but excluding the latter).
+     */
+    private void removeNode2() throws BackingStoreException {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node already removed.");
+
+            // Ensure that all children are cached
+            String[] kidNames = childrenNamesSpi();
+            for (int i=0; i<kidNames.length; i++)
+                if (!kidCache.containsKey(kidNames[i]))
+                    kidCache.put(kidNames[i], childSpi(kidNames[i]));
+
+            // Recursively remove all cached children
+            for (Iterator<AbstractPreferences> i = kidCache.values().iterator();
+                 i.hasNext();) {
+                try {
+                    i.next().removeNode2();
+                    i.remove();
+                } catch (BackingStoreException x) { }
+            }
+
+            // Now we have no descendants - it's time to die!
+            removeNodeSpi();
+            removed = true;
+            parent.enqueueNodeRemovedEvent(this);
+        }
+    }
+
+    /**
+     * Implements the <tt>name</tt> method as per the specification in
+     * {@link Preferences#name()}.
+     *
+     * <p>This implementation merely returns the name that was
+     * passed to this node's constructor.
+     *
+     * @return this preference node's name, relative to its parent.
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Implements the <tt>absolutePath</tt> method as per the specification in
+     * {@link Preferences#absolutePath()}.
+     *
+     * <p>This implementation merely returns the absolute path name that
+     * was computed at the time that this node was constructed (based on
+     * the name that was passed to this node's constructor, and the names
+     * that were passed to this node's ancestors' constructors).
+     *
+     * @return this preference node's absolute path name.
+     */
+    public String absolutePath() {
+        return absolutePath;
+    }
+
+    /**
+     * Implements the <tt>isUserNode</tt> method as per the specification in
+     * {@link Preferences#isUserNode()}.
+     *
+     * <p>This implementation compares this node's root node (which is stored
+     * in a private field) with the value returned by
+     * {@link Preferences#userRoot()}.  If the two object references are
+     * identical, this method returns true.
+     *
+     * @return <tt>true</tt> if this preference node is in the user
+     *         preference tree, <tt>false</tt> if it's in the system
+     *         preference tree.
+     */
+    public boolean isUserNode() {
+        return AccessController.doPrivileged(
+            new PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return root == Preferences.userRoot();
+            }
+            }).booleanValue();
+    }
+
+    public void addPreferenceChangeListener(PreferenceChangeListener pcl) {
+        if (pcl==null)
+            throw new NullPointerException("Change listener is null.");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            PreferenceChangeListener[] old = prefListeners;
+            prefListeners = new PreferenceChangeListener[old.length + 1];
+            System.arraycopy(old, 0, prefListeners, 0, old.length);
+            prefListeners[old.length] = pcl;
+            */
+            prefListeners.add(pcl);
+        }
+        startEventDispatchThreadIfNecessary();
+    }
+
+    public void removePreferenceChangeListener(PreferenceChangeListener pcl) {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // if ((prefListeners == null) || (prefListeners.length == 0))
+            if (!prefListeners.contains(pcl)) {
+                throw new IllegalArgumentException("Listener not registered.");
+            }
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            PreferenceChangeListener[] newPl =
+                new PreferenceChangeListener[prefListeners.length - 1];
+            int i = 0;
+            while (i < newPl.length && prefListeners[i] != pcl)
+                newPl[i] = prefListeners[i++];
+
+            if (i == newPl.length &&  prefListeners[i] != pcl)
+                throw new IllegalArgumentException("Listener not registered.");
+            while (i < newPl.length)
+                newPl[i] = prefListeners[++i];
+            prefListeners = newPl;
+            */
+            prefListeners.remove(pcl);
+        }
+    }
+
+    public void addNodeChangeListener(NodeChangeListener ncl) {
+        if (ncl==null)
+            throw new NullPointerException("Change listener is null.");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            if (nodeListeners == null) {
+                nodeListeners = new NodeChangeListener[1];
+                nodeListeners[0] = ncl;
+            } else {
+                NodeChangeListener[] old = nodeListeners;
+                nodeListeners = new NodeChangeListener[old.length + 1];
+                System.arraycopy(old, 0, nodeListeners, 0, old.length);
+                nodeListeners[old.length] = ncl;
+            }
+            */
+            nodeListeners.add(ncl);
+        }
+        startEventDispatchThreadIfNecessary();
+    }
+
+    public void removeNodeChangeListener(NodeChangeListener ncl) {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // if ((nodeListeners == null) || (nodeListeners.length == 0))
+            if (!nodeListeners.contains(ncl)) {
+                throw new IllegalArgumentException("Listener not registered.");
+            }
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            int i = 0;
+            while (i < nodeListeners.length && nodeListeners[i] != ncl)
+                i++;
+            if (i == nodeListeners.length)
+                throw new IllegalArgumentException("Listener not registered.");
+            NodeChangeListener[] newNl =
+                new NodeChangeListener[nodeListeners.length - 1];
+            if (i != 0)
+                System.arraycopy(nodeListeners, 0, newNl, 0, i);
+            if (i != newNl.length)
+                System.arraycopy(nodeListeners, i + 1,
+                                 newNl, i, newNl.length - i);
+            nodeListeners = newNl;
+            */
+            nodeListeners.remove(ncl);
+        }
+    }
+
+    // "SPI" METHODS
+
+    /**
+     * Put the given key-value association into this preference node.  It is
+     * guaranteed that <tt>key</tt> and <tt>value</tt> are non-null and of
+     * legal length.  Also, it is guaranteed that this node has not been
+     * removed.  (The implementor needn't check for any of these things.)
+     *
+     * <p>This method is invoked with the lock on this node held.
+     * @param key the key
+     * @param value the value
+     */
+    protected abstract void putSpi(String key, String value);
+
+    /**
+     * Return the value associated with the specified key at this preference
+     * node, or <tt>null</tt> if there is no association for this key, or the
+     * association cannot be determined at this time.  It is guaranteed that
+     * <tt>key</tt> is non-null.  Also, it is guaranteed that this node has
+     * not been removed.  (The implementor needn't check for either of these
+     * things.)
+     *
+     * <p> Generally speaking, this method should not throw an exception
+     * under any circumstances.  If, however, if it does throw an exception,
+     * the exception will be intercepted and treated as a <tt>null</tt>
+     * return value.
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * @param key the key
+     * @return the value associated with the specified key at this preference
+     *          node, or <tt>null</tt> if there is no association for this
+     *          key, or the association cannot be determined at this time.
+     */
+    protected abstract String getSpi(String key);
+
+    /**
+     * Remove the association (if any) for the specified key at this
+     * preference node.  It is guaranteed that <tt>key</tt> is non-null.
+     * Also, it is guaranteed that this node has not been removed.
+     * (The implementor needn't check for either of these things.)
+     *
+     * <p>This method is invoked with the lock on this node held.
+     * @param key the key
+     */
+    protected abstract void removeSpi(String key);
+
+    /**
+     * Removes this preference node, invalidating it and any preferences that
+     * it contains.  The named child will have no descendants at the time this
+     * invocation is made (i.e., the {@link Preferences#removeNode()} method
+     * invokes this method repeatedly in a bottom-up fashion, removing each of
+     * a node's descendants before removing the node itself).
+     *
+     * <p>This method is invoked with the lock held on this node and its
+     * parent (and all ancestors that are being removed as a
+     * result of a single invocation to {@link Preferences#removeNode()}).
+     *
+     * <p>The removal of a node needn't become persistent until the
+     * <tt>flush</tt> method is invoked on this node (or an ancestor).
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #removeNode()}
+     * invocation.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract void removeNodeSpi() throws BackingStoreException;
+
+    /**
+     * Returns all of the keys that have an associated value in this
+     * preference node.  (The returned array will be of size zero if
+     * this node has no preferences.)  It is guaranteed that this node has not
+     * been removed.
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #keys()} invocation.
+     *
+     * @return an array of the keys that have an associated value in this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract String[] keysSpi() throws BackingStoreException;
+
+    /**
+     * Returns the names of the children of this preference node.  (The
+     * returned array will be of size zero if this node has no children.)
+     * This method need not return the names of any nodes already cached,
+     * but may do so without harm.
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #childrenNames()}
+     * invocation.
+     *
+     * @return an array containing the names of the children of this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract String[] childrenNamesSpi()
+        throws BackingStoreException;
+
+    /**
+     * Returns the named child if it exists, or <tt>null</tt> if it does not.
+     * It is guaranteed that <tt>nodeName</tt> is non-null, non-empty,
+     * does not contain the slash character ('/'), and is no longer than
+     * {@link #MAX_NAME_LENGTH} characters.  Also, it is guaranteed
+     * that this node has not been removed.  (The implementor needn't check
+     * for any of these things if he chooses to override this method.)
+     *
+     * <p>Finally, it is guaranteed that the named node has not been returned
+     * by a previous invocation of this method or {@link #childSpi} after the
+     * last time that it was removed.  In other words, a cached value will
+     * always be used in preference to invoking this method.  (The implementor
+     * needn't maintain his own cache of previously returned children if he
+     * chooses to override this method.)
+     *
+     * <p>This implementation obtains this preference node's lock, invokes
+     * {@link #childrenNames()} to get an array of the names of this node's
+     * children, and iterates over the array comparing the name of each child
+     * with the specified node name.  If a child node has the correct name,
+     * the {@link #childSpi(String)} method is invoked and the resulting
+     * node is returned.  If the iteration completes without finding the
+     * specified name, <tt>null</tt> is returned.
+     *
+     * @param nodeName name of the child to be searched for.
+     * @return the named child if it exists, or null if it does not.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected AbstractPreferences getChild(String nodeName)
+            throws BackingStoreException {
+        synchronized(lock) {
+            // assert kidCache.get(nodeName)==null;
+            String[] kidNames = childrenNames();
+            for (int i=0; i<kidNames.length; i++)
+                if (kidNames[i].equals(nodeName))
+                    return childSpi(kidNames[i]);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the named child of this preference node, creating it if it does
+     * not already exist.  It is guaranteed that <tt>name</tt> is non-null,
+     * non-empty, does not contain the slash character ('/'), and is no longer
+     * than {@link #MAX_NAME_LENGTH} characters.  Also, it is guaranteed that
+     * this node has not been removed.  (The implementor needn't check for any
+     * of these things.)
+     *
+     * <p>Finally, it is guaranteed that the named node has not been returned
+     * by a previous invocation of this method or {@link #getChild(String)}
+     * after the last time that it was removed.  In other words, a cached
+     * value will always be used in preference to invoking this method.
+     * Subclasses need not maintain their own cache of previously returned
+     * children.
+     *
+     * <p>The implementer must ensure that the returned node has not been
+     * removed.  If a like-named child of this node was previously removed, the
+     * implementer must return a newly constructed <tt>AbstractPreferences</tt>
+     * node; once removed, an <tt>AbstractPreferences</tt> node
+     * cannot be "resuscitated."
+     *
+     * <p>If this method causes a node to be created, this node is not
+     * guaranteed to be persistent until the <tt>flush</tt> method is
+     * invoked on this node or one of its ancestors (or descendants).
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * @param name The name of the child node to return, relative to
+     *        this preference node.
+     * @return The named child node.
+     */
+    protected abstract AbstractPreferences childSpi(String name);
+
+    /**
+     * Returns the absolute path name of this preferences node.
+     */
+    public String toString() {
+        return (this.isUserNode() ? "User" : "System") +
+               " Preference Node: " + this.absolutePath();
+    }
+
+    /**
+     * Implements the <tt>sync</tt> method as per the specification in
+     * {@link Preferences#sync()}.
+     *
+     * <p>This implementation calls a recursive helper method that locks this
+     * node, invokes syncSpi() on it, unlocks this node, and recursively
+     * invokes this method on each "cached child."  A cached child is a child
+     * of this node that has been created in this VM and not subsequently
+     * removed.  In effect, this method does a depth first traversal of the
+     * "cached subtree" rooted at this node, calling syncSpi() on each node in
+     * the subTree while only that node is locked. Note that syncSpi() is
+     * invoked top-down.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #flush()
+     */
+    public void sync() throws BackingStoreException {
+        sync2();
+    }
+
+    private void sync2() throws BackingStoreException {
+        AbstractPreferences[] cachedKids;
+
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed");
+            syncSpi();
+            cachedKids = cachedChildren();
+        }
+
+        for (int i=0; i<cachedKids.length; i++)
+            cachedKids[i].sync2();
+    }
+
+    /**
+     * This method is invoked with this node locked.  The contract of this
+     * method is to synchronize any cached preferences stored at this node
+     * with any stored in the backing store.  (It is perfectly possible that
+     * this node does not exist on the backing store, either because it has
+     * been deleted by another VM, or because it has not yet been created.)
+     * Note that this method should <i>not</i> synchronize the preferences in
+     * any subnodes of this node.  If the backing store naturally syncs an
+     * entire subtree at once, the implementer is encouraged to override
+     * sync(), rather than merely overriding this method.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #sync()} invocation.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract void syncSpi() throws BackingStoreException;
+
+    /**
+     * Implements the <tt>flush</tt> method as per the specification in
+     * {@link Preferences#flush()}.
+     *
+     * <p>This implementation calls a recursive helper method that locks this
+     * node, invokes flushSpi() on it, unlocks this node, and recursively
+     * invokes this method on each "cached child."  A cached child is a child
+     * of this node that has been created in this VM and not subsequently
+     * removed.  In effect, this method does a depth first traversal of the
+     * "cached subtree" rooted at this node, calling flushSpi() on each node in
+     * the subTree while only that node is locked. Note that flushSpi() is
+     * invoked top-down.
+     *
+     * <p> If this method is invoked on a node that has been removed with
+     * the {@link #removeNode()} method, flushSpi() is invoked on this node,
+     * but not on others.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @see #flush()
+     */
+    public void flush() throws BackingStoreException {
+        flush2();
+    }
+
+    private void flush2() throws BackingStoreException {
+        AbstractPreferences[] cachedKids;
+
+        synchronized(lock) {
+            flushSpi();
+            if(removed)
+                return;
+            cachedKids = cachedChildren();
+        }
+
+        for (int i = 0; i < cachedKids.length; i++)
+            cachedKids[i].flush2();
+    }
+
+    /**
+     * This method is invoked with this node locked.  The contract of this
+     * method is to force any cached changes in the contents of this
+     * preference node to the backing store, guaranteeing their persistence.
+     * (It is perfectly possible that this node does not exist on the backing
+     * store, either because it has been deleted by another VM, or because it
+     * has not yet been created.)  Note that this method should <i>not</i>
+     * flush the preferences in any subnodes of this node.  If the backing
+     * store naturally flushes an entire subtree at once, the implementer is
+     * encouraged to override flush(), rather than merely overriding this
+     * method.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #flush()} invocation.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract void flushSpi() throws BackingStoreException;
+
+    /**
+     * Returns <tt>true</tt> iff this node (or an ancestor) has been
+     * removed with the {@link #removeNode()} method.  This method
+     * locks this node prior to returning the contents of the private
+     * field used to track this state.
+     *
+     * @return <tt>true</tt> iff this node (or an ancestor) has been
+     *       removed with the {@link #removeNode()} method.
+     */
+    protected boolean isRemoved() {
+        synchronized(lock) {
+            return removed;
+        }
+    }
+
+    /**
+     * Queue of pending notification events.  When a preference or node
+     * change event for which there are one or more listeners occurs,
+     * it is placed on this queue and the queue is notified.  A background
+     * thread waits on this queue and delivers the events.  This decouples
+     * event delivery from preference activity, greatly simplifying
+     * locking and reducing opportunity for deadlock.
+     */
+    private static final List<EventObject> eventQueue = new LinkedList<>();
+
+    /**
+     * These two classes are used to distinguish NodeChangeEvents on
+     * eventQueue so the event dispatch thread knows whether to call
+     * childAdded or childRemoved.
+     */
+    private class NodeAddedEvent extends NodeChangeEvent {
+        private static final long serialVersionUID = -6743557530157328528L;
+        NodeAddedEvent(Preferences parent, Preferences child) {
+            super(parent, child);
+        }
+    }
+    private class NodeRemovedEvent extends NodeChangeEvent {
+        private static final long serialVersionUID = 8735497392918824837L;
+        NodeRemovedEvent(Preferences parent, Preferences child) {
+            super(parent, child);
+        }
+    }
+
+    /**
+     * A single background thread ("the event notification thread") monitors
+     * the event queue and delivers events that are placed on the queue.
+     */
+    private static class EventDispatchThread extends Thread {
+        public void run() {
+            while(true) {
+                // Wait on eventQueue till an event is present
+                EventObject event = null;
+                synchronized(eventQueue) {
+                    try {
+                        while (eventQueue.isEmpty())
+                            eventQueue.wait();
+                        event = eventQueue.remove(0);
+                    } catch (InterruptedException e) {
+                        // XXX Log "Event dispatch thread interrupted. Exiting"
+                        return;
+                    }
+                }
+
+                // Now we have event & hold no locks; deliver evt to listeners
+                AbstractPreferences src=(AbstractPreferences)event.getSource();
+                if (event instanceof PreferenceChangeEvent) {
+                    PreferenceChangeEvent pce = (PreferenceChangeEvent)event;
+                    PreferenceChangeListener[] listeners = src.prefListeners();
+                    for (int i=0; i<listeners.length; i++)
+                        listeners[i].preferenceChange(pce);
+                } else {
+                    NodeChangeEvent nce = (NodeChangeEvent)event;
+                    NodeChangeListener[] listeners = src.nodeListeners();
+                    if (nce instanceof NodeAddedEvent) {
+                        for (int i=0; i<listeners.length; i++)
+                            listeners[i].childAdded(nce);
+                    } else {
+                        // assert nce instanceof NodeRemovedEvent;
+                        for (int i=0; i<listeners.length; i++)
+                            listeners[i].childRemoved(nce);
+                    }
+                }
+            }
+        }
+    }
+
+    private static Thread eventDispatchThread = null;
+
+    /**
+     * This method starts the event dispatch thread the first time it
+     * is called.  The event dispatch thread will be started only
+     * if someone registers a listener.
+     */
+    private static synchronized void startEventDispatchThreadIfNecessary() {
+        if (eventDispatchThread == null) {
+            // XXX Log "Starting event dispatch thread"
+            eventDispatchThread = new EventDispatchThread();
+            eventDispatchThread.setDaemon(true);
+            eventDispatchThread.start();
+        }
+    }
+
+    // BEGIN Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    // Changed documentation.
+    /*
+    /**
+     * Return this node's preference/node change listeners.  Even though
+     * we're using a copy-on-write lists, we use synchronized accessors to
+     * ensure information transmission from the writing thread to the
+     * reading thread.
+     *
+    */
+    /**
+     * Return this node's preference/node change listeners. All accesses to prefListeners
+     * and nodeListeners are guarded by |lock|. We return a copy of the list so that the
+     * EventQueue thread will iterate over a fixed snapshot of the listeners at the time of
+     * this call.
+     */
+    // END Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    PreferenceChangeListener[] prefListeners() {
+        synchronized(lock) {
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // return prefListeners;
+            return prefListeners.toArray(new PreferenceChangeListener[prefListeners.size()]);
+        }
+    }
+    NodeChangeListener[] nodeListeners() {
+        synchronized(lock) {
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // return nodeListeners;
+            return nodeListeners.toArray(new NodeChangeListener[nodeListeners.size()]);
+        }
+    }
+
+    /**
+     * Enqueue a preference change event for delivery to registered
+     * preference change listeners unless there are no registered
+     * listeners.  Invoked with this.lock held.
+     */
+    private void enqueuePreferenceChangeEvent(String key, String newValue) {
+        // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+        // if (prefListeners.length != 0) {
+        if (!prefListeners.isEmpty()) {
+            synchronized(eventQueue) {
+                eventQueue.add(new PreferenceChangeEvent(this, key, newValue));
+                eventQueue.notify();
+            }
+        }
+    }
+
+    /**
+     * Enqueue a "node added" event for delivery to registered node change
+     * listeners unless there are no registered listeners.  Invoked with
+     * this.lock held.
+     */
+    private void enqueueNodeAddedEvent(Preferences child) {
+        // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+        // if (nodeListeners.length != 0) {
+        if (!nodeListeners.isEmpty()) {
+            synchronized(eventQueue) {
+                eventQueue.add(new NodeAddedEvent(this, child));
+                eventQueue.notify();
+            }
+        }
+    }
+
+    /**
+     * Enqueue a "node removed" event for delivery to registered node change
+     * listeners unless there are no registered listeners.  Invoked with
+     * this.lock held.
+     */
+    private void enqueueNodeRemovedEvent(Preferences child) {
+        // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+        // if (nodeListeners.length != 0) {
+        if (!nodeListeners.isEmpty()) {
+            synchronized(eventQueue) {
+                eventQueue.add(new NodeRemovedEvent(this, child));
+                eventQueue.notify();
+            }
+        }
+    }
+
+    /**
+     * Implements the <tt>exportNode</tt> method as per the specification in
+     * {@link Preferences#exportNode(OutputStream)}.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     */
+    public void exportNode(OutputStream os)
+        throws IOException, BackingStoreException
+    {
+        XmlSupport.export(os, this, false);
+    }
+
+    /**
+     * Implements the <tt>exportSubtree</tt> method as per the specification in
+     * {@link Preferences#exportSubtree(OutputStream)}.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     */
+    public void exportSubtree(OutputStream os)
+        throws IOException, BackingStoreException
+    {
+        XmlSupport.export(os, this, true);
+    }
+}
diff --git a/java/util/prefs/BackingStoreException.java b/java/util/prefs/BackingStoreException.java
new file mode 100644
index 0000000..0bce9c6
--- /dev/null
+++ b/java/util/prefs/BackingStoreException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * Thrown to indicate that a preferences operation could not complete because
+ * of a failure in the backing store, or a failure to contact the backing
+ * store.
+ *
+ * @author  Josh Bloch
+ * @since   1.4
+ */
+public class BackingStoreException extends Exception {
+    /**
+     * Constructs a BackingStoreException with the specified detail message.
+     *
+     * @param s the detail message.
+     */
+    public BackingStoreException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a BackingStoreException with the specified cause.
+     *
+     * @param cause the cause
+     */
+    public BackingStoreException(Throwable cause) {
+        super(cause);
+    }
+
+    private static final long serialVersionUID = 859796500401108469L;
+}
diff --git a/java/util/prefs/Base64.java b/java/util/prefs/Base64.java
new file mode 100644
index 0000000..c0d8d53
--- /dev/null
+++ b/java/util/prefs/Base64.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * Static methods for translating Base64 encoded strings to byte arrays
+ * and vice-versa.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+class Base64 {
+    /**
+     * Translates the specified byte array into a Base64 string as per
+     * Preferences.put(byte[]).
+     */
+    static String byteArrayToBase64(byte[] a) {
+        return byteArrayToBase64(a, false);
+    }
+
+    /**
+     * Translates the specified byte array into an "alternate representation"
+     * Base64 string.  This non-standard variant uses an alphabet that does
+     * not contain the uppercase alphabetic characters, which makes it
+     * suitable for use in situations where case-folding occurs.
+     */
+    static String byteArrayToAltBase64(byte[] a) {
+        return byteArrayToBase64(a, true);
+    }
+
+    private static String byteArrayToBase64(byte[] a, boolean alternate) {
+        int aLen = a.length;
+        int numFullGroups = aLen/3;
+        int numBytesInPartialGroup = aLen - 3*numFullGroups;
+        int resultLen = 4*((aLen + 2)/3);
+        StringBuffer result = new StringBuffer(resultLen);
+        char[] intToAlpha = (alternate ? intToAltBase64 : intToBase64);
+
+        // Translate all full groups from byte array elements to Base64
+        int inCursor = 0;
+        for (int i=0; i<numFullGroups; i++) {
+            int byte0 = a[inCursor++] & 0xff;
+            int byte1 = a[inCursor++] & 0xff;
+            int byte2 = a[inCursor++] & 0xff;
+            result.append(intToAlpha[byte0 >> 2]);
+            result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
+            result.append(intToAlpha[(byte1 << 2)&0x3f | (byte2 >> 6)]);
+            result.append(intToAlpha[byte2 & 0x3f]);
+        }
+
+        // Translate partial group if present
+        if (numBytesInPartialGroup != 0) {
+            int byte0 = a[inCursor++] & 0xff;
+            result.append(intToAlpha[byte0 >> 2]);
+            if (numBytesInPartialGroup == 1) {
+                result.append(intToAlpha[(byte0 << 4) & 0x3f]);
+                result.append("==");
+            } else {
+                // assert numBytesInPartialGroup == 2;
+                int byte1 = a[inCursor++] & 0xff;
+                result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
+                result.append(intToAlpha[(byte1 << 2)&0x3f]);
+                result.append('=');
+            }
+        }
+        // assert inCursor == a.length;
+        // assert result.length() == resultLen;
+        return result.toString();
+    }
+
+    /**
+     * This array is a lookup table that translates 6-bit positive integer
+     * index values into their "Base64 Alphabet" equivalents as specified
+     * in Table 1 of RFC 2045.
+     */
+    private static final char intToBase64[] = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+    };
+
+    /**
+     * This array is a lookup table that translates 6-bit positive integer
+     * index values into their "Alternate Base64 Alphabet" equivalents.
+     * This is NOT the real Base64 Alphabet as per in Table 1 of RFC 2045.
+     * This alternate alphabet does not use the capital letters.  It is
+     * designed for use in environments where "case folding" occurs.
+     */
+    private static final char intToAltBase64[] = {
+        '!', '"', '#', '$', '%', '&', '\'', '(', ')', ',', '-', '.', ':',
+        ';', '<', '>', '@', '[', ']', '^',  '`', '_', '{', '|', '}', '~',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't',  'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6',  '7', '8', '9', '+', '?'
+    };
+
+    /**
+     * Translates the specified Base64 string (as per Preferences.get(byte[]))
+     * into a byte array.
+     *
+     * @throw IllegalArgumentException if <tt>s</tt> is not a valid Base64
+     *        string.
+     */
+    static byte[] base64ToByteArray(String s) {
+        return base64ToByteArray(s, false);
+    }
+
+    /**
+     * Translates the specified "alternate representation" Base64 string
+     * into a byte array.
+     *
+     * @throw IllegalArgumentException or ArrayOutOfBoundsException
+     *        if <tt>s</tt> is not a valid alternate representation
+     *        Base64 string.
+     */
+    static byte[] altBase64ToByteArray(String s) {
+        return base64ToByteArray(s, true);
+    }
+
+    private static byte[] base64ToByteArray(String s, boolean alternate) {
+        byte[] alphaToInt = (alternate ?  altBase64ToInt : base64ToInt);
+        int sLen = s.length();
+        int numGroups = sLen/4;
+        if (4*numGroups != sLen)
+            throw new IllegalArgumentException(
+                "String length must be a multiple of four.");
+        int missingBytesInLastGroup = 0;
+        int numFullGroups = numGroups;
+        if (sLen != 0) {
+            if (s.charAt(sLen-1) == '=') {
+                missingBytesInLastGroup++;
+                numFullGroups--;
+            }
+            if (s.charAt(sLen-2) == '=')
+                missingBytesInLastGroup++;
+        }
+        byte[] result = new byte[3*numGroups - missingBytesInLastGroup];
+
+        // Translate all full groups from base64 to byte array elements
+        int inCursor = 0, outCursor = 0;
+        for (int i=0; i<numFullGroups; i++) {
+            int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch3 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
+            result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
+            result[outCursor++] = (byte) ((ch2 << 6) | ch3);
+        }
+
+        // Translate partial group, if present
+        if (missingBytesInLastGroup != 0) {
+            int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
+
+            if (missingBytesInLastGroup == 1) {
+                int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt);
+                result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
+            }
+        }
+        // assert inCursor == s.length()-missingBytesInLastGroup;
+        // assert outCursor == result.length;
+        return result;
+    }
+
+    /**
+     * Translates the specified character, which is assumed to be in the
+     * "Base 64 Alphabet" into its equivalent 6-bit positive integer.
+     *
+     * @throw IllegalArgumentException or ArrayOutOfBoundsException if
+     *        c is not in the Base64 Alphabet.
+     */
+    private static int base64toInt(char c, byte[] alphaToInt) {
+        int result = alphaToInt[c];
+        if (result < 0)
+            throw new IllegalArgumentException("Illegal character " + c);
+        return result;
+    }
+
+    /**
+     * This array is a lookup table that translates unicode characters
+     * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045)
+     * into their 6-bit positive integer equivalents.  Characters that
+     * are not in the Base64 alphabet but fall within the bounds of the
+     * array are translated to -1.
+     */
+    private static final byte base64ToInt[] = {
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
+        55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
+        5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+        24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+        35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+    };
+
+    /**
+     * This array is the analogue of base64ToInt, but for the nonstandard
+     * variant that avoids the use of uppercase alphabetic characters.
+     */
+    private static final byte altBase64ToInt[] = {
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1,
+        2, 3, 4, 5, 6, 7, 8, -1, 62, 9, 10, 11, -1 , 52, 53, 54, 55, 56, 57,
+        58, 59, 60, 61, 12, 13, 14, -1, 15, 63, 16, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, 17, -1, 18, 19, 21, 20, 26, 27, 28, 29, 30, 31, 32, 33,
+        34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+        51, 22, 23, 24, 25
+    };
+
+    public static void main(String args[]) {
+        int numRuns  = Integer.parseInt(args[0]);
+        int numBytes = Integer.parseInt(args[1]);
+        java.util.Random rnd = new java.util.Random();
+        for (int i=0; i<numRuns; i++) {
+            for (int j=0; j<numBytes; j++) {
+                byte[] arr = new byte[j];
+                for (int k=0; k<j; k++)
+                    arr[k] = (byte)rnd.nextInt();
+
+                String s = byteArrayToBase64(arr);
+                byte [] b = base64ToByteArray(s);
+                if (!java.util.Arrays.equals(arr, b))
+                    System.out.println("Dismal failure!");
+
+                s = byteArrayToAltBase64(arr);
+                b = altBase64ToByteArray(s);
+                if (!java.util.Arrays.equals(arr, b))
+                    System.out.println("Alternate dismal failure!");
+            }
+        }
+    }
+}
diff --git a/java/util/prefs/FileSystemPreferences.java b/java/util/prefs/FileSystemPreferences.java
new file mode 100644
index 0000000..b888c4d
--- /dev/null
+++ b/java/util/prefs/FileSystemPreferences.java
@@ -0,0 +1,996 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+import java.util.*;
+import java.io.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+
+import sun.util.logging.PlatformLogger;
+
+// Android-changed: @hide.
+/**
+ * Preferences implementation for Unix.  Preferences are stored in the file
+ * system, with one directory per preferences node.  All of the preferences
+ * at each node are stored in a single file.  Atomic file system operations
+ * (e.g. File.renameTo) are used to ensure integrity.  An in-memory cache of
+ * the "explored" portion of the tree is maintained for performance, and
+ * written back to the disk periodically.  File-locking is used to ensure
+ * reasonable behavior when multiple VMs are running at the same time.
+ * (The file lock is obtained only for sync(), flush() and removeNode().)
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ *
+ * @hide
+ */
+public class FileSystemPreferences extends AbstractPreferences {
+    /**
+     * Returns logger for error messages. Backing store exceptions are logged at
+     * WARNING level.
+     */
+    private static PlatformLogger getLogger() {
+        return PlatformLogger.getLogger("java.util.prefs");
+    }
+
+    /**
+     * Directory for system preferences.
+     */
+    private static File systemRootDir;
+
+    /*
+     * Flag, indicating whether systemRoot  directory is writable
+     */
+    private static boolean isSystemRootWritable;
+
+    /**
+     * Directory for user preferences.
+     */
+    private static File userRootDir;
+
+    /*
+     * Flag, indicating whether userRoot  directory is writable
+     */
+    private static boolean isUserRootWritable;
+
+   /**
+     * The user root.
+     */
+    static Preferences userRoot = null;
+
+    static synchronized Preferences getUserRoot() {
+        if (userRoot == null) {
+            setupUserRoot();
+            userRoot = new FileSystemPreferences(true);
+        }
+        return userRoot;
+    }
+
+    private static void setupUserRoot() {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                userRootDir =
+                      new File(System.getProperty("java.util.prefs.userRoot",
+                      System.getProperty("user.home")), ".java/.userPrefs");
+                // Attempt to create root dir if it does not yet exist.
+                if (!userRootDir.exists()) {
+                    if (userRootDir.mkdirs()) {
+                        try {
+                            chmod(userRootDir.getCanonicalPath(), USER_RWX);
+                        } catch (IOException e) {
+                            getLogger().warning("Could not change permissions" +
+                                " on userRoot directory. ");
+                        }
+                        getLogger().info("Created user preferences directory.");
+                    }
+                    else
+                        getLogger().warning("Couldn't create user preferences" +
+                        " directory. User preferences are unusable.");
+                }
+                isUserRootWritable = userRootDir.canWrite();
+                String USER_NAME = System.getProperty("user.name");
+                userLockFile = new File (userRootDir,".user.lock." + USER_NAME);
+                userRootModFile = new File (userRootDir,
+                                               ".userRootModFile." + USER_NAME);
+                if (!userRootModFile.exists())
+                try {
+                    // create if does not exist.
+                    userRootModFile.createNewFile();
+                    // Only user can read/write userRootModFile.
+                    int result = chmod(userRootModFile.getCanonicalPath(),
+                                                               USER_READ_WRITE);
+                    if (result !=0)
+                        getLogger().warning("Problem creating userRoot " +
+                            "mod file. Chmod failed on " +
+                             userRootModFile.getCanonicalPath() +
+                             " Unix error code " + result);
+                } catch (IOException e) {
+                    getLogger().warning(e.toString());
+                }
+                userRootModTime = userRootModFile.lastModified();
+                return null;
+            }
+        });
+    }
+
+
+    /**
+     * The system root.
+     */
+    static Preferences systemRoot;
+
+    static synchronized Preferences getSystemRoot() {
+        if (systemRoot == null) {
+            setupSystemRoot();
+            systemRoot = new FileSystemPreferences(false);
+        }
+        return systemRoot;
+    }
+
+    private static void setupSystemRoot() {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                String systemPrefsDirName =
+                  System.getProperty("java.util.prefs.systemRoot","/etc/.java");
+                systemRootDir =
+                     new File(systemPrefsDirName, ".systemPrefs");
+                // Attempt to create root dir if it does not yet exist.
+                if (!systemRootDir.exists()) {
+                    // system root does not exist in /etc/.java
+                    // Switching  to java.home
+                    systemRootDir =
+                                  new File(System.getProperty("java.home"),
+                                                            ".systemPrefs");
+                    if (!systemRootDir.exists()) {
+                        if (systemRootDir.mkdirs()) {
+                            getLogger().info(
+                                "Created system preferences directory "
+                                + "in java.home.");
+                            try {
+                                chmod(systemRootDir.getCanonicalPath(),
+                                                          USER_RWX_ALL_RX);
+                            } catch (IOException e) {
+                            }
+                        } else {
+                            getLogger().warning("Could not create "
+                                + "system preferences directory. System "
+                                + "preferences are unusable.");
+                        }
+                    }
+                }
+                isSystemRootWritable = systemRootDir.canWrite();
+                systemLockFile = new File(systemRootDir, ".system.lock");
+                systemRootModFile =
+                               new File (systemRootDir,".systemRootModFile");
+                if (!systemRootModFile.exists() && isSystemRootWritable)
+                try {
+                    // create if does not exist.
+                    systemRootModFile.createNewFile();
+                    int result = chmod(systemRootModFile.getCanonicalPath(),
+                                                          USER_RW_ALL_READ);
+                    if (result !=0)
+                        getLogger().warning("Chmod failed on " +
+                               systemRootModFile.getCanonicalPath() +
+                              " Unix error code " + result);
+                } catch (IOException e) { getLogger().warning(e.toString());
+                }
+                systemRootModTime = systemRootModFile.lastModified();
+                return null;
+            }
+        });
+    }
+
+
+    /**
+     * Unix user write/read permission
+     */
+    private static final int USER_READ_WRITE = 0600;
+
+    private static final int USER_RW_ALL_READ = 0644;
+
+
+    private static final int USER_RWX_ALL_RX = 0755;
+
+    private static final int USER_RWX = 0700;
+
+    /**
+     * The lock file for the user tree.
+     */
+    static File userLockFile;
+
+
+
+    /**
+     * The lock file for the system tree.
+     */
+    static File systemLockFile;
+
+    /**
+     * Unix lock handle for userRoot.
+     * Zero, if unlocked.
+     */
+
+    private static int userRootLockHandle = 0;
+
+    /**
+     * Unix lock handle for systemRoot.
+     * Zero, if unlocked.
+     */
+
+    private static int systemRootLockHandle = 0;
+
+    /**
+     * The directory representing this preference node.  There is no guarantee
+     * that this directory exits, as another VM can delete it at any time
+     * that it (the other VM) holds the file-lock.  While the root node cannot
+     * be deleted, it may not yet have been created, or the underlying
+     * directory could have been deleted accidentally.
+     */
+    private final File dir;
+
+    /**
+     * The file representing this preference node's preferences.
+     * The file format is undocumented, and subject to change
+     * from release to release, but I'm sure that you can figure
+     * it out if you try real hard.
+     */
+    private final File prefsFile;
+
+    /**
+     * A temporary file used for saving changes to preferences.  As part of
+     * the sync operation, changes are first saved into this file, and then
+     * atomically renamed to prefsFile.  This results in an atomic state
+     * change from one valid set of preferences to another.  The
+     * the file-lock is held for the duration of this transformation.
+     */
+    private final File tmpFile;
+
+    /**
+     * File, which keeps track of global modifications of userRoot.
+     */
+    private static  File userRootModFile;
+
+    /**
+     * Flag, which indicated whether userRoot was modified by another VM
+     */
+    private static boolean isUserRootModified = false;
+
+    /**
+     * Keeps track of userRoot modification time. This time is reset to
+     * zero after UNIX reboot, and is increased by 1 second each time
+     * userRoot is modified.
+     */
+    private static long userRootModTime;
+
+
+    /*
+     * File, which keeps track of global modifications of systemRoot
+     */
+    private static File systemRootModFile;
+    /*
+     * Flag, which indicates whether systemRoot was modified by another VM
+     */
+    private static boolean isSystemRootModified = false;
+
+    /**
+     * Keeps track of systemRoot modification time. This time is reset to
+     * zero after system reboot, and is increased by 1 second each time
+     * systemRoot is modified.
+     */
+    private static long systemRootModTime;
+
+    /**
+     * Locally cached preferences for this node (includes uncommitted
+     * changes).  This map is initialized with from disk when the first get or
+     * put operation occurs on this node.  It is synchronized with the
+     * corresponding disk file (prefsFile) by the sync operation.  The initial
+     * value is read *without* acquiring the file-lock.
+     */
+    private Map<String, String> prefsCache = null;
+
+    /**
+     * The last modification time of the file backing this node at the time
+     * that prefCache was last synchronized (or initially read).  This
+     * value is set *before* reading the file, so it's conservative; the
+     * actual timestamp could be (slightly) higher.  A value of zero indicates
+     * that we were unable to initialize prefsCache from the disk, or
+     * have not yet attempted to do so.  (If prefsCache is non-null, it
+     * indicates the former; if it's null, the latter.)
+     */
+    private long lastSyncTime = 0;
+
+   /**
+    * Unix error code for locked file.
+    */
+    private static final int EAGAIN = 11;
+
+   /**
+    * Unix error code for denied access.
+    */
+    private static final int EACCES = 13;
+
+    /* Used to interpret results of native functions */
+    private static final int LOCK_HANDLE = 0;
+    private static final int ERROR_CODE = 1;
+
+    /**
+     * A list of all uncommitted preference changes.  The elements in this
+     * list are of type PrefChange.  If this node is concurrently modified on
+     * disk by another VM, the two sets of changes are merged when this node
+     * is sync'ed by overwriting our prefsCache with the preference map last
+     * written out to disk (by the other VM), and then replaying this change
+     * log against that map.  The resulting map is then written back
+     * to the disk.
+     */
+    final List<Change> changeLog = new ArrayList<>();
+
+    /**
+     * Represents a change to a preference.
+     */
+    private abstract class Change {
+        /**
+         * Reapplies the change to prefsCache.
+         */
+        abstract void replay();
+    };
+
+    /**
+     * Represents a preference put.
+     */
+    private class Put extends Change {
+        String key, value;
+
+        Put(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        void replay() {
+            prefsCache.put(key, value);
+        }
+    }
+
+    /**
+     * Represents a preference remove.
+     */
+    private class Remove extends Change {
+        String key;
+
+        Remove(String key) {
+            this.key = key;
+        }
+
+        void replay() {
+            prefsCache.remove(key);
+        }
+    }
+
+    /**
+     * Represents the creation of this node.
+     */
+    private class NodeCreate extends Change {
+        /**
+         * Performs no action, but the presence of this object in changeLog
+         * will force the node and its ancestors to be made permanent at the
+         * next sync.
+         */
+        void replay() {
+        }
+    }
+
+    /**
+     * NodeCreate object for this node.
+     */
+    NodeCreate nodeCreate = null;
+
+    /**
+     * Replay changeLog against prefsCache.
+     */
+    private void replayChanges() {
+        for (int i = 0, n = changeLog.size(); i<n; i++)
+            changeLog.get(i).replay();
+    }
+
+    static {
+        // Add shutdown hook to flush cached prefs on normal termination
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            public void run() {
+                syncWorld();
+            }
+        });
+    }
+
+    private static void syncWorld() {
+        /*
+         * Synchronization necessary because userRoot and systemRoot are
+         * lazily initialized.
+         */
+        Preferences userRt;
+        Preferences systemRt;
+        synchronized(FileSystemPreferences.class) {
+            userRt   = userRoot;
+            systemRt = systemRoot;
+        }
+
+        try {
+            if (userRt != null)
+                userRt.flush();
+        } catch(BackingStoreException e) {
+            getLogger().warning("Couldn't flush user prefs: " + e);
+        }
+
+        try {
+            if (systemRt != null)
+                systemRt.flush();
+        } catch(BackingStoreException e) {
+            getLogger().warning("Couldn't flush system prefs: " + e);
+        }
+    }
+
+    private final boolean isUserNode;
+
+    /**
+     * Special constructor for roots (both user and system).  This constructor
+     * will only be called twice, by the static initializer.
+     */
+    private FileSystemPreferences(boolean user) {
+        super(null, "");
+        isUserNode = user;
+        dir = (user ? userRootDir: systemRootDir);
+        prefsFile = new File(dir, "prefs.xml");
+        tmpFile   = new File(dir, "prefs.tmp");
+    }
+
+    /** @hide for unit testing only */
+    // Android-added constructor for testing.
+    public FileSystemPreferences(String path, File lockFile, boolean isUserNode) {
+        super(null, "");
+        this.isUserNode = isUserNode;
+        this.dir = new File(path);
+        prefsFile = new File(dir, "prefs.xml");
+        tmpFile = new File(dir, "prefs.tmp");
+        newNode = !dir.exists();
+        if (newNode) {
+            // These 2 things guarantee node will get wrtten at next flush/sync
+            prefsCache = new TreeMap<>();
+            nodeCreate = new NodeCreate();
+            changeLog.add(nodeCreate);
+        }
+
+        if (isUserNode) {
+            userLockFile = lockFile;
+            userRootModFile = new File(lockFile.getParentFile(), lockFile.getName() + ".rootmod");
+        } else {
+            systemLockFile = lockFile;
+            systemRootModFile = new File(lockFile.getParentFile(), lockFile.getName() + ".rootmod");
+        }
+    }
+
+    /**
+     * Construct a new FileSystemPreferences instance with the specified
+     * parent node and name.  This constructor, called from childSpi,
+     * is used to make every node except for the two //roots.
+     */
+    private FileSystemPreferences(FileSystemPreferences parent, String name) {
+        super(parent, name);
+        isUserNode = parent.isUserNode;
+        dir  = new File(parent.dir, dirName(name));
+        prefsFile = new File(dir, "prefs.xml");
+        tmpFile  = new File(dir, "prefs.tmp");
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                newNode = !dir.exists();
+                return null;
+            }
+        });
+        if (newNode) {
+            // These 2 things guarantee node will get wrtten at next flush/sync
+            prefsCache = new TreeMap<>();
+            nodeCreate = new NodeCreate();
+            changeLog.add(nodeCreate);
+        }
+    }
+
+    public boolean isUserNode() {
+        return isUserNode;
+    }
+
+    protected void putSpi(String key, String value) {
+        initCacheIfNecessary();
+        changeLog.add(new Put(key, value));
+        prefsCache.put(key, value);
+    }
+
+    protected String getSpi(String key) {
+        initCacheIfNecessary();
+        return prefsCache.get(key);
+    }
+
+    protected void removeSpi(String key) {
+        initCacheIfNecessary();
+        changeLog.add(new Remove(key));
+        prefsCache.remove(key);
+    }
+
+    /**
+     * Initialize prefsCache if it has yet to be initialized.  When this method
+     * returns, prefsCache will be non-null.  If the data was successfully
+     * read from the file, lastSyncTime will be updated.  If prefsCache was
+     * null, but it was impossible to read the file (because it didn't
+     * exist or for any other reason) prefsCache will be initialized to an
+     * empty, modifiable Map, and lastSyncTime remain zero.
+     */
+    private void initCacheIfNecessary() {
+        if (prefsCache != null)
+            return;
+
+        try {
+            loadCache();
+        } catch(Exception e) {
+            // assert lastSyncTime == 0;
+            prefsCache = new TreeMap<>();
+        }
+    }
+
+    /**
+     * Attempt to load prefsCache from the backing store.  If the attempt
+     * succeeds, lastSyncTime will be updated (the new value will typically
+     * correspond to the data loaded into the map, but it may be less,
+     * if another VM is updating this node concurrently).  If the attempt
+     * fails, a BackingStoreException is thrown and both prefsCache and
+     * lastSyncTime are unaffected by the call.
+     */
+    private void loadCache() throws BackingStoreException {
+        Map<String, String> m = new TreeMap<>();
+        long newLastSyncTime = 0;
+        try {
+            newLastSyncTime = prefsFile.lastModified();
+            try (FileInputStream fis = new FileInputStream(prefsFile)) {
+                XmlSupport.importMap(fis, m);
+            }
+        } catch(Exception e) {
+            if (e instanceof InvalidPreferencesFormatException) {
+                getLogger().warning("Invalid preferences format in "
+                                    +  prefsFile.getPath());
+                prefsFile.renameTo( new File(
+                                             prefsFile.getParentFile(),
+                                             "IncorrectFormatPrefs.xml"));
+                m = new TreeMap<>();
+            } else if (e instanceof FileNotFoundException) {
+                getLogger().warning("Prefs file removed in background "
+                                    + prefsFile.getPath());
+            } else {
+                // Android-added: This exception may be ignored by some callers,
+                // added a logger entry to prevent omitting it completely.
+                getLogger().warning("Exception while reading cache: "
+                                    + e.getMessage());
+                throw new BackingStoreException(e);
+            }
+        }
+        // Attempt succeeded; update state
+        prefsCache = m;
+        lastSyncTime = newLastSyncTime;
+    }
+
+    /**
+     * Attempt to write back prefsCache to the backing store.  If the attempt
+     * succeeds, lastSyncTime will be updated (the new value will correspond
+     * exactly to the data thust written back, as we hold the file lock, which
+     * prevents a concurrent write.  If the attempt fails, a
+     * BackingStoreException is thrown and both the backing store (prefsFile)
+     * and lastSyncTime will be unaffected by this call.  This call will
+     * NEVER leave prefsFile in a corrupt state.
+     */
+    private void writeBackCache() throws BackingStoreException {
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                public Void run() throws BackingStoreException {
+                    try {
+                        if (!dir.exists() && !dir.mkdirs())
+                            throw new BackingStoreException(dir +
+                                                             " create failed.");
+                        try (FileOutputStream fos = new FileOutputStream(tmpFile)) {
+                            XmlSupport.exportMap(fos, prefsCache);
+                        }
+                        if (!tmpFile.renameTo(prefsFile))
+                            throw new BackingStoreException("Can't rename " +
+                            tmpFile + " to " + prefsFile);
+                    } catch(Exception e) {
+                        if (e instanceof BackingStoreException)
+                            throw (BackingStoreException)e;
+                        throw new BackingStoreException(e);
+                    }
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw (BackingStoreException) e.getException();
+        }
+    }
+
+    protected String[] keysSpi() {
+        initCacheIfNecessary();
+        return prefsCache.keySet().toArray(new String[prefsCache.size()]);
+    }
+
+    protected String[] childrenNamesSpi() {
+        return AccessController.doPrivileged(
+            new PrivilegedAction<String[]>() {
+                public String[] run() {
+                    List<String> result = new ArrayList<>();
+                    File[] dirContents = dir.listFiles();
+                    if (dirContents != null) {
+                        for (int i = 0; i < dirContents.length; i++)
+                            if (dirContents[i].isDirectory())
+                                result.add(nodeName(dirContents[i].getName()));
+                    }
+                    return result.toArray(EMPTY_STRING_ARRAY);
+               }
+            });
+    }
+
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    protected AbstractPreferences childSpi(String name) {
+        return new FileSystemPreferences(this, name);
+    }
+
+    public void removeNode() throws BackingStoreException {
+        synchronized (isUserNode()? userLockFile: systemLockFile) {
+            // to remove a node we need an exclusive lock
+            if (!lockFile(false))
+                throw(new BackingStoreException("Couldn't get file lock."));
+           try {
+                super.removeNode();
+           } finally {
+                unlockFile();
+           }
+        }
+    }
+
+    /**
+     * Called with file lock held (in addition to node locks).
+     */
+    protected void removeNodeSpi() throws BackingStoreException {
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                public Void run() throws BackingStoreException {
+                    if (changeLog.contains(nodeCreate)) {
+                        changeLog.remove(nodeCreate);
+                        nodeCreate = null;
+                        return null;
+                    }
+                    if (!dir.exists())
+                        return null;
+                    prefsFile.delete();
+                    tmpFile.delete();
+                    // dir should be empty now.  If it's not, empty it
+                    File[] junk = dir.listFiles();
+                    if (junk.length != 0) {
+                        getLogger().warning(
+                           "Found extraneous files when removing node: "
+                            + Arrays.asList(junk));
+                        for (int i=0; i<junk.length; i++)
+                            junk[i].delete();
+                    }
+                    if (!dir.delete())
+                        throw new BackingStoreException("Couldn't delete dir: "
+                                                                         + dir);
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw (BackingStoreException) e.getException();
+        }
+    }
+
+    public synchronized void sync() throws BackingStoreException {
+        boolean userNode = isUserNode();
+        boolean shared;
+
+        if (userNode) {
+            shared = false; /* use exclusive lock for user prefs */
+        } else {
+            /* if can write to system root, use exclusive lock.
+               otherwise use shared lock. */
+            shared = !isSystemRootWritable;
+        }
+        synchronized (isUserNode()? userLockFile:systemLockFile) {
+           if (!lockFile(shared))
+               throw(new BackingStoreException("Couldn't get file lock."));
+           final Long newModTime =
+                AccessController.doPrivileged(
+                    new PrivilegedAction<Long>() {
+               public Long run() {
+                   long nmt;
+                   if (isUserNode()) {
+                       nmt = userRootModFile.lastModified();
+                       isUserRootModified = userRootModTime == nmt;
+                   } else {
+                       nmt = systemRootModFile.lastModified();
+                       isSystemRootModified = systemRootModTime == nmt;
+                   }
+                   return new Long(nmt);
+               }
+           });
+           try {
+               super.sync();
+               AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                   public Void run() {
+                   if (isUserNode()) {
+                       userRootModTime = newModTime.longValue() + 1000;
+                       userRootModFile.setLastModified(userRootModTime);
+                   } else {
+                       systemRootModTime = newModTime.longValue() + 1000;
+                       systemRootModFile.setLastModified(systemRootModTime);
+                   }
+                   return null;
+                   }
+               });
+           } finally {
+                unlockFile();
+           }
+        }
+    }
+
+    protected void syncSpi() throws BackingStoreException {
+        syncSpiPrivileged();
+    }
+
+    private void syncSpiPrivileged() throws BackingStoreException {
+        if (isRemoved())
+            throw new IllegalStateException("Node has been removed");
+        if (prefsCache == null)
+            return;  // We've never been used, don't bother syncing
+        long lastModifiedTime;
+        if ((isUserNode() ? isUserRootModified : isSystemRootModified)) {
+            lastModifiedTime = prefsFile.lastModified();
+            if (lastModifiedTime  != lastSyncTime) {
+                // Prefs at this node were externally modified; read in node and
+                // playback any local mods since last sync
+                loadCache();
+                replayChanges();
+                lastSyncTime = lastModifiedTime;
+            }
+        } else if (lastSyncTime != 0 && !dir.exists()) {
+            // This node was removed in the background.  Playback any changes
+            // against a virgin (empty) Map.
+            prefsCache = new TreeMap<>();
+            replayChanges();
+        }
+        if (!changeLog.isEmpty()) {
+            writeBackCache();  // Creates directory & file if necessary
+           /*
+            * Attempt succeeded; it's barely possible that the call to
+            * lastModified might fail (i.e., return 0), but this would not
+            * be a disaster, as lastSyncTime is allowed to lag.
+            */
+            lastModifiedTime = prefsFile.lastModified();
+            /* If lastSyncTime did not change, or went back
+             * increment by 1 second. Since we hold the lock
+             * lastSyncTime always monotonically encreases in the
+             * atomic sense.
+             */
+            if (lastSyncTime <= lastModifiedTime) {
+                lastSyncTime = lastModifiedTime + 1000;
+                prefsFile.setLastModified(lastSyncTime);
+            }
+            changeLog.clear();
+        }
+    }
+
+    public void flush() throws BackingStoreException {
+        if (isRemoved())
+            return;
+        sync();
+    }
+
+    protected void flushSpi() throws BackingStoreException {
+        // assert false;
+    }
+
+    /**
+     * Returns true if the specified character is appropriate for use in
+     * Unix directory names.  A character is appropriate if it's a printable
+     * ASCII character (> 0x1f && < 0x7f) and unequal to slash ('/', 0x2f),
+     * dot ('.', 0x2e), or underscore ('_', 0x5f).
+     */
+    private static boolean isDirChar(char ch) {
+        return ch > 0x1f && ch < 0x7f && ch != '/' && ch != '.' && ch != '_';
+    }
+
+    /**
+     * Returns the directory name corresponding to the specified node name.
+     * Generally, this is just the node name.  If the node name includes
+     * inappropriate characters (as per isDirChar) it is translated to Base64.
+     * with the underscore  character ('_', 0x5f) prepended.
+     */
+    private static String dirName(String nodeName) {
+        for (int i=0, n=nodeName.length(); i < n; i++)
+            if (!isDirChar(nodeName.charAt(i)))
+                return "_" + Base64.byteArrayToAltBase64(byteArray(nodeName));
+        return nodeName;
+    }
+
+    /**
+     * Translate a string into a byte array by translating each character
+     * into two bytes, high-byte first ("big-endian").
+     */
+    private static byte[] byteArray(String s) {
+        int len = s.length();
+        byte[] result = new byte[2*len];
+        for (int i=0, j=0; i<len; i++) {
+            char c = s.charAt(i);
+            result[j++] = (byte) (c>>8);
+            result[j++] = (byte) c;
+        }
+        return result;
+    }
+
+    /**
+     * Returns the node name corresponding to the specified directory name.
+ * (Inverts the transformation of dirName(String).
+     */
+    private static String nodeName(String dirName) {
+        if (dirName.charAt(0) != '_')
+            return dirName;
+        byte a[] = Base64.altBase64ToByteArray(dirName.substring(1));
+        StringBuffer result = new StringBuffer(a.length/2);
+        for (int i = 0; i < a.length; ) {
+            int highByte = a[i++] & 0xff;
+            int lowByte =  a[i++] & 0xff;
+            result.append((char) ((highByte << 8) | lowByte));
+        }
+        return result.toString();
+    }
+
+    /**
+     * Try to acquire the appropriate file lock (user or system).  If
+     * the initial attempt fails, several more attempts are made using
+     * an exponential backoff strategy.  If all attempts fail, this method
+     * returns false.
+     * @throws SecurityException if file access denied.
+     */
+    private boolean lockFile(boolean shared) throws SecurityException{
+        boolean usernode = isUserNode();
+        int[] result;
+        int errorCode = 0;
+        File lockFile = (usernode ? userLockFile : systemLockFile);
+        long sleepTime = INIT_SLEEP_TIME;
+        for (int i = 0; i < MAX_ATTEMPTS; i++) {
+            try {
+                  int perm = (usernode? USER_READ_WRITE: USER_RW_ALL_READ);
+                  result = lockFile0(lockFile.getCanonicalPath(), perm, shared);
+
+                  errorCode = result[ERROR_CODE];
+                  if (result[LOCK_HANDLE] != 0) {
+                     if (usernode) {
+                         userRootLockHandle = result[LOCK_HANDLE];
+                     } else {
+                         systemRootLockHandle = result[LOCK_HANDLE];
+                     }
+                     return true;
+                  }
+            } catch(IOException e) {
+//                // If at first, you don't succeed...
+            }
+
+            try {
+                Thread.sleep(sleepTime);
+            } catch(InterruptedException e) {
+                checkLockFile0ErrorCode(errorCode);
+                return false;
+            }
+            sleepTime *= 2;
+        }
+        checkLockFile0ErrorCode(errorCode);
+        return false;
+    }
+
+    /**
+     * Checks if unlockFile0() returned an error. Throws a SecurityException,
+     * if access denied. Logs a warning otherwise.
+     */
+    private void checkLockFile0ErrorCode (int errorCode)
+                                                      throws SecurityException {
+        if (errorCode == EACCES)
+            throw new SecurityException("Could not lock " +
+            (isUserNode()? "User prefs." : "System prefs.") +
+             " Lock file access denied.");
+        if (errorCode != EAGAIN)
+            getLogger().warning("Could not lock " +
+                             (isUserNode()? "User prefs. " : "System prefs.") +
+                             " Unix error code " + errorCode + ".");
+    }
+
+    /**
+     * Locks file using UNIX file locking.
+     * @param fileName Absolute file name of the lock file.
+     * @return Returns a lock handle, used to unlock the file.
+     */
+    private static native int[]
+            lockFile0(String fileName, int permission, boolean shared);
+
+    /**
+     * Unlocks file previously locked by lockFile0().
+     * @param lockHandle Handle to the file lock.
+     * @return Returns zero if OK, UNIX error code if failure.
+     */
+    private  static native int unlockFile0(int lockHandle);
+
+    /**
+     * Changes UNIX file permissions.
+     */
+    private static native int chmod(String fileName, int permission);
+
+    /**
+     * Initial time between lock attempts, in ms.  The time is doubled
+     * after each failing attempt (except the first).
+     */
+    private static int INIT_SLEEP_TIME = 50;
+
+    /**
+     * Maximum number of lock attempts.
+     */
+    private static int MAX_ATTEMPTS = 5;
+
+    /**
+     * Release the the appropriate file lock (user or system).
+     * @throws SecurityException if file access denied.
+     */
+    private void unlockFile() {
+        int result;
+        boolean usernode = isUserNode();
+        File lockFile = (usernode ? userLockFile : systemLockFile);
+        int lockHandle = ( usernode ? userRootLockHandle:systemRootLockHandle);
+        if (lockHandle == 0) {
+            getLogger().warning("Unlock: zero lockHandle for " +
+                           (usernode ? "user":"system") + " preferences.)");
+            return;
+        }
+        result = unlockFile0(lockHandle);
+        if (result != 0) {
+            getLogger().warning("Could not drop file-lock on " +
+            (isUserNode() ? "user" : "system") + " preferences." +
+            " Unix error code " + result + ".");
+            if (result == EACCES)
+                throw new SecurityException("Could not unlock" +
+                (isUserNode()? "User prefs." : "System prefs.") +
+                " Lock file access denied.");
+        }
+        if (isUserNode()) {
+            userRootLockHandle = 0;
+        } else {
+            systemRootLockHandle = 0;
+        }
+    }
+}
diff --git a/java/util/prefs/FileSystemPreferencesFactory.java b/java/util/prefs/FileSystemPreferencesFactory.java
new file mode 100644
index 0000000..bd1a723
--- /dev/null
+++ b/java/util/prefs/FileSystemPreferencesFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * Factory for FileSystemPreferences.  This class allows FileSystemPreferences
+ * to be installed as the Preferences implementations via the
+ * java.util.prefs.PreferencesFactory system property.
+ *
+ * @author  Josh Bloch
+ * @see     FileSystemPreferences
+ * @see     Preferences
+ * @since   1.4
+ */
+
+class FileSystemPreferencesFactory implements PreferencesFactory {
+    public Preferences userRoot() {
+        return FileSystemPreferences.getUserRoot();
+    }
+
+    public Preferences systemRoot() {
+        return FileSystemPreferences.getSystemRoot();
+    }
+}
diff --git a/java/util/prefs/InvalidPreferencesFormatException.java b/java/util/prefs/InvalidPreferencesFormatException.java
new file mode 100644
index 0000000..3a5e817
--- /dev/null
+++ b/java/util/prefs/InvalidPreferencesFormatException.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * Thrown to indicate that an operation could not complete because
+ * the input did not conform to the appropriate XML document type
+ * for a collection of preferences, as per the {@link Preferences}
+ * specification.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+public class InvalidPreferencesFormatException extends Exception {
+    /**
+     * Constructs an InvalidPreferencesFormatException with the specified
+     * cause.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).
+     */
+    public InvalidPreferencesFormatException(Throwable cause) {
+        super(cause);
+    }
+
+   /**
+    * Constructs an InvalidPreferencesFormatException with the specified
+    * detail message.
+    *
+    * @param   message   the detail message. The detail message is saved for
+    *          later retrieval by the {@link Throwable#getMessage()} method.
+    */
+    public InvalidPreferencesFormatException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an InvalidPreferencesFormatException with the specified
+     * detail message and cause.
+     *
+     * @param  message   the detail message. The detail message is saved for
+     *         later retrieval by the {@link Throwable#getMessage()} method.
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).
+     */
+    public InvalidPreferencesFormatException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    private static final long serialVersionUID = -791715184232119669L;
+}
diff --git a/java/util/prefs/NodeChangeEvent.java b/java/util/prefs/NodeChangeEvent.java
new file mode 100644
index 0000000..f108925
--- /dev/null
+++ b/java/util/prefs/NodeChangeEvent.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * An event emitted by a <tt>Preferences</tt> node to indicate that
+ * a child of that node has been added or removed.<p>
+ *
+ * Note, that although NodeChangeEvent inherits Serializable interface from
+ * java.util.EventObject, it is not intended to be Serializable. Appropriate
+ * serialization methods are implemented to throw NotSerializableException.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @see     NodeChangeListener
+ * @see     PreferenceChangeEvent
+ * @since   1.4
+ * @serial  exclude
+ */
+
+public class NodeChangeEvent extends java.util.EventObject {
+    /**
+     * The node that was added or removed.
+     *
+     * @serial
+     */
+    private Preferences child;
+
+    /**
+     * Constructs a new <code>NodeChangeEvent</code> instance.
+     *
+     * @param parent  The parent of the node that was added or removed.
+     * @param child   The node that was added or removed.
+     */
+    public NodeChangeEvent(Preferences parent, Preferences child) {
+        super(parent);
+        this.child = child;
+    }
+
+    /**
+     * Returns the parent of the node that was added or removed.
+     *
+     * @return  The parent Preferences node whose child was added or removed
+     */
+    public Preferences getParent() {
+        return (Preferences) getSource();
+    }
+
+    /**
+     * Returns the node that was added or removed.
+     *
+     * @return  The node that was added or removed.
+     */
+    public Preferences getChild() {
+        return child;
+    }
+
+    /**
+     * Throws NotSerializableException, since NodeChangeEvent objects are not
+     * intended to be serializable.
+     */
+     private void writeObject(java.io.ObjectOutputStream out)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    /**
+     * Throws NotSerializableException, since NodeChangeEvent objects are not
+     * intended to be serializable.
+     */
+     private void readObject(java.io.ObjectInputStream in)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    // Defined so that this class isn't flagged as a potential problem when
+    // searches for missing serialVersionUID fields are done.
+    private static final long serialVersionUID = 8068949086596572957L;
+}
diff --git a/java/util/prefs/NodeChangeListener.java b/java/util/prefs/NodeChangeListener.java
new file mode 100644
index 0000000..f343764
--- /dev/null
+++ b/java/util/prefs/NodeChangeListener.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * A listener for receiving preference node change events.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @see     NodeChangeEvent
+ * @see     PreferenceChangeListener
+ * @since   1.4
+ */
+
+public interface NodeChangeListener extends java.util.EventListener {
+    /**
+     * This method gets called when a child node is added.
+     *
+     * @param evt A node change event object describing the parent
+     *            and child node.
+     */
+    void childAdded(NodeChangeEvent evt);
+
+    /**
+     * This method gets called when a child node is removed.
+     *
+     * @param evt A node change event object describing the parent
+     *            and child node.
+     */
+    void childRemoved(NodeChangeEvent evt);
+}
diff --git a/java/util/prefs/PreferenceChangeEvent.java b/java/util/prefs/PreferenceChangeEvent.java
new file mode 100644
index 0000000..f7cf7b5
--- /dev/null
+++ b/java/util/prefs/PreferenceChangeEvent.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * An event emitted by a <tt>Preferences</tt> node to indicate that
+ * a preference has been added, removed or has had its value changed.<p>
+ *
+ * Note, that although PreferenceChangeEvent inherits Serializable interface
+ * from EventObject, it is not intended to be Serializable. Appropriate
+ * serialization methods are implemented to throw NotSerializableException.
+ *
+ * @author  Josh Bloch
+ * @see Preferences
+ * @see PreferenceChangeListener
+ * @see NodeChangeEvent
+ * @since   1.4
+ * @serial exclude
+ */
+public class PreferenceChangeEvent extends java.util.EventObject {
+
+    /**
+     * Key of the preference that changed.
+     *
+     * @serial
+     */
+    private String key;
+
+    /**
+     * New value for preference, or <tt>null</tt> if it was removed.
+     *
+     * @serial
+     */
+    private String newValue;
+
+    /**
+     * Constructs a new <code>PreferenceChangeEvent</code> instance.
+     *
+     * @param node  The Preferences node that emitted the event.
+     * @param key  The key of the preference that was changed.
+     * @param newValue  The new value of the preference, or <tt>null</tt>
+     *                  if the preference is being removed.
+     */
+    public PreferenceChangeEvent(Preferences node, String key,
+                                 String newValue) {
+        super(node);
+        this.key = key;
+        this.newValue = newValue;
+    }
+
+    /**
+     * Returns the preference node that emitted the event.
+     *
+     * @return  The preference node that emitted the event.
+     */
+    public Preferences getNode() {
+        return (Preferences) getSource();
+    }
+
+    /**
+     * Returns the key of the preference that was changed.
+     *
+     * @return  The key of the preference that was changed.
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * Returns the new value for the preference.
+     *
+     * @return  The new value for the preference, or <tt>null</tt> if the
+     *          preference was removed.
+     */
+    public String getNewValue() {
+        return newValue;
+    }
+
+    /**
+     * Throws NotSerializableException, since NodeChangeEvent objects
+     * are not intended to be serializable.
+     */
+     private void writeObject(java.io.ObjectOutputStream out)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    /**
+     * Throws NotSerializableException, since PreferenceChangeEvent objects
+     * are not intended to be serializable.
+     */
+     private void readObject(java.io.ObjectInputStream in)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    // Defined so that this class isn't flagged as a potential problem when
+    // searches for missing serialVersionUID fields are done.
+    private static final long serialVersionUID = 793724513368024975L;
+}
diff --git a/java/util/prefs/PreferenceChangeListener.java b/java/util/prefs/PreferenceChangeListener.java
new file mode 100644
index 0000000..0fb96c5
--- /dev/null
+++ b/java/util/prefs/PreferenceChangeListener.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * A listener for receiving preference change events.
+ *
+ * @author  Josh Bloch
+ * @see Preferences
+ * @see PreferenceChangeEvent
+ * @see NodeChangeListener
+ * @since   1.4
+ */
+@FunctionalInterface
+public interface PreferenceChangeListener extends java.util.EventListener {
+    /**
+     * This method gets called when a preference is added, removed or when
+     * its value is changed.
+     * <p>
+     * @param evt A PreferenceChangeEvent object describing the event source
+     *          and the preference that has changed.
+     */
+    void preferenceChange(PreferenceChangeEvent evt);
+}
diff --git a/java/util/prefs/Preferences.java b/java/util/prefs/Preferences.java
new file mode 100644
index 0000000..c643fc2
--- /dev/null
+++ b/java/util/prefs/Preferences.java
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.util.ServiceConfigurationError;
+
+// These imports needed only as a workaround for a JavaDoc bug
+import java.lang.RuntimePermission;
+import java.lang.Integer;
+import java.lang.Long;
+import java.lang.Float;
+import java.lang.Double;
+
+/**
+ * A node in a hierarchical collection of preference data.  This class
+ * allows applications to store and retrieve user and system
+ * preference and configuration data.  This data is stored
+ * persistently in an implementation-dependent backing store.  Typical
+ * implementations include flat files, OS-specific registries,
+ * directory servers and SQL databases.  The user of this class needn't
+ * be concerned with details of the backing store.
+ *
+ * <p>There are two separate trees of preference nodes, one for user
+ * preferences and one for system preferences.  Each user has a separate user
+ * preference tree, and all users in a given system share the same system
+ * preference tree.  The precise description of "user" and "system" will vary
+ * from implementation to implementation.  Typical information stored in the
+ * user preference tree might include font choice, color choice, or preferred
+ * window location and size for a particular application.  Typical information
+ * stored in the system preference tree might include installation
+ * configuration data for an application.
+ *
+ * <p>Nodes in a preference tree are named in a similar fashion to
+ * directories in a hierarchical file system.   Every node in a preference
+ * tree has a <i>node name</i> (which is not necessarily unique),
+ * a unique <i>absolute path name</i>, and a path name <i>relative</i> to each
+ * ancestor including itself.
+ *
+ * <p>The root node has a node name of the empty string ("").  Every other
+ * node has an arbitrary node name, specified at the time it is created.  The
+ * only restrictions on this name are that it cannot be the empty string, and
+ * it cannot contain the slash character ('/').
+ *
+ * <p>The root node has an absolute path name of <tt>"/"</tt>.  Children of
+ * the root node have absolute path names of <tt>"/" + </tt><i>&lt;node
+ * name&gt;</i>.  All other nodes have absolute path names of <i>&lt;parent's
+ * absolute path name&gt;</i><tt> + "/" + </tt><i>&lt;node name&gt;</i>.
+ * Note that all absolute path names begin with the slash character.
+ *
+ * <p>A node <i>n</i>'s path name relative to its ancestor <i>a</i>
+ * is simply the string that must be appended to <i>a</i>'s absolute path name
+ * in order to form <i>n</i>'s absolute path name, with the initial slash
+ * character (if present) removed.  Note that:
+ * <ul>
+ * <li>No relative path names begin with the slash character.
+ * <li>Every node's path name relative to itself is the empty string.
+ * <li>Every node's path name relative to its parent is its node name (except
+ * for the root node, which does not have a parent).
+ * <li>Every node's path name relative to the root is its absolute path name
+ * with the initial slash character removed.
+ * </ul>
+ *
+ * <p>Note finally that:
+ * <ul>
+ * <li>No path name contains multiple consecutive slash characters.
+ * <li>No path name with the exception of the root's absolute path name
+ * ends in the slash character.
+ * <li>Any string that conforms to these two rules is a valid path name.
+ * </ul>
+ *
+ * <p>All of the methods that modify preferences data are permitted to operate
+ * asynchronously; they may return immediately, and changes will eventually
+ * propagate to the persistent backing store with an implementation-dependent
+ * delay.  The <tt>flush</tt> method may be used to synchronously force
+ * updates to the backing store.  Normal termination of the Java Virtual
+ * Machine will <i>not</i> result in the loss of pending updates -- an explicit
+ * <tt>flush</tt> invocation is <i>not</i> required upon termination to ensure
+ * that pending updates are made persistent.
+ *
+ * <p>All of the methods that read preferences from a <tt>Preferences</tt>
+ * object require the invoker to provide a default value.  The default value is
+ * returned if no value has been previously set <i>or if the backing store is
+ * unavailable</i>.  The intent is to allow applications to operate, albeit
+ * with slightly degraded functionality, even if the backing store becomes
+ * unavailable.  Several methods, like <tt>flush</tt>, have semantics that
+ * prevent them from operating if the backing store is unavailable.  Ordinary
+ * applications should have no need to invoke any of these methods, which can
+ * be identified by the fact that they are declared to throw {@link
+ * BackingStoreException}.
+ *
+ * <p>The methods in this class may be invoked concurrently by multiple threads
+ * in a single JVM without the need for external synchronization, and the
+ * results will be equivalent to some serial execution.  If this class is used
+ * concurrently <i>by multiple JVMs</i> that store their preference data in
+ * the same backing store, the data store will not be corrupted, but no
+ * other guarantees are made concerning the consistency of the preference
+ * data.
+ *
+ * <p>This class contains an export/import facility, allowing preferences
+ * to be "exported" to an XML document, and XML documents representing
+ * preferences to be "imported" back into the system.  This facility
+ * may be used to back up all or part of a preference tree, and
+ * subsequently restore from the backup.
+ *
+ * <p>The XML document has the following DOCTYPE declaration:
+ * <pre>{@code
+ * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+ * }</pre>
+ * Note that the system URI (http://java.sun.com/dtd/preferences.dtd) is
+ * <i>not</i> accessed when exporting or importing preferences; it merely
+ * serves as a string to uniquely identify the DTD, which is:
+ * <pre>{@code
+ *    <?xml version="1.0" encoding="UTF-8"?>
+ *
+ *    <!-- DTD for a Preferences tree. -->
+ *
+ *    <!-- The preferences element is at the root of an XML document
+ *         representing a Preferences tree. -->
+ *    <!ELEMENT preferences (root)>
+ *
+ *    <!-- The preferences element contains an optional version attribute,
+ *          which specifies version of DTD. -->
+ *    <!ATTLIST preferences EXTERNAL_XML_VERSION CDATA "0.0" >
+ *
+ *    <!-- The root element has a map representing the root's preferences
+ *         (if any), and one node for each child of the root (if any). -->
+ *    <!ELEMENT root (map, node*) >
+ *
+ *    <!-- Additionally, the root contains a type attribute, which
+ *         specifies whether it's the system or user root. -->
+ *    <!ATTLIST root
+ *              type (system|user) #REQUIRED >
+ *
+ *    <!-- Each node has a map representing its preferences (if any),
+ *         and one node for each child (if any). -->
+ *    <!ELEMENT node (map, node*) >
+ *
+ *    <!-- Additionally, each node has a name attribute -->
+ *    <!ATTLIST node
+ *              name CDATA #REQUIRED >
+ *
+ *    <!-- A map represents the preferences stored at a node (if any). -->
+ *    <!ELEMENT map (entry*) >
+ *
+ *    <!-- An entry represents a single preference, which is simply
+ *          a key-value pair. -->
+ *    <!ELEMENT entry EMPTY >
+ *    <!ATTLIST entry
+ *              key   CDATA #REQUIRED
+ *              value CDATA #REQUIRED >
+ * }</pre>
+ *
+ * Every <tt>Preferences</tt> implementation must have an associated {@link
+ * PreferencesFactory} implementation.  Every Java(TM) SE implementation must provide
+ * some means of specifying which <tt>PreferencesFactory</tt> implementation
+ * is used to generate the root preferences nodes.  This allows the
+ * administrator to replace the default preferences implementation with an
+ * alternative implementation.
+ *
+ * <p>Implementation note: In Sun's JRE, the <tt>PreferencesFactory</tt>
+ * implementation is located as follows:
+ *
+ * <ol>
+ *
+ * <li><p>If the system property
+ * <tt>java.util.prefs.PreferencesFactory</tt> is defined, then it is
+ * taken to be the fully-qualified name of a class implementing the
+ * <tt>PreferencesFactory</tt> interface.  The class is loaded and
+ * instantiated; if this process fails then an unspecified error is
+ * thrown.</p></li>
+ *
+ * <li><p> If a <tt>PreferencesFactory</tt> implementation class file
+ * has been installed in a jar file that is visible to the
+ * {@link java.lang.ClassLoader#getSystemClassLoader system class loader},
+ * and that jar file contains a provider-configuration file named
+ * <tt>java.util.prefs.PreferencesFactory</tt> in the resource
+ * directory <tt>META-INF/services</tt>, then the first class name
+ * specified in that file is taken.  If more than one such jar file is
+ * provided, the first one found will be used.  The class is loaded
+ * and instantiated; if this process fails then an unspecified error
+ * is thrown.  </p></li>
+ *
+ * <li><p>Finally, if neither the above-mentioned system property nor
+ * an extension jar file is provided, then the system-wide default
+ * <tt>PreferencesFactory</tt> implementation for the underlying
+ * platform is loaded and instantiated.</p></li>
+ *
+ * </ol>
+ *
+ * @author  Josh Bloch
+ * @since   1.4
+ */
+public abstract class Preferences {
+
+    // Android-changed: Allow Preferences.factory to be set by tests.
+    // private static final PreferencesFactory factory = factory();
+    private static PreferencesFactory factory = factory();
+
+    // BEGIN Android-changed: Logic for constructing the default Preferences factory.
+    /*
+    private static PreferencesFactory factory() {
+        // 1. Try user-specified system property
+        String factoryName = AccessController.doPrivileged(
+            new PrivilegedAction<String>() {
+                public String run() {
+                    return System.getProperty(
+                        "java.util.prefs.PreferencesFactory");}});
+        if (factoryName != null) {
+            // FIXME: This code should be run in a doPrivileged and
+            // not use the context classloader, to avoid being
+            // dependent on the invoking thread.
+            // Checking AllPermission also seems wrong.
+            try {
+                return (PreferencesFactory)
+                    Class.forName(factoryName, false,
+                                  ClassLoader.getSystemClassLoader())
+                    .newInstance();
+            } catch (Exception ex) {
+                try {
+                    // workaround for javaws, plugin,
+                    // load factory class using non-system classloader
+                    SecurityManager sm = System.getSecurityManager();
+                    if (sm != null) {
+                        sm.checkPermission(new java.security.AllPermission());
+                    }
+                    return (PreferencesFactory)
+                        Class.forName(factoryName, false,
+                                      Thread.currentThread()
+                                      .getContextClassLoader())
+                        .newInstance();
+                } catch (Exception e) {
+                    throw new InternalError(
+                        "Can't instantiate Preferences factory "
+                        + factoryName, e);
+                }
+            }
+        }
+
+        return AccessController.doPrivileged(
+            new PrivilegedAction<PreferencesFactory>() {
+                public PreferencesFactory run() {
+                    return factory1();}});
+    }
+
+    private static PreferencesFactory factory1() {
+        // 2. Try service provider interface
+        Iterator<PreferencesFactory> itr = ServiceLoader
+            .load(PreferencesFactory.class, ClassLoader.getSystemClassLoader())
+            .iterator();
+
+        // choose first provider instance
+        while (itr.hasNext()) {
+            try {
+                return itr.next();
+            } catch (ServiceConfigurationError sce) {
+                if (sce.getCause() instanceof SecurityException) {
+                    // Ignore the security exception, try the next provider
+                    continue;
+                }
+                throw sce;
+            }
+        }
+
+        // 3. Use platform-specific system-wide default
+        String osName = System.getProperty("os.name");
+        String platformFactory;
+        if (osName.startsWith("Windows")) {
+            platformFactory = "java.util.prefs.WindowsPreferencesFactory";
+        } else if (osName.contains("OS X")) {
+            platformFactory = "java.util.prefs.MacOSXPreferencesFactory";
+        } else {
+            platformFactory = "java.util.prefs.FileSystemPreferencesFactory";
+        }
+        try {
+            return (PreferencesFactory)
+                Class.forName(platformFactory, false,
+                              Preferences.class.getClassLoader()).newInstance();
+        } catch (Exception e) {
+            throw new InternalError(
+                "Can't instantiate platform default Preferences factory "
+                + platformFactory, e);
+        }
+    }
+    */
+    private static PreferencesFactory factory() {
+        // Try the system property first...
+        PreferencesFactory result = ServiceLoader.loadFromSystemProperty(PreferencesFactory.class);
+        if (result != null) {
+            return result;
+        }
+        // Then use ServiceLoader for META-INF/services/...
+        for (PreferencesFactory impl : ServiceLoader.load(PreferencesFactory.class)) {
+            return impl;
+        }
+        // Finally return a default...
+        return new FileSystemPreferencesFactory();
+    }
+    // END Android-changed: Logic for constructing the default Preferences factory.
+
+    // BEGIN Android-added: Allow Preferences.factory to be set by tests.
+    /** @hide for testing only. */
+    public static PreferencesFactory setPreferencesFactory(PreferencesFactory pf) {
+        PreferencesFactory previous = factory;
+        factory = pf;
+        return previous;
+    }
+    // END Android-added: Allow Preferences.factory to be set by tests.
+
+    /**
+     * Maximum length of string allowed as a key (80 characters).
+     */
+    public static final int MAX_KEY_LENGTH = 80;
+
+    /**
+     * Maximum length of string allowed as a value (8192 characters).
+     */
+    public static final int MAX_VALUE_LENGTH = 8*1024;
+
+    /**
+     * Maximum length of a node name (80 characters).
+     */
+    public static final int MAX_NAME_LENGTH = 80;
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the preference node from the calling user's preference tree
+     * that is associated (by convention) with the specified class's package.
+     * The convention is as follows: the absolute path name of the node is the
+     * fully qualified package name, preceded by a slash (<tt>'/'</tt>), and
+     * with each period (<tt>'.'</tt>) replaced by a slash.  For example the
+     * absolute path name of the node associated with the class
+     * <tt>com.acme.widget.Foo</tt> is <tt>/com/acme/widget</tt>.
+     *
+     * <p>This convention does not apply to the unnamed package, whose
+     * associated preference node is <tt>&lt;unnamed&gt;</tt>.  This node
+     * is not intended for long term use, but for convenience in the early
+     * development of programs that do not yet belong to a package, and
+     * for "throwaway" programs.  <i>Valuable data should not be stored
+     * at this node as it is shared by all programs that use it.</i>
+     *
+     * <p>A class <tt>Foo</tt> wishing to access preferences pertaining to its
+     * package can obtain a preference node as follows: <pre>
+     *    static Preferences prefs = Preferences.userNodeForPackage(Foo.class);
+     * </pre>
+     * This idiom obviates the need for using a string to describe the
+     * preferences node and decreases the likelihood of a run-time failure.
+     * (If the class name is misspelled, it will typically result in a
+     * compile-time error.)
+     *
+     * <p>Invoking this method will result in the creation of the returned
+     * node and its ancestors if they do not already exist.  If the returned
+     * node did not exist prior to this call, this node and any ancestors that
+     * were created by this call are not guaranteed to become permanent until
+     * the <tt>flush</tt> method is called on the returned node (or one of its
+     * ancestors or descendants).
+     *
+     * @param c the class for whose package a user preference node is desired.
+     * @return the user preference node associated with the package of which
+     *         <tt>c</tt> is a member.
+     * @throws NullPointerException if <tt>c</tt> is <tt>null</tt>.
+     * @throws SecurityException if a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences userNodeForPackage(Class<?> c) {
+        return userRoot().node(nodeName(c));
+    }
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the preference node from the system preference tree that is
+     * associated (by convention) with the specified class's package.  The
+     * convention is as follows: the absolute path name of the node is the
+     * fully qualified package name, preceded by a slash (<tt>'/'</tt>), and
+     * with each period (<tt>'.'</tt>) replaced by a slash.  For example the
+     * absolute path name of the node associated with the class
+     * <tt>com.acme.widget.Foo</tt> is <tt>/com/acme/widget</tt>.
+     *
+     * <p>This convention does not apply to the unnamed package, whose
+     * associated preference node is <tt>&lt;unnamed&gt;</tt>.  This node
+     * is not intended for long term use, but for convenience in the early
+     * development of programs that do not yet belong to a package, and
+     * for "throwaway" programs.  <i>Valuable data should not be stored
+     * at this node as it is shared by all programs that use it.</i>
+     *
+     * <p>A class <tt>Foo</tt> wishing to access preferences pertaining to its
+     * package can obtain a preference node as follows: <pre>
+     *  static Preferences prefs = Preferences.systemNodeForPackage(Foo.class);
+     * </pre>
+     * This idiom obviates the need for using a string to describe the
+     * preferences node and decreases the likelihood of a run-time failure.
+     * (If the class name is misspelled, it will typically result in a
+     * compile-time error.)
+     *
+     * <p>Invoking this method will result in the creation of the returned
+     * node and its ancestors if they do not already exist.  If the returned
+     * node did not exist prior to this call, this node and any ancestors that
+     * were created by this call are not guaranteed to become permanent until
+     * the <tt>flush</tt> method is called on the returned node (or one of its
+     * ancestors or descendants).
+     *
+     * @param c the class for whose package a system preference node is desired.
+     * @return the system preference node associated with the package of which
+     *         <tt>c</tt> is a member.
+     * @throws NullPointerException if <tt>c</tt> is <tt>null</tt>.
+     * @throws SecurityException if a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences systemNodeForPackage(Class<?> c) {
+        return systemRoot().node(nodeName(c));
+    }
+
+    /**
+     * Returns the absolute path name of the node corresponding to the package
+     * of the specified object.
+     *
+     * @throws IllegalArgumentException if the package has node preferences
+     *         node associated with it.
+     */
+    private static String nodeName(Class<?> c) {
+        if (c.isArray())
+            throw new IllegalArgumentException(
+                "Arrays have no associated preferences node.");
+        String className = c.getName();
+        int pkgEndIndex = className.lastIndexOf('.');
+        if (pkgEndIndex < 0)
+            return "/<unnamed>";
+        String packageName = className.substring(0, pkgEndIndex);
+        return "/" + packageName.replace('.', '/');
+    }
+
+    /**
+     * This permission object represents the permission required to get
+     * access to the user or system root (which in turn allows for all
+     * other operations).
+     */
+    private static Permission prefsPerm = new RuntimePermission("preferences");
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the root preference node for the calling user.
+     *
+     * @return the root preference node for the calling user.
+     * @throws SecurityException If a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences userRoot() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(prefsPerm);
+
+        return factory.userRoot();
+    }
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the root preference node for the system.
+     *
+     * @return the root preference node for the system.
+     * @throws SecurityException If a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences systemRoot() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(prefsPerm);
+
+        return factory.systemRoot();
+    }
+
+    /**
+     * Sole constructor. (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected Preferences() {
+    }
+
+    /**
+     * Associates the specified value with the specified key in this
+     * preference node.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *       <tt>MAX_KEY_LENGTH</tt> or if <tt>value.length</tt> exceeds
+     *       <tt>MAX_VALUE_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract void put(String key, String value);
+
+    /**
+     * Returns the value associated with the specified key in this preference
+     * node.  Returns the specified default if there is no value associated
+     * with the key, or the backing store is inaccessible.
+     *
+     * <p>Some implementations may store default values in their backing
+     * stores.  If there is no value associated with the specified key
+     * but there is such a <i>stored default</i>, it is returned in
+     * preference to the specified default.
+     *
+     * @param key key whose associated value is to be returned.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>.
+     * @return the value associated with <tt>key</tt>, or <tt>def</tt>
+     *         if no value is associated with <tt>key</tt>, or the backing
+     *         store is inaccessible.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.  (A
+     *         <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
+     */
+    public abstract String get(String key, String def);
+
+    /**
+     * Removes the value associated with the specified key in this preference
+     * node, if any.
+     *
+     * <p>If this implementation supports <i>stored defaults</i>, and there is
+     * such a default for the specified preference, the stored default will be
+     * "exposed" by this call, in the sense that it will be returned
+     * by a succeeding call to <tt>get</tt>.
+     *
+     * @param key key whose mapping is to be removed from the preference node.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract void remove(String key);
+
+    /**
+     * Removes all of the preferences (key-value associations) in this
+     * preference node.  This call has no effect on any descendants
+     * of this node.
+     *
+     * <p>If this implementation supports <i>stored defaults</i>, and this
+     * node in the preferences hierarchy contains any such defaults,
+     * the stored defaults will be "exposed" by this call, in the sense that
+     * they will be returned by succeeding calls to <tt>get</tt>.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #removeNode()
+     */
+    public abstract void clear() throws BackingStoreException;
+
+    /**
+     * Associates a string representing the specified int value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the int value were passed to
+     * {@link Integer#toString(int)}.  This method is intended for use in
+     * conjunction with {@link #getInt}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getInt(String,int)
+     */
+    public abstract void putInt(String key, int value);
+
+    /**
+     * Returns the int value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to
+     * an integer as by {@link Integer#parseInt(String)}.  Returns the
+     * specified default if there is no value associated with the key,
+     * the backing store is inaccessible, or if
+     * <tt>Integer.parseInt(String)</tt> would throw a {@link
+     * NumberFormatException} if the associated value were passed.  This
+     * method is intended for use in conjunction with {@link #putInt}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to an int
+     * with <tt>Integer.parseInt</tt>, this int is returned in preference to
+     * the specified default.
+     *
+     * @param key key whose associated value is to be returned as an int.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as an int,
+     *        or the backing store is inaccessible.
+     * @return the int value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         an int.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putInt(String,int)
+     * @see #get(String,String)
+     */
+    public abstract int getInt(String key, int def);
+
+    /**
+     * Associates a string representing the specified long value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the long value were passed to
+     * {@link Long#toString(long)}.  This method is intended for use in
+     * conjunction with {@link #getLong}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getLong(String,long)
+     */
+    public abstract void putLong(String key, long value);
+
+    /**
+     * Returns the long value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to
+     * a long as by {@link Long#parseLong(String)}.  Returns the
+     * specified default if there is no value associated with the key,
+     * the backing store is inaccessible, or if
+     * <tt>Long.parseLong(String)</tt> would throw a {@link
+     * NumberFormatException} if the associated value were passed.  This
+     * method is intended for use in conjunction with {@link #putLong}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to a long
+     * with <tt>Long.parseLong</tt>, this long is returned in preference to
+     * the specified default.
+     *
+     * @param key key whose associated value is to be returned as a long.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a long,
+     *        or the backing store is inaccessible.
+     * @return the long value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a long.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putLong(String,long)
+     * @see #get(String,String)
+     */
+    public abstract long getLong(String key, long def);
+
+    /**
+     * Associates a string representing the specified boolean value with the
+     * specified key in this preference node.  The associated string is
+     * <tt>"true"</tt> if the value is true, and <tt>"false"</tt> if it is
+     * false.  This method is intended for use in conjunction with
+     * {@link #getBoolean}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getBoolean(String,boolean)
+     * @see #get(String,String)
+     */
+    public abstract void putBoolean(String key, boolean value);
+
+    /**
+     * Returns the boolean value represented by the string associated with the
+     * specified key in this preference node.  Valid strings
+     * are <tt>"true"</tt>, which represents true, and <tt>"false"</tt>, which
+     * represents false.  Case is ignored, so, for example, <tt>"TRUE"</tt>
+     * and <tt>"False"</tt> are also valid.  This method is intended for use in
+     * conjunction with {@link #putBoolean}.
+     *
+     * <p>Returns the specified default if there is no value
+     * associated with the key, the backing store is inaccessible, or if the
+     * associated value is something other than <tt>"true"</tt> or
+     * <tt>"false"</tt>, ignoring case.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists and is accessible, it is used in preference to the
+     * specified default, unless the stored default is something other than
+     * <tt>"true"</tt> or <tt>"false"</tt>, ignoring case, in which case the
+     * specified default is used.
+     *
+     * @param key key whose associated value is to be returned as a boolean.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a boolean,
+     *        or the backing store is inaccessible.
+     * @return the boolean value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a boolean.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #get(String,String)
+     * @see #putBoolean(String,boolean)
+     */
+    public abstract boolean getBoolean(String key, boolean def);
+
+    /**
+     * Associates a string representing the specified float value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the float value were passed to
+     * {@link Float#toString(float)}.  This method is intended for use in
+     * conjunction with {@link #getFloat}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getFloat(String,float)
+     */
+    public abstract void putFloat(String key, float value);
+
+    /**
+     * Returns the float value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to an
+     * integer as by {@link Float#parseFloat(String)}.  Returns the specified
+     * default if there is no value associated with the key, the backing store
+     * is inaccessible, or if <tt>Float.parseFloat(String)</tt> would throw a
+     * {@link NumberFormatException} if the associated value were passed.
+     * This method is intended for use in conjunction with {@link #putFloat}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to a float
+     * with <tt>Float.parseFloat</tt>, this float is returned in preference to
+     * the specified default.
+     *
+     * @param key key whose associated value is to be returned as a float.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a float,
+     *        or the backing store is inaccessible.
+     * @return the float value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a float.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putFloat(String,float)
+     * @see #get(String,String)
+     */
+    public abstract float getFloat(String key, float def);
+
+    /**
+     * Associates a string representing the specified double value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the double value were passed to
+     * {@link Double#toString(double)}.  This method is intended for use in
+     * conjunction with {@link #getDouble}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getDouble(String,double)
+     */
+    public abstract void putDouble(String key, double value);
+
+    /**
+     * Returns the double value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to an
+     * integer as by {@link Double#parseDouble(String)}.  Returns the specified
+     * default if there is no value associated with the key, the backing store
+     * is inaccessible, or if <tt>Double.parseDouble(String)</tt> would throw a
+     * {@link NumberFormatException} if the associated value were passed.
+     * This method is intended for use in conjunction with {@link #putDouble}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to a double
+     * with <tt>Double.parseDouble</tt>, this double is returned in preference
+     * to the specified default.
+     *
+     * @param key key whose associated value is to be returned as a double.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a double,
+     *        or the backing store is inaccessible.
+     * @return the double value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a double.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putDouble(String,double)
+     * @see #get(String,String)
+     */
+    public abstract double getDouble(String key, double def);
+
+    /**
+     * Associates a string representing the specified byte array with the
+     * specified key in this preference node.  The associated string is
+     * the <i>Base64</i> encoding of the byte array, as defined in <a
+     * href=http://www.ietf.org/rfc/rfc2045.txt>RFC 2045</a>, Section 6.8,
+     * with one minor change: the string will consist solely of characters
+     * from the <i>Base64 Alphabet</i>; it will not contain any newline
+     * characters.  Note that the maximum length of the byte array is limited
+     * to three quarters of <tt>MAX_VALUE_LENGTH</tt> so that the length
+     * of the Base64 encoded String does not exceed <tt>MAX_VALUE_LENGTH</tt>.
+     * This method is intended for use in conjunction with
+     * {@link #getByteArray}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if key.length() exceeds MAX_KEY_LENGTH
+     *         or if value.length exceeds MAX_VALUE_LENGTH*3/4.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getByteArray(String,byte[])
+     * @see #get(String,String)
+     */
+    public abstract void putByteArray(String key, byte[] value);
+
+    /**
+     * Returns the byte array value represented by the string associated with
+     * the specified key in this preference node.  Valid strings are
+     * <i>Base64</i> encoded binary data, as defined in <a
+     * href=http://www.ietf.org/rfc/rfc2045.txt>RFC 2045</a>, Section 6.8,
+     * with one minor change: the string must consist solely of characters
+     * from the <i>Base64 Alphabet</i>; no newline characters or
+     * extraneous characters are permitted.  This method is intended for use
+     * in conjunction with {@link #putByteArray}.
+     *
+     * <p>Returns the specified default if there is no value
+     * associated with the key, the backing store is inaccessible, or if the
+     * associated value is not a valid Base64 encoded byte array
+     * (as defined above).
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists and is accessible, it is used in preference to the
+     * specified default, unless the stored default is not a valid Base64
+     * encoded byte array (as defined above), in which case the
+     * specified default is used.
+     *
+     * @param key key whose associated value is to be returned as a byte array.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a byte array,
+     *        or the backing store is inaccessible.
+     * @return the byte array value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a byte array.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.  (A
+     *         <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
+     * @see #get(String,String)
+     * @see #putByteArray(String,byte[])
+     */
+    public abstract byte[] getByteArray(String key, byte[] def);
+
+    /**
+     * Returns all of the keys that have an associated value in this
+     * preference node.  (The returned array will be of size zero if
+     * this node has no preferences.)
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and there
+     * are any such defaults at this node that have not been overridden,
+     * by explicit preferences, the defaults are returned in the array in
+     * addition to any explicit preferences.
+     *
+     * @return an array of the keys that have an associated value in this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract String[] keys() throws BackingStoreException;
+
+    /**
+     * Returns the names of the children of this preference node, relative to
+     * this node.  (The returned array will be of size zero if this node has
+     * no children.)
+     *
+     * @return the names of the children of this preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract String[] childrenNames() throws BackingStoreException;
+
+    /**
+     * Returns the parent of this preference node, or <tt>null</tt> if this is
+     * the root.
+     *
+     * @return the parent of this preference node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract Preferences parent();
+
+    /**
+     * Returns the named preference node in the same tree as this node,
+     * creating it and any of its ancestors if they do not already exist.
+     * Accepts a relative or absolute path name.  Relative path names
+     * (which do not begin with the slash character <tt>('/')</tt>) are
+     * interpreted relative to this preference node.
+     *
+     * <p>If the returned node did not exist prior to this call, this node and
+     * any ancestors that were created by this call are not guaranteed
+     * to become permanent until the <tt>flush</tt> method is called on
+     * the returned node (or one of its ancestors or descendants).
+     *
+     * @param pathName the path name of the preference node to return.
+     * @return the specified preference node.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws NullPointerException if path name is <tt>null</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #flush()
+     */
+    public abstract Preferences node(String pathName);
+
+    /**
+     * Returns true if the named preference node exists in the same tree
+     * as this node.  Relative path names (which do not begin with the slash
+     * character <tt>('/')</tt>) are interpreted relative to this preference
+     * node.
+     *
+     * <p>If this node (or an ancestor) has already been removed with the
+     * {@link #removeNode()} method, it <i>is</i> legal to invoke this method,
+     * but only with the path name <tt>""</tt>; the invocation will return
+     * <tt>false</tt>.  Thus, the idiom <tt>p.nodeExists("")</tt> may be
+     * used to test whether <tt>p</tt> has been removed.
+     *
+     * @param pathName the path name of the node whose existence
+     *        is to be checked.
+     * @return true if the specified node exists.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws NullPointerException if path name is <tt>null</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method and
+     *         <tt>pathName</tt> is not the empty string (<tt>""</tt>).
+     */
+    public abstract boolean nodeExists(String pathName)
+        throws BackingStoreException;
+
+    /**
+     * Removes this preference node and all of its descendants, invalidating
+     * any preferences contained in the removed nodes.  Once a node has been
+     * removed, attempting any method other than {@link #name()},
+     * {@link #absolutePath()}, {@link #isUserNode()}, {@link #flush()} or
+     * {@link #node(String) nodeExists("")} on the corresponding
+     * <tt>Preferences</tt> instance will fail with an
+     * <tt>IllegalStateException</tt>.  (The methods defined on {@link Object}
+     * can still be invoked on a node after it has been removed; they will not
+     * throw <tt>IllegalStateException</tt>.)
+     *
+     * <p>The removal is not guaranteed to be persistent until the
+     * <tt>flush</tt> method is called on this node (or an ancestor).
+     *
+     * <p>If this implementation supports <i>stored defaults</i>, removing a
+     * node exposes any stored defaults at or below this node.  Thus, a
+     * subsequent call to <tt>nodeExists</tt> on this node's path name may
+     * return <tt>true</tt>, and a subsequent call to <tt>node</tt> on this
+     * path name may return a (different) <tt>Preferences</tt> instance
+     * representing a non-empty collection of preferences and/or children.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has already
+     *         been removed with the {@link #removeNode()} method.
+     * @throws UnsupportedOperationException if this method is invoked on
+     *         the root node.
+     * @see #flush()
+     */
+    public abstract void removeNode() throws BackingStoreException;
+
+    /**
+     * Returns this preference node's name, relative to its parent.
+     *
+     * @return this preference node's name, relative to its parent.
+     */
+    public abstract String name();
+
+    /**
+     * Returns this preference node's absolute path name.
+     *
+     * @return this preference node's absolute path name.
+     */
+    public abstract String absolutePath();
+
+    /**
+     * Returns <tt>true</tt> if this preference node is in the user
+     * preference tree, <tt>false</tt> if it's in the system preference tree.
+     *
+     * @return <tt>true</tt> if this preference node is in the user
+     *         preference tree, <tt>false</tt> if it's in the system
+     *         preference tree.
+     */
+    public abstract boolean isUserNode();
+
+    /**
+     * Returns a string representation of this preferences node,
+     * as if computed by the expression:<tt>(this.isUserNode() ? "User" :
+     * "System") + " Preference Node: " + this.absolutePath()</tt>.
+     */
+    public abstract String toString();
+
+    /**
+     * Forces any changes in the contents of this preference node and its
+     * descendants to the persistent store.  Once this method returns
+     * successfully, it is safe to assume that all changes made in the
+     * subtree rooted at this node prior to the method invocation have become
+     * permanent.
+     *
+     * <p>Implementations are free to flush changes into the persistent store
+     * at any time.  They do not need to wait for this method to be called.
+     *
+     * <p>When a flush occurs on a newly created node, it is made persistent,
+     * as are any ancestors (and descendants) that have yet to be made
+     * persistent.  Note however that any preference value changes in
+     * ancestors are <i>not</i> guaranteed to be made persistent.
+     *
+     * <p> If this method is invoked on a node that has been removed with
+     * the {@link #removeNode()} method, flushSpi() is invoked on this node,
+     * but not on others.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @see    #sync()
+     */
+    public abstract void flush() throws BackingStoreException;
+
+    /**
+     * Ensures that future reads from this preference node and its
+     * descendants reflect any changes that were committed to the persistent
+     * store (from any VM) prior to the <tt>sync</tt> invocation.  As a
+     * side-effect, forces any changes in the contents of this preference node
+     * and its descendants to the persistent store, as if the <tt>flush</tt>
+     * method had been invoked on this node.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see    #flush()
+     */
+    public abstract void sync() throws BackingStoreException;
+
+    /**
+     * Registers the specified listener to receive <i>preference change
+     * events</i> for this preference node.  A preference change event is
+     * generated when a preference is added to this node, removed from this
+     * node, or when the value associated with a preference is changed.
+     * (Preference change events are <i>not</i> generated by the {@link
+     * #removeNode()} method, which generates a <i>node change event</i>.
+     * Preference change events <i>are</i> generated by the <tt>clear</tt>
+     * method.)
+     *
+     * <p>Events are only guaranteed for changes made within the same JVM
+     * as the registered listener, though some implementations may generate
+     * events for changes made outside this JVM.  Events may be generated
+     * before the changes have been made persistent.  Events are not generated
+     * when preferences are modified in descendants of this node; a caller
+     * desiring such events must register with each descendant.
+     *
+     * @param pcl The preference change listener to add.
+     * @throws NullPointerException if <tt>pcl</tt> is null.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #removePreferenceChangeListener(PreferenceChangeListener)
+     * @see #addNodeChangeListener(NodeChangeListener)
+     */
+    public abstract void addPreferenceChangeListener(
+        PreferenceChangeListener pcl);
+
+    /**
+     * Removes the specified preference change listener, so it no longer
+     * receives preference change events.
+     *
+     * @param pcl The preference change listener to remove.
+     * @throws IllegalArgumentException if <tt>pcl</tt> was not a registered
+     *         preference change listener on this node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #addPreferenceChangeListener(PreferenceChangeListener)
+     */
+    public abstract void removePreferenceChangeListener(
+        PreferenceChangeListener pcl);
+
+    /**
+     * Registers the specified listener to receive <i>node change events</i>
+     * for this node.  A node change event is generated when a child node is
+     * added to or removed from this node.  (A single {@link #removeNode()}
+     * invocation results in multiple <i>node change events</i>, one for every
+     * node in the subtree rooted at the removed node.)
+     *
+     * <p>Events are only guaranteed for changes made within the same JVM
+     * as the registered listener, though some implementations may generate
+     * events for changes made outside this JVM.  Events may be generated
+     * before the changes have become permanent.  Events are not generated
+     * when indirect descendants of this node are added or removed; a
+     * caller desiring such events must register with each descendant.
+     *
+     * <p>Few guarantees can be made regarding node creation.  Because nodes
+     * are created implicitly upon access, it may not be feasible for an
+     * implementation to determine whether a child node existed in the backing
+     * store prior to access (for example, because the backing store is
+     * unreachable or cached information is out of date).  Under these
+     * circumstances, implementations are neither required to generate node
+     * change events nor prohibited from doing so.
+     *
+     * @param ncl The <tt>NodeChangeListener</tt> to add.
+     * @throws NullPointerException if <tt>ncl</tt> is null.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #removeNodeChangeListener(NodeChangeListener)
+     * @see #addPreferenceChangeListener(PreferenceChangeListener)
+     */
+    public abstract void addNodeChangeListener(NodeChangeListener ncl);
+
+    /**
+     * Removes the specified <tt>NodeChangeListener</tt>, so it no longer
+     * receives change events.
+     *
+     * @param ncl The <tt>NodeChangeListener</tt> to remove.
+     * @throws IllegalArgumentException if <tt>ncl</tt> was not a registered
+     *         <tt>NodeChangeListener</tt> on this node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #addNodeChangeListener(NodeChangeListener)
+     */
+    public abstract void removeNodeChangeListener(NodeChangeListener ncl);
+
+    /**
+     * Emits on the specified output stream an XML document representing all
+     * of the preferences contained in this node (but not its descendants).
+     * This XML document is, in effect, an offline backup of the node.
+     *
+     * <p>The XML document will have the following DOCTYPE declaration:
+     * <pre>{@code
+     * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+     * }</pre>
+     * The UTF-8 character encoding will be used.
+     *
+     * <p>This method is an exception to the general rule that the results of
+     * concurrently executing multiple methods in this class yields
+     * results equivalent to some serial execution.  If the preferences
+     * at this node are modified concurrently with an invocation of this
+     * method, the exported preferences comprise a "fuzzy snapshot" of the
+     * preferences contained in the node; some of the concurrent modifications
+     * may be reflected in the exported data while others may not.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     * @see    #importPreferences(InputStream)
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract void exportNode(OutputStream os)
+        throws IOException, BackingStoreException;
+
+    /**
+     * Emits an XML document representing all of the preferences contained
+     * in this node and all of its descendants.  This XML document is, in
+     * effect, an offline backup of the subtree rooted at the node.
+     *
+     * <p>The XML document will have the following DOCTYPE declaration:
+     * <pre>{@code
+     * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+     * }</pre>
+     * The UTF-8 character encoding will be used.
+     *
+     * <p>This method is an exception to the general rule that the results of
+     * concurrently executing multiple methods in this class yields
+     * results equivalent to some serial execution.  If the preferences
+     * or nodes in the subtree rooted at this node are modified concurrently
+     * with an invocation of this method, the exported preferences comprise a
+     * "fuzzy snapshot" of the subtree; some of the concurrent modifications
+     * may be reflected in the exported data while others may not.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see    #importPreferences(InputStream)
+     * @see    #exportNode(OutputStream)
+     */
+    public abstract void exportSubtree(OutputStream os)
+        throws IOException, BackingStoreException;
+
+    /**
+     * Imports all of the preferences represented by the XML document on the
+     * specified input stream.  The document may represent user preferences or
+     * system preferences.  If it represents user preferences, the preferences
+     * will be imported into the calling user's preference tree (even if they
+     * originally came from a different user's preference tree).  If any of
+     * the preferences described by the document inhabit preference nodes that
+     * do not exist, the nodes will be created.
+     *
+     * <p>The XML document must have the following DOCTYPE declaration:
+     * <pre>{@code
+     * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+     * }</pre>
+     * (This method is designed for use in conjunction with
+     * {@link #exportNode(OutputStream)} and
+     * {@link #exportSubtree(OutputStream)}.
+     *
+     * <p>This method is an exception to the general rule that the results of
+     * concurrently executing multiple methods in this class yields
+     * results equivalent to some serial execution.  The method behaves
+     * as if implemented on top of the other public methods in this class,
+     * notably {@link #node(String)} and {@link #put(String, String)}.
+     *
+     * @param is the input stream from which to read the XML document.
+     * @throws IOException if reading from the specified input stream
+     *         results in an <tt>IOException</tt>.
+     * @throws InvalidPreferencesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     * @throws SecurityException If a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static void importPreferences(InputStream is)
+        throws IOException, InvalidPreferencesFormatException
+    {
+        XmlSupport.importPreferences(is);
+    }
+}
diff --git a/java/util/prefs/PreferencesFactory.java b/java/util/prefs/PreferencesFactory.java
new file mode 100644
index 0000000..d7341e6
--- /dev/null
+++ b/java/util/prefs/PreferencesFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+import java.util.*;
+
+/**
+ * A factory object that generates Preferences objects.  Providers of
+ * new {@link Preferences} implementations should provide corresponding
+ * <tt>PreferencesFactory</tt> implementations so that the new
+ * <tt>Preferences</tt> implementation can be installed in place of the
+ * platform-specific default implementation.
+ *
+ * <p><strong>This class is for <tt>Preferences</tt> implementers only.
+ * Normal users of the <tt>Preferences</tt> facility should have no need to
+ * consult this documentation.</strong>
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+public interface PreferencesFactory {
+    /**
+     * Returns the system root preference node.  (Multiple calls on this
+     * method will return the same object reference.)
+     * @return the system root preference node
+     */
+    Preferences systemRoot();
+
+    /**
+     * Returns the user root preference node corresponding to the calling
+     * user.  In a server, the returned value will typically depend on
+     * some implicit client-context.
+     * @return the user root preference node corresponding to the calling
+     * user
+     */
+    Preferences userRoot();
+}
diff --git a/java/util/prefs/XmlSupport.java b/java/util/prefs/XmlSupport.java
new file mode 100644
index 0000000..a90ff19
--- /dev/null
+++ b/java/util/prefs/XmlSupport.java
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.util.*;
+import java.io.*;
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.stream.*;
+import org.xml.sax.*;
+import org.w3c.dom.*;
+
+/**
+ * XML Support for java.util.prefs. Methods to import and export preference
+ * nodes and subtrees.
+ *
+ * @author  Josh Bloch and Mark Reinhold
+ * @see     Preferences
+ * @since   1.4
+ */
+class XmlSupport {
+    // The required DTD URI for exported preferences
+    private static final String PREFS_DTD_URI =
+        "http://java.sun.com/dtd/preferences.dtd";
+
+    // The actual DTD corresponding to the URI
+    private static final String PREFS_DTD =
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+
+        "<!-- DTD for preferences -->"               +
+
+        "<!ELEMENT preferences (root) >"             +
+        "<!ATTLIST preferences"                      +
+        " EXTERNAL_XML_VERSION CDATA \"0.0\"  >"     +
+
+        "<!ELEMENT root (map, node*) >"              +
+        "<!ATTLIST root"                             +
+        "          type (system|user) #REQUIRED >"   +
+
+        "<!ELEMENT node (map, node*) >"              +
+        "<!ATTLIST node"                             +
+        "          name CDATA #REQUIRED >"           +
+
+        "<!ELEMENT map (entry*) >"                   +
+        "<!ATTLIST map"                              +
+        "  MAP_XML_VERSION CDATA \"0.0\"  >"         +
+        "<!ELEMENT entry EMPTY >"                    +
+        "<!ATTLIST entry"                            +
+        "          key CDATA #REQUIRED"              +
+        "          value CDATA #REQUIRED >"          ;
+    /**
+     * Version number for the format exported preferences files.
+     */
+    private static final String EXTERNAL_XML_VERSION = "1.0";
+
+    /*
+     * Version number for the internal map files.
+     */
+    private static final String MAP_XML_VERSION = "1.0";
+
+    /**
+     * Export the specified preferences node and, if subTree is true, all
+     * subnodes, to the specified output stream.  Preferences are exported as
+     * an XML document conforming to the definition in the Preferences spec.
+     *
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link Preferences#removeNode()} method.
+     */
+    static void export(OutputStream os, final Preferences p, boolean subTree)
+        throws IOException, BackingStoreException {
+        if (((AbstractPreferences)p).isRemoved())
+            throw new IllegalStateException("Node has been removed");
+        Document doc = createPrefsDoc("preferences");
+        Element preferences =  doc.getDocumentElement() ;
+        preferences.setAttribute("EXTERNAL_XML_VERSION", EXTERNAL_XML_VERSION);
+        Element xmlRoot =  (Element)
+        preferences.appendChild(doc.createElement("root"));
+        xmlRoot.setAttribute("type", (p.isUserNode() ? "user" : "system"));
+
+        // Get bottom-up list of nodes from p to root, excluding root
+        List<Preferences> ancestors = new ArrayList<>();
+
+        for (Preferences kid = p, dad = kid.parent(); dad != null;
+                                   kid = dad, dad = kid.parent()) {
+            ancestors.add(kid);
+        }
+        Element e = xmlRoot;
+        for (int i=ancestors.size()-1; i >= 0; i--) {
+            e.appendChild(doc.createElement("map"));
+            e = (Element) e.appendChild(doc.createElement("node"));
+            e.setAttribute("name", ancestors.get(i).name());
+        }
+        putPreferencesInXml(e, doc, p, subTree);
+
+        writeDoc(doc, os);
+    }
+
+    /**
+     * Put the preferences in the specified Preferences node into the
+     * specified XML element which is assumed to represent a node
+     * in the specified XML document which is assumed to conform to
+     * PREFS_DTD.  If subTree is true, create children of the specified
+     * XML node conforming to all of the children of the specified
+     * Preferences node and recurse.
+     *
+     * @throws BackingStoreException if it is not possible to read
+     *         the preferences or children out of the specified
+     *         preferences node.
+     */
+    private static void putPreferencesInXml(Element elt, Document doc,
+               Preferences prefs, boolean subTree) throws BackingStoreException
+    {
+        Preferences[] kidsCopy = null;
+        String[] kidNames = null;
+
+        // Node is locked to export its contents and get a
+        // copy of children, then lock is released,
+        // and, if subTree = true, recursive calls are made on children
+        synchronized (((AbstractPreferences)prefs).lock) {
+            // Check if this node was concurrently removed. If yes
+            // remove it from XML Document and return.
+            if (((AbstractPreferences)prefs).isRemoved()) {
+                elt.getParentNode().removeChild(elt);
+                return;
+            }
+            // Put map in xml element
+            String[] keys = prefs.keys();
+            Element map = (Element) elt.appendChild(doc.createElement("map"));
+            for (int i=0; i<keys.length; i++) {
+                Element entry = (Element)
+                    map.appendChild(doc.createElement("entry"));
+                entry.setAttribute("key", keys[i]);
+                // NEXT STATEMENT THROWS NULL PTR EXC INSTEAD OF ASSERT FAIL
+                entry.setAttribute("value", prefs.get(keys[i], null));
+            }
+            // Recurse if appropriate
+            if (subTree) {
+                /* Get a copy of kids while lock is held */
+                kidNames = prefs.childrenNames();
+                kidsCopy = new Preferences[kidNames.length];
+                for (int i = 0; i <  kidNames.length; i++)
+                    kidsCopy[i] = prefs.node(kidNames[i]);
+            }
+            // release lock
+        }
+
+        if (subTree) {
+            for (int i=0; i < kidNames.length; i++) {
+                Element xmlKid = (Element)
+                    elt.appendChild(doc.createElement("node"));
+                xmlKid.setAttribute("name", kidNames[i]);
+                putPreferencesInXml(xmlKid, doc, kidsCopy[i], subTree);
+            }
+        }
+    }
+
+    /**
+     * Import preferences from the specified input stream, which is assumed
+     * to contain an XML document in the format described in the Preferences
+     * spec.
+     *
+     * @throws IOException if reading from the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws InvalidPreferencesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     */
+    static void importPreferences(InputStream is)
+        throws IOException, InvalidPreferencesFormatException
+    {
+        try {
+            Document doc = loadPrefsDoc(is);
+            String xmlVersion =
+                doc.getDocumentElement().getAttribute("EXTERNAL_XML_VERSION");
+            if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0)
+                throw new InvalidPreferencesFormatException(
+                "Exported preferences file format version " + xmlVersion +
+                " is not supported. This java installation can read" +
+                " versions " + EXTERNAL_XML_VERSION + " or older. You may need" +
+                " to install a newer version of JDK.");
+
+            // BEGIN Android-changed: Filter out non-Element nodes.
+            // Use a selector to skip over CDATA / DATA elements.
+            // The selector is specific to children with tag name "root";
+            // export() always creates exactly one such child.
+            // Element xmlRoot = (Element) doc.getDocumentElement().
+            //                                    getChildNodes().item(0);
+            Element xmlRoot = (Element) doc.getDocumentElement();
+
+            NodeList elements = xmlRoot.getElementsByTagName("root");
+            if (elements == null || elements.getLength() != 1) {
+                throw new InvalidPreferencesFormatException("invalid root node");
+            }
+
+            xmlRoot = (Element) elements.item(0);
+            // END Android-changed: Filter out non-Element nodes.
+            Preferences prefsRoot =
+                (xmlRoot.getAttribute("type").equals("user") ?
+                            Preferences.userRoot() : Preferences.systemRoot());
+            ImportSubtree(prefsRoot, xmlRoot);
+        } catch(SAXException e) {
+            throw new InvalidPreferencesFormatException(e);
+        }
+    }
+
+    /**
+     * Create a new prefs XML document.
+     */
+    private static Document createPrefsDoc( String qname ) {
+        try {
+            DOMImplementation di = DocumentBuilderFactory.newInstance().
+                newDocumentBuilder().getDOMImplementation();
+            DocumentType dt = di.createDocumentType(qname, null, PREFS_DTD_URI);
+            return di.createDocument(null, qname, dt);
+        } catch(ParserConfigurationException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Load an XML document from specified input stream, which must
+     * have the requisite DTD URI.
+     */
+    private static Document loadPrefsDoc(InputStream in)
+        throws SAXException, IOException
+    {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setIgnoringElementContentWhitespace(true);
+        // Android-changed: No validating builder implementation.
+        // dbf.setValidating(true);
+        dbf.setCoalescing(true);
+        dbf.setIgnoringComments(true);
+        try {
+            DocumentBuilder db = dbf.newDocumentBuilder();
+            db.setEntityResolver(new Resolver());
+            db.setErrorHandler(new EH());
+            return db.parse(new InputSource(in));
+        } catch (ParserConfigurationException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Write XML document to the specified output stream.
+     */
+    private static final void writeDoc(Document doc, OutputStream out)
+        throws IOException
+    {
+        try {
+            TransformerFactory tf = TransformerFactory.newInstance();
+            try {
+                tf.setAttribute("indent-number", new Integer(2));
+            } catch (IllegalArgumentException iae) {
+                //Ignore the IAE. Should not fail the writeout even the
+                //transformer provider does not support "indent-number".
+            }
+            Transformer t = tf.newTransformer();
+            t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId());
+            t.setOutputProperty(OutputKeys.INDENT, "yes");
+            //Transformer resets the "indent" info if the "result" is a StreamResult with
+            //an OutputStream object embedded, creating a Writer object on top of that
+            //OutputStream object however works.
+            t.transform(new DOMSource(doc),
+                        new StreamResult(new BufferedWriter(new OutputStreamWriter(out, "UTF-8"))));
+        } catch(TransformerException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    // BEGIN Android-added: Filter out non-Element nodes.
+    static class NodeListAdapter implements NodeList {
+        private final List<? extends Node> delegate;
+
+        public NodeListAdapter(List<? extends Node> delegate) {
+            this.delegate = Objects.requireNonNull(delegate);
+        }
+
+        @Override public Node item(int index) {
+            if (index < 0 || index >= delegate.size()) {
+                return null;
+            }
+            return delegate.get(index);
+        }
+        @Override public int getLength() { return delegate.size(); }
+    }
+
+    private static NodeList elementNodesOf(NodeList xmlKids) {
+        List<Element> elements = new ArrayList<>(xmlKids.getLength());
+        for (int i = 0; i < xmlKids.getLength(); ++i) {
+            Node node = xmlKids.item(i);
+            if (node instanceof Element) {
+                elements.add((Element) node);
+            }
+        }
+        return new NodeListAdapter(elements);
+    }
+    // END Android-added: Filter out non-Element nodes.
+
+    /**
+     * Recursively traverse the specified preferences node and store
+     * the described preferences into the system or current user
+     * preferences tree, as appropriate.
+     */
+    private static void ImportSubtree(Preferences prefsNode, Element xmlNode) {
+        NodeList xmlKids = xmlNode.getChildNodes();
+        // Android-added: Filter out non-Element nodes.
+        xmlKids = elementNodesOf(xmlKids);
+        int numXmlKids = xmlKids.getLength();
+        /*
+         * We first lock the node, import its contents and get
+         * child nodes. Then we unlock the node and go to children
+         * Since some of the children might have been concurrently
+         * deleted we check for this.
+         */
+        Preferences[] prefsKids;
+        /* Lock the node */
+        synchronized (((AbstractPreferences)prefsNode).lock) {
+            //If removed, return silently
+            if (((AbstractPreferences)prefsNode).isRemoved())
+                return;
+
+            // Import any preferences at this node
+            Element firstXmlKid = (Element) xmlKids.item(0);
+            ImportPrefs(prefsNode, firstXmlKid);
+            prefsKids = new Preferences[numXmlKids - 1];
+
+            // Get involved children
+            for (int i=1; i < numXmlKids; i++) {
+                Element xmlKid = (Element) xmlKids.item(i);
+                prefsKids[i-1] = prefsNode.node(xmlKid.getAttribute("name"));
+            }
+        } // unlocked the node
+        // import children
+        for (int i=1; i < numXmlKids; i++)
+            ImportSubtree(prefsKids[i-1], (Element)xmlKids.item(i));
+    }
+
+    /**
+     * Import the preferences described by the specified XML element
+     * (a map from a preferences document) into the specified
+     * preferences node.
+     */
+    private static void ImportPrefs(Preferences prefsNode, Element map) {
+        NodeList entries = map.getChildNodes();
+        // Android-added: Filter out non-Element nodes.
+        entries = elementNodesOf(entries);
+        for (int i=0, numEntries = entries.getLength(); i < numEntries; i++) {
+            Element entry = (Element) entries.item(i);
+            prefsNode.put(entry.getAttribute("key"),
+                          entry.getAttribute("value"));
+        }
+    }
+
+    /**
+     * Export the specified Map<String,String> to a map document on
+     * the specified OutputStream as per the prefs DTD.  This is used
+     * as the internal (undocumented) format for FileSystemPrefs.
+     *
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     */
+    static void exportMap(OutputStream os, Map<String, String> map) throws IOException {
+        Document doc = createPrefsDoc("map");
+        Element xmlMap = doc.getDocumentElement( ) ;
+        xmlMap.setAttribute("MAP_XML_VERSION", MAP_XML_VERSION);
+
+        for (Iterator<Map.Entry<String, String>> i = map.entrySet().iterator(); i.hasNext(); ) {
+            Map.Entry<String, String> e = i.next();
+            Element xe = (Element)
+                xmlMap.appendChild(doc.createElement("entry"));
+            xe.setAttribute("key",   e.getKey());
+            xe.setAttribute("value", e.getValue());
+        }
+
+        writeDoc(doc, os);
+    }
+
+    /**
+     * Import Map from the specified input stream, which is assumed
+     * to contain a map document as per the prefs DTD.  This is used
+     * as the internal (undocumented) format for FileSystemPrefs.  The
+     * key-value pairs specified in the XML document will be put into
+     * the specified Map.  (If this Map is empty, it will contain exactly
+     * the key-value pairs int the XML-document when this method returns.)
+     *
+     * @throws IOException if reading from the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws InvalidPreferencesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     */
+    static void importMap(InputStream is, Map<String, String> m)
+        throws IOException, InvalidPreferencesFormatException
+    {
+        try {
+            Document doc = loadPrefsDoc(is);
+            Element xmlMap = doc.getDocumentElement();
+            // check version
+            String mapVersion = xmlMap.getAttribute("MAP_XML_VERSION");
+            if (mapVersion.compareTo(MAP_XML_VERSION) > 0)
+                throw new InvalidPreferencesFormatException(
+                "Preferences map file format version " + mapVersion +
+                " is not supported. This java installation can read" +
+                " versions " + MAP_XML_VERSION + " or older. You may need" +
+                " to install a newer version of JDK.");
+
+            NodeList entries = xmlMap.getChildNodes();
+            for (int i=0, numEntries=entries.getLength(); i<numEntries; i++) {
+                // BEGIN Android-added: Filter out non-Element nodes.
+                // Android xml serializer generates one-char Text nodes with a single
+                // new-line character between expected Element nodes. OpenJDK code wasn't
+                // expecting anything else than Element nodes.
+                if (!(entries.item(i) instanceof Element)) {
+                    continue;
+                }
+                // END Android-added: Filter out non-Element nodes.
+                Element entry = (Element) entries.item(i);
+                m.put(entry.getAttribute("key"), entry.getAttribute("value"));
+            }
+        } catch(SAXException e) {
+            throw new InvalidPreferencesFormatException(e);
+        }
+    }
+
+    private static class Resolver implements EntityResolver {
+        public InputSource resolveEntity(String pid, String sid)
+            throws SAXException
+        {
+            if (sid.equals(PREFS_DTD_URI)) {
+                InputSource is;
+                is = new InputSource(new StringReader(PREFS_DTD));
+                is.setSystemId(PREFS_DTD_URI);
+                return is;
+            }
+            throw new SAXException("Invalid system identifier: " + sid);
+        }
+    }
+
+    private static class EH implements ErrorHandler {
+        public void error(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void fatalError(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void warning(SAXParseException x) throws SAXException {
+            throw x;
+        }
+    }
+}
diff --git a/java/util/regex/MatchResult.java b/java/util/regex/MatchResult.java
new file mode 100644
index 0000000..4f42eae
--- /dev/null
+++ b/java/util/regex/MatchResult.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+/**
+ * The result of a match operation.
+ *
+ * <p>This interface contains query methods used to determine the
+ * results of a match against a regular expression. The match boundaries,
+ * groups and group boundaries can be seen but not modified through
+ * a <code>MatchResult</code>.
+ *
+ * @author  Michael McCloskey
+ * @see Matcher
+ * @since 1.5
+ */
+public interface MatchResult {
+
+    /**
+     * Returns the start index of the match.
+     *
+     * @return  The index of the first character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int start();
+
+    /**
+     * Returns the start index of the subsequence captured by the given group
+     * during this match.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i><tt>start(0)</tt> is equivalent to
+     * <i>m.</i><tt>start()</tt>.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The index of the first character captured by the group,
+     *          or <tt>-1</tt> if the match was successful but the group
+     *          itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int start(int group);
+
+    /**
+     * Returns the offset after the last character matched.
+     *
+     * @return  The offset after the last character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int end();
+
+    /**
+     * Returns the offset after the last character of the subsequence
+     * captured by the given group during this match.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i><tt>end(0)</tt> is equivalent to
+     * <i>m.</i><tt>end()</tt>.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The offset after the last character captured by the group,
+     *          or <tt>-1</tt> if the match was successful
+     *          but the group itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int end(int group);
+
+    /**
+     * Returns the input subsequence matched by the previous match.
+     *
+     * <p> For a matcher <i>m</i> with input sequence <i>s</i>,
+     * the expressions <i>m.</i><tt>group()</tt> and
+     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(),</tt>&nbsp;<i>m.</i><tt>end())</tt>
+     * are equivalent.  </p>
+     *
+     * <p> Note that some patterns, for example <tt>a*</tt>, match the empty
+     * string.  This method will return the empty string when the pattern
+     * successfully matches the empty string in the input.  </p>
+     *
+     * @return The (possibly empty) subsequence matched by the previous match,
+     *         in string form
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public String group();
+
+    /**
+     * Returns the input subsequence captured by the given group during the
+     * previous match operation.
+     *
+     * <p> For a matcher <i>m</i>, input sequence <i>s</i>, and group index
+     * <i>g</i>, the expressions <i>m.</i><tt>group(</tt><i>g</i><tt>)</tt> and
+     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(</tt><i>g</i><tt>),</tt>&nbsp;<i>m.</i><tt>end(</tt><i>g</i><tt>))</tt>
+     * are equivalent.  </p>
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <tt>m.group(0)</tt> is equivalent to <tt>m.group()</tt>.
+     * </p>
+     *
+     * <p> If the match was successful but the group specified failed to match
+     * any part of the input sequence, then <tt>null</tt> is returned. Note
+     * that some groups, for example <tt>(a*)</tt>, match the empty string.
+     * This method will return the empty string when such a group successfully
+     * matches the empty string in the input.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The (possibly empty) subsequence captured by the group
+     *          during the previous match, or <tt>null</tt> if the group
+     *          failed to match part of the input
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public String group(int group);
+
+    /**
+     * Returns the number of capturing groups in this match result's pattern.
+     *
+     * <p> Group zero denotes the entire pattern by convention. It is not
+     * included in this count.
+     *
+     * <p> Any non-negative integer smaller than or equal to the value
+     * returned by this method is guaranteed to be a valid group index for
+     * this matcher.  </p>
+     *
+     * @return The number of capturing groups in this matcher's pattern
+     */
+    public int groupCount();
+
+}
diff --git a/java/util/regex/Matcher.annotated.java b/java/util/regex/Matcher.annotated.java
new file mode 100644
index 0000000..1bc7c89
--- /dev/null
+++ b/java/util/regex/Matcher.annotated.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.regex;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Matcher implements java.util.regex.MatchResult {
+
+Matcher(@libcore.util.NonNull java.util.regex.Pattern parent, @libcore.util.NonNull java.lang.CharSequence text) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Pattern pattern() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.MatchResult toMatchResult() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher usePattern(@libcore.util.NonNull java.util.regex.Pattern newPattern) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher reset() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher reset(@libcore.util.NonNull java.lang.CharSequence input) { throw new RuntimeException("Stub!"); }
+
+public int start() { throw new RuntimeException("Stub!"); }
+
+public int start(int group) { throw new RuntimeException("Stub!"); }
+
+public int start(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public int end() { throw new RuntimeException("Stub!"); }
+
+public int end(int group) { throw new RuntimeException("Stub!"); }
+
+public int end(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String group() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String group(int group) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String group(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public int groupCount() { throw new RuntimeException("Stub!"); }
+
+public boolean matches() { throw new RuntimeException("Stub!"); }
+
+public boolean find() { throw new RuntimeException("Stub!"); }
+
+public boolean find(int start) { throw new RuntimeException("Stub!"); }
+
+public boolean lookingAt() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String quoteReplacement(@libcore.util.NonNull java.lang.String s) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher appendReplacement(@libcore.util.NonNull java.lang.StringBuffer sb, @libcore.util.NonNull java.lang.String replacement) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuffer appendTail(@libcore.util.NonNull java.lang.StringBuffer sb) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String replaceAll(@libcore.util.NonNull java.lang.String replacement) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String replaceFirst(@libcore.util.NonNull java.lang.String replacement) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher region(int start, int end) { throw new RuntimeException("Stub!"); }
+
+public int regionStart() { throw new RuntimeException("Stub!"); }
+
+public int regionEnd() { throw new RuntimeException("Stub!"); }
+
+public boolean hasTransparentBounds() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher useTransparentBounds(boolean b) { throw new RuntimeException("Stub!"); }
+
+public boolean hasAnchoringBounds() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher useAnchoringBounds(boolean b) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public boolean hitEnd() { throw new RuntimeException("Stub!"); }
+
+public boolean requireEnd() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/regex/Matcher.java b/java/util/regex/Matcher.java
new file mode 100644
index 0000000..d50ea32
--- /dev/null
+++ b/java/util/regex/Matcher.java
@@ -0,0 +1,1259 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+import com.android.icu.util.regex.MatcherNative;
+
+/**
+ * An engine that performs match operations on a {@linkplain java.lang.CharSequence
+ * character sequence} by interpreting a {@link Pattern}.
+ *
+ * <p> A matcher is created from a pattern by invoking the pattern's {@link
+ * Pattern#matcher matcher} method.  Once created, a matcher can be used to
+ * perform three different kinds of match operations:
+ *
+ * <ul>
+ *
+ *   <li><p> The {@link #matches matches} method attempts to match the entire
+ *   input sequence against the pattern.  </p></li>
+ *
+ *   <li><p> The {@link #lookingAt lookingAt} method attempts to match the
+ *   input sequence, starting at the beginning, against the pattern.  </p></li>
+ *
+ *   <li><p> The {@link #find find} method scans the input sequence looking for
+ *   the next subsequence that matches the pattern.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Each of these methods returns a boolean indicating success or failure.
+ * More information about a successful match can be obtained by querying the
+ * state of the matcher.
+ *
+ * <p> A matcher finds matches in a subset of its input called the
+ * <i>region</i>. By default, the region contains all of the matcher's input.
+ * The region can be modified via the{@link #region region} method and queried
+ * via the {@link #regionStart regionStart} and {@link #regionEnd regionEnd}
+ * methods. The way that the region boundaries interact with some pattern
+ * constructs can be changed. See {@link #useAnchoringBounds
+ * useAnchoringBounds} and {@link #useTransparentBounds useTransparentBounds}
+ * for more details.
+ *
+ * <p> This class also defines methods for replacing matched subsequences with
+ * new strings whose contents can, if desired, be computed from the match
+ * result.  The {@link #appendReplacement appendReplacement} and {@link
+ * #appendTail appendTail} methods can be used in tandem in order to collect
+ * the result into an existing string buffer, or the more convenient {@link
+ * #replaceAll replaceAll} method can be used to create a string in which every
+ * matching subsequence in the input sequence is replaced.
+ *
+ * <p> The explicit state of a matcher includes the start and end indices of
+ * the most recent successful match.  It also includes the start and end
+ * indices of the input subsequence captured by each <a
+ * href="Pattern.html#cg">capturing group</a> in the pattern as well as a total
+ * count of such subsequences.  As a convenience, methods are also provided for
+ * returning these captured subsequences in string form.
+ *
+ * <p> The explicit state of a matcher is initially undefined; attempting to
+ * query any part of it before a successful match will cause an {@link
+ * IllegalStateException} to be thrown.  The explicit state of a matcher is
+ * recomputed by every match operation.
+ *
+ * <p> The implicit state of a matcher includes the input character sequence as
+ * well as the <i>append position</i>, which is initially zero and is updated
+ * by the {@link #appendReplacement appendReplacement} method.
+ *
+ * <p> A matcher may be reset explicitly by invoking its {@link #reset()}
+ * method or, if a new input sequence is desired, its {@link
+ * #reset(java.lang.CharSequence) reset(CharSequence)} method.  Resetting a
+ * matcher discards its explicit state information and sets the append position
+ * to zero.
+ *
+ * <p> Instances of this class are not safe for use by multiple concurrent
+ * threads. </p>
+ *
+ *
+ * @author      Mike McCloskey
+ * @author      Mark Reinhold
+ * @author      JSR-51 Expert Group
+ * @since       1.4
+ * @spec        JSR-51
+ */
+
+public final class Matcher implements MatchResult {
+
+    /**
+     * The Pattern object that created this Matcher.
+     */
+    private Pattern parentPattern;
+
+    /**
+     * Holds the offsets for the most recent match.
+     */
+    int[] groups;
+
+    /**
+     * The range within the sequence that is to be matched (between  0
+     * and text.length()).
+     */
+    int from, to;
+
+    /**
+     * Holds the input text.
+     */
+    String text;
+
+    /**
+     * Reflects whether a match has been found during the most recent find
+     * operation.
+     */
+    private boolean matchFound;
+
+    private MatcherNative nativeMatcher;
+
+    /**
+     * The index of the last position appended in a substitution.
+     */
+    int appendPos = 0;
+
+    /**
+     * Holds the original CharSequence for use in {@link #reset}. {@link #text} is used during
+     * matching. Note that CharSequence is mutable while String is not, so reset can cause the input
+     * to match to change.
+     */
+    private CharSequence originalInput;
+
+    /**
+     * If transparentBounds is true then the boundaries of this
+     * matcher's region are transparent to lookahead, lookbehind,
+     * and boundary matching constructs that try to see beyond them.
+     */
+    boolean transparentBounds = false;
+
+    /**
+     * If anchoringBounds is true then the boundaries of this
+     * matcher's region match anchors such as ^ and $.
+     */
+    boolean anchoringBounds = true;
+
+    /**
+     * All matchers have the state used by Pattern during a match.
+     */
+    Matcher(Pattern parent, CharSequence text) {
+        usePattern(parent);
+        reset(text);
+    }
+
+    /**
+     * Returns the pattern that is interpreted by this matcher.
+     *
+     * @return  The pattern for which this matcher was created
+     */
+    public Pattern pattern() {
+        return parentPattern;
+    }
+
+    /**
+     * Returns the match state of this matcher as a {@link MatchResult}.
+     * The result is unaffected by subsequent operations performed upon this
+     * matcher.
+     *
+     * @return  a <code>MatchResult</code> with the state of this matcher
+     * @since 1.5
+     */
+    public MatchResult toMatchResult() {
+        ensureMatch();
+        return new OffsetBasedMatchResult(text, groups);
+    }
+
+    /**
+      * Changes the <tt>Pattern</tt> that this <tt>Matcher</tt> uses to
+      * find matches with.
+      *
+      * <p> This method causes this matcher to lose information
+      * about the groups of the last match that occurred. The
+      * matcher's position in the input is maintained and its
+      * last append position is unaffected.</p>
+      *
+      * @param  newPattern
+      *         The new pattern used by this matcher
+      * @return  This matcher
+      * @throws  IllegalArgumentException
+      *          If newPattern is <tt>null</tt>
+      * @since 1.5
+      */
+    public Matcher usePattern(Pattern newPattern) {
+        if (newPattern == null)
+            throw new IllegalArgumentException("Pattern cannot be null");
+
+        synchronized (this) {
+            // may throw
+            nativeMatcher = MatcherNative.create(newPattern.nativePattern);
+        }
+        parentPattern = newPattern;
+
+        if (text != null) {
+            resetForInput();
+        }
+
+        groups = new int[(groupCount() + 1) * 2];
+        matchFound = false;
+        return this;
+    }
+
+    /**
+     * Resets this matcher.
+     *
+     * <p> Resetting a matcher discards all of its explicit state information
+     * and sets its append position to zero. The matcher's region is set to the
+     * default region, which is its entire character sequence. The anchoring
+     * and transparency of this matcher's region boundaries are unaffected.
+     *
+     * @return  This matcher
+     */
+    public Matcher reset() {
+        return reset(originalInput, 0, originalInput.length());
+    }
+
+    /**
+     * Resets this matcher with a new input sequence.
+     *
+     * <p> Resetting a matcher discards all of its explicit state information
+     * and sets its append position to zero.  The matcher's region is set to
+     * the default region, which is its entire character sequence.  The
+     * anchoring and transparency of this matcher's region boundaries are
+     * unaffected.
+     *
+     * @param  input
+     *         The new input character sequence
+     *
+     * @return  This matcher
+     */
+    public Matcher reset(CharSequence input) {
+        return reset(input, 0, input.length());
+    }
+
+    /**
+     * Returns the start index of the previous match.
+     *
+     * @return  The index of the first character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int start() {
+        return start(0);
+    }
+
+    /**
+     * Returns the start index of the subsequence captured by the given group
+     * during the previous match operation.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i><tt>start(0)</tt> is equivalent to
+     * <i>m.</i><tt>start()</tt>.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The index of the first character captured by the group,
+     *          or <tt>-1</tt> if the match was successful but the group
+     *          itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int start(int group) {
+        ensureMatch();
+        if (group < 0 || group > groupCount())
+            throw new IndexOutOfBoundsException("No group " + group);
+        return groups[group * 2];
+    }
+
+    /**
+     * Returns the start index of the subsequence captured by the given
+     * <a href="Pattern.html#groupname">named-capturing group</a> during the
+     * previous match operation.
+     *
+     * @param  name
+     *         The name of a named-capturing group in this matcher's pattern
+     *
+     * @return  The index of the first character captured by the group,
+     *          or {@code -1} if the match was successful but the group
+     *          itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If there is no capturing group in the pattern
+     *          with the given name
+     * @since 1.8
+     */
+    public int start(String name) {
+        return groups[getMatchedGroupIndex(name) * 2];
+    }
+
+    /**
+     * Returns the offset after the last character matched.
+     *
+     * @return  The offset after the last character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int end() {
+        return end(0);
+    }
+
+    /**
+     * Returns the offset after the last character of the subsequence
+     * captured by the given group during the previous match operation.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i><tt>end(0)</tt> is equivalent to
+     * <i>m.</i><tt>end()</tt>.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The offset after the last character captured by the group,
+     *          or <tt>-1</tt> if the match was successful
+     *          but the group itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int end(int group) {
+        ensureMatch();
+        if (group < 0 || group > groupCount())
+            throw new IndexOutOfBoundsException("No group " + group);
+        return groups[group * 2 + 1];
+    }
+
+    /**
+     * Returns the offset after the last character of the subsequence
+     * captured by the given <a href="Pattern.html#groupname">named-capturing
+     * group</a> during the previous match operation.
+     *
+     * @param  name
+     *         The name of a named-capturing group in this matcher's pattern
+     *
+     * @return  The offset after the last character captured by the group,
+     *          or {@code -1} if the match was successful
+     *          but the group itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If there is no capturing group in the pattern
+     *          with the given name
+     * @since 1.8
+     */
+    public int end(String name) {
+        return groups[getMatchedGroupIndex(name) * 2 + 1];
+    }
+
+    /**
+     * Returns the input subsequence matched by the previous match.
+     *
+     * <p> For a matcher <i>m</i> with input sequence <i>s</i>,
+     * the expressions <i>m.</i><tt>group()</tt> and
+     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(),</tt>&nbsp;<i>m.</i><tt>end())</tt>
+     * are equivalent.  </p>
+     *
+     * <p> Note that some patterns, for example <tt>a*</tt>, match the empty
+     * string.  This method will return the empty string when the pattern
+     * successfully matches the empty string in the input.  </p>
+     *
+     * @return The (possibly empty) subsequence matched by the previous match,
+     *         in string form
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public String group() {
+        return group(0);
+    }
+
+    /**
+     * Returns the input subsequence captured by the given group during the
+     * previous match operation.
+     *
+     * <p> For a matcher <i>m</i>, input sequence <i>s</i>, and group index
+     * <i>g</i>, the expressions <i>m.</i><tt>group(</tt><i>g</i><tt>)</tt> and
+     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(</tt><i>g</i><tt>),</tt>&nbsp;<i>m.</i><tt>end(</tt><i>g</i><tt>))</tt>
+     * are equivalent.  </p>
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <tt>m.group(0)</tt> is equivalent to <tt>m.group()</tt>.
+     * </p>
+     *
+     * <p> If the match was successful but the group specified failed to match
+     * any part of the input sequence, then <tt>null</tt> is returned. Note
+     * that some groups, for example <tt>(a*)</tt>, match the empty string.
+     * This method will return the empty string when such a group successfully
+     * matches the empty string in the input.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The (possibly empty) subsequence captured by the group
+     *          during the previous match, or <tt>null</tt> if the group
+     *          failed to match part of the input
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public String group(int group) {
+        ensureMatch();
+        if (group < 0 || group > groupCount())
+            throw new IndexOutOfBoundsException("No group " + group);
+        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
+            return null;
+        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
+    }
+
+    /**
+     * Returns the input subsequence captured by the given
+     * <a href="Pattern.html#groupname">named-capturing group</a> during the previous
+     * match operation.
+     *
+     * <p> If the match was successful but the group specified failed to match
+     * any part of the input sequence, then <tt>null</tt> is returned. Note
+     * that some groups, for example <tt>(a*)</tt>, match the empty string.
+     * This method will return the empty string when such a group successfully
+     * matches the empty string in the input.  </p>
+     *
+     * @param  name
+     *         The name of a named-capturing group in this matcher's pattern
+     *
+     * @return  The (possibly empty) subsequence captured by the named group
+     *          during the previous match, or <tt>null</tt> if the group
+     *          failed to match part of the input
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If there is no capturing group in the pattern
+     *          with the given name
+     * @since 1.7
+     */
+    public String group(String name) {
+        int group = getMatchedGroupIndex(name);
+        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
+            return null;
+        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
+    }
+
+    /**
+     * Returns the number of capturing groups in this matcher's pattern.
+     *
+     * <p> Group zero denotes the entire pattern by convention. It is not
+     * included in this count.
+     *
+     * <p> Any non-negative integer smaller than or equal to the value
+     * returned by this method is guaranteed to be a valid group index for
+     * this matcher.  </p>
+     *
+     * @return The number of capturing groups in this matcher's pattern
+     */
+    public int groupCount() {
+        synchronized (this) {
+            return nativeMatcher.groupCount();
+        }
+    }
+
+    /**
+     * Attempts to match the entire region against the pattern.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, the entire region sequence
+     *          matches this matcher's pattern
+     */
+    public boolean matches() {
+        synchronized (this) {
+            matchFound = nativeMatcher.matches(groups);
+        }
+        return matchFound;
+    }
+
+    /**
+     * Attempts to find the next subsequence of the input sequence that matches
+     * the pattern.
+     *
+     * <p> This method starts at the beginning of this matcher's region, or, if
+     * a previous invocation of the method was successful and the matcher has
+     * not since been reset, at the first character not matched by the previous
+     * match.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, a subsequence of the input
+     *          sequence matches this matcher's pattern
+     */
+    public boolean find() {
+        synchronized (this) {
+            matchFound = nativeMatcher.findNext(groups);
+        }
+        return matchFound;
+    }
+
+    /**
+     * Resets this matcher and then attempts to find the next subsequence of
+     * the input sequence that matches the pattern, starting at the specified
+     * index.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods, and subsequent
+     * invocations of the {@link #find()} method will start at the first
+     * character not matched by this match.  </p>
+     *
+     * @param start the index to start searching for a match
+     * @throws  IndexOutOfBoundsException
+     *          If start is less than zero or if start is greater than the
+     *          length of the input sequence.
+     *
+     * @return  <tt>true</tt> if, and only if, a subsequence of the input
+     *          sequence starting at the given index matches this matcher's
+     *          pattern
+     */
+    public boolean find(int start) {
+        int limit = getTextLength();
+        if ((start < 0) || (start > limit))
+            throw new IndexOutOfBoundsException("Illegal start index");
+        reset();
+        synchronized (this) {
+            matchFound = nativeMatcher.find(start, groups);
+        }
+        return matchFound;
+    }
+
+    /**
+     * Attempts to match the input sequence, starting at the beginning of the
+     * region, against the pattern.
+     *
+     * <p> Like the {@link #matches matches} method, this method always starts
+     * at the beginning of the region; unlike that method, it does not
+     * require that the entire region be matched.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, a prefix of the input
+     *          sequence matches this matcher's pattern
+     */
+    public boolean lookingAt() {
+        synchronized (this) {
+            matchFound = nativeMatcher.lookingAt(groups);
+        }
+        return matchFound;
+    }
+
+    /**
+     * Returns a literal replacement <code>String</code> for the specified
+     * <code>String</code>.
+     *
+     * This method produces a <code>String</code> that will work
+     * as a literal replacement <code>s</code> in the
+     * <code>appendReplacement</code> method of the {@link Matcher} class.
+     * The <code>String</code> produced will match the sequence of characters
+     * in <code>s</code> treated as a literal sequence. Slashes ('\') and
+     * dollar signs ('$') will be given no special meaning.
+     *
+     * @param  s The string to be literalized
+     * @return  A literal string replacement
+     * @since 1.5
+     */
+    public static String quoteReplacement(String s) {
+        if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1))
+            return s;
+        StringBuilder sb = new StringBuilder();
+        for (int i=0; i<s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '\\' || c == '$') {
+                sb.append('\\');
+            }
+            sb.append(c);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Implements a non-terminal append-and-replace step.
+     *
+     * <p> This method performs the following actions: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> It reads characters from the input sequence, starting at the
+     *   append position, and appends them to the given string buffer.  It
+     *   stops after reading the last character preceding the previous match,
+     *   that is, the character at index {@link
+     *   #start()}&nbsp;<tt>-</tt>&nbsp;<tt>1</tt>.  </p></li>
+     *
+     *   <li><p> It appends the given replacement string to the string buffer.
+     *   </p></li>
+     *
+     *   <li><p> It sets the append position of this matcher to the index of
+     *   the last character matched, plus one, that is, to {@link #end()}.
+     *   </p></li>
+     *
+     * </ol>
+     *
+     * <p> The replacement string may contain references to subsequences
+     * captured during the previous match: Each occurrence of
+     * <tt>${</tt><i>name</i><tt>}</tt> or <tt>$</tt><i>g</i>
+     * will be replaced by the result of evaluating the corresponding
+     * {@link #group(String) group(name)} or {@link #group(int) group(g)}
+     * respectively. For  <tt>$</tt><i>g</i>,
+     * the first number after the <tt>$</tt> is always treated as part of
+     * the group reference. Subsequent numbers are incorporated into g if
+     * they would form a legal group reference. Only the numerals '0'
+     * through '9' are considered as potential components of the group
+     * reference. If the second group matched the string <tt>"foo"</tt>, for
+     * example, then passing the replacement string <tt>"$2bar"</tt> would
+     * cause <tt>"foobar"</tt> to be appended to the string buffer. A dollar
+     * sign (<tt>$</tt>) may be included as a literal in the replacement
+     * string by preceding it with a backslash (<tt>\$</tt>).
+     *
+     * <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
+     * the replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> This method is intended to be used in a loop together with the
+     * {@link #appendTail appendTail} and {@link #find find} methods.  The
+     * following code, for example, writes <tt>one dog two dogs in the
+     * yard</tt> to the standard-output stream: </p>
+     *
+     * <blockquote><pre>
+     * Pattern p = Pattern.compile("cat");
+     * Matcher m = p.matcher("one cat two cats in the yard");
+     * StringBuffer sb = new StringBuffer();
+     * while (m.find()) {
+     *     m.appendReplacement(sb, "dog");
+     * }
+     * m.appendTail(sb);
+     * System.out.println(sb.toString());</pre></blockquote>
+     *
+     * @param  sb
+     *         The target string buffer
+     *
+     * @param  replacement
+     *         The replacement string
+     *
+     * @return  This matcher
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If the replacement string refers to a named-capturing
+     *          group that does not exist in the pattern
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the replacement string refers to a capturing group
+     *          that does not exist in the pattern
+     */
+    public Matcher appendReplacement(StringBuffer sb, String replacement) {
+
+        sb.append(text.substring(appendPos, start()));
+        appendEvaluated(sb, replacement);
+        appendPos = end();
+
+        return this;
+    }
+
+    /**
+     * Internal helper method to append a given string to a given string buffer.
+     * If the string contains any references to groups, these are replaced by
+     * the corresponding group's contents.
+     *
+     * @param buffer the string buffer.
+     * @param s the string to append.
+     */
+    private void appendEvaluated(StringBuffer buffer, String s) {
+        boolean escape = false;
+        boolean dollar = false;
+        boolean escapeNamedGroup = false;
+        int escapeNamedGroupStart = -1;
+
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '\\' && !escape) {
+                escape = true;
+            } else if (c == '$' && !escape) {
+                dollar = true;
+            } else if (c >= '0' && c <= '9' && dollar && !escapeNamedGroup) {
+                String groupValue = group(c - '0');
+                if (groupValue != null) {
+                    buffer.append(groupValue);
+                }
+                dollar = false;
+            } else if (c == '{' && dollar) {
+                escapeNamedGroup = true;
+                escapeNamedGroupStart = i;
+            } else if (c == '}' && dollar && escapeNamedGroup) {
+                String groupValue = group(s.substring(escapeNamedGroupStart + 1, i));
+                if (groupValue != null) {
+                    buffer.append(groupValue);
+                }
+                dollar = false;
+                escapeNamedGroup = false;
+            } else if (c != '}' && dollar && escapeNamedGroup) {
+                continue;
+            } else {
+                buffer.append(c);
+                dollar = false;
+                escape = false;
+                escapeNamedGroup = false;
+            }
+        }
+
+        if (escape) {
+            throw new IllegalArgumentException("character to be escaped is missing");
+        }
+
+        if (dollar) {
+            throw new IllegalArgumentException("Illegal group reference: group index is missing");
+        }
+
+        if (escapeNamedGroup) {
+            throw new IllegalArgumentException("Missing ending brace '}' from replacement string");
+        }
+    }
+
+    /**
+     * Implements a terminal append-and-replace step.
+     *
+     * <p> This method reads characters from the input sequence, starting at
+     * the append position, and appends them to the given string buffer.  It is
+     * intended to be invoked after one or more invocations of the {@link
+     * #appendReplacement appendReplacement} method in order to copy the
+     * remainder of the input sequence.  </p>
+     *
+     * @param  sb
+     *         The target string buffer
+     *
+     * @return  The target string buffer
+     */
+    public StringBuffer appendTail(StringBuffer sb) {
+        if (appendPos < to) {
+            sb.append(text.substring(appendPos, to));
+        }
+        return sb;
+    }
+
+    /**
+     * Replaces every subsequence of the input sequence that matches the
+     * pattern with the given replacement string.
+     *
+     * <p> This method first resets this matcher.  It then scans the input
+     * sequence looking for matches of the pattern.  Characters that are not
+     * part of any match are appended directly to the result string; each match
+     * is replaced in the result by the replacement string.  The replacement
+     * string may contain references to captured subsequences as in the {@link
+     * #appendReplacement appendReplacement} method.
+     *
+     * <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
+     * the replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> Given the regular expression <tt>a*b</tt>, the input
+     * <tt>"aabfooaabfooabfoob"</tt>, and the replacement string
+     * <tt>"-"</tt>, an invocation of this method on a matcher for that
+     * expression would yield the string <tt>"-foo-foo-foo-"</tt>.
+     *
+     * <p> Invoking this method changes this matcher's state.  If the matcher
+     * is to be used in further matching operations then it should first be
+     * reset.  </p>
+     *
+     * @param  replacement
+     *         The replacement string
+     *
+     * @return  The string constructed by replacing each matching subsequence
+     *          by the replacement string, substituting captured subsequences
+     *          as needed
+     */
+    public String replaceAll(String replacement) {
+        reset();
+        boolean result = find();
+        if (result) {
+            StringBuffer sb = new StringBuffer();
+            do {
+                appendReplacement(sb, replacement);
+                result = find();
+            } while (result);
+            appendTail(sb);
+            return sb.toString();
+        }
+        return text.toString();
+    }
+
+    /**
+     * Replaces the first subsequence of the input sequence that matches the
+     * pattern with the given replacement string.
+     *
+     * <p> This method first resets this matcher.  It then scans the input
+     * sequence looking for a match of the pattern.  Characters that are not
+     * part of the match are appended directly to the result string; the match
+     * is replaced in the result by the replacement string.  The replacement
+     * string may contain references to captured subsequences as in the {@link
+     * #appendReplacement appendReplacement} method.
+     *
+     * <p>Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
+     * the replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> Given the regular expression <tt>dog</tt>, the input
+     * <tt>"zzzdogzzzdogzzz"</tt>, and the replacement string
+     * <tt>"cat"</tt>, an invocation of this method on a matcher for that
+     * expression would yield the string <tt>"zzzcatzzzdogzzz"</tt>.  </p>
+     *
+     * <p> Invoking this method changes this matcher's state.  If the matcher
+     * is to be used in further matching operations then it should first be
+     * reset.  </p>
+     *
+     * @param  replacement
+     *         The replacement string
+     * @return  The string constructed by replacing the first matching
+     *          subsequence by the replacement string, substituting captured
+     *          subsequences as needed
+     */
+    public String replaceFirst(String replacement) {
+        if (replacement == null)
+            throw new NullPointerException("replacement");
+        reset();
+        if (!find())
+            return text.toString();
+        StringBuffer sb = new StringBuffer();
+        appendReplacement(sb, replacement);
+        appendTail(sb);
+        return sb.toString();
+    }
+
+    /**
+     * Sets the limits of this matcher's region. The region is the part of the
+     * input sequence that will be searched to find a match. Invoking this
+     * method resets the matcher, and then sets the region to start at the
+     * index specified by the <code>start</code> parameter and end at the
+     * index specified by the <code>end</code> parameter.
+     *
+     * <p>Depending on the transparency and anchoring being used (see
+     * {@link #useTransparentBounds useTransparentBounds} and
+     * {@link #useAnchoringBounds useAnchoringBounds}), certain constructs such
+     * as anchors may behave differently at or around the boundaries of the
+     * region.
+     *
+     * @param  start
+     *         The index to start searching at (inclusive)
+     * @param  end
+     *         The index to end searching at (exclusive)
+     * @throws  IndexOutOfBoundsException
+     *          If start or end is less than zero, if
+     *          start is greater than the length of the input sequence, if
+     *          end is greater than the length of the input sequence, or if
+     *          start is greater than end.
+     * @return  this matcher
+     * @since 1.5
+     */
+    public Matcher region(int start, int end) {
+        return reset(originalInput, start, end);
+    }
+
+    /**
+     * Reports the start index of this matcher's region. The
+     * searches this matcher conducts are limited to finding matches
+     * within {@link #regionStart regionStart} (inclusive) and
+     * {@link #regionEnd regionEnd} (exclusive).
+     *
+     * @return  The starting point of this matcher's region
+     * @since 1.5
+     */
+    public int regionStart() {
+        return from;
+    }
+
+    /**
+     * Reports the end index (exclusive) of this matcher's region.
+     * The searches this matcher conducts are limited to finding matches
+     * within {@link #regionStart regionStart} (inclusive) and
+     * {@link #regionEnd regionEnd} (exclusive).
+     *
+     * @return  the ending point of this matcher's region
+     * @since 1.5
+     */
+    public int regionEnd() {
+        return to;
+    }
+
+    /**
+     * Queries the transparency of region bounds for this matcher.
+     *
+     * <p> This method returns <tt>true</tt> if this matcher uses
+     * <i>transparent</i> bounds, <tt>false</tt> if it uses <i>opaque</i>
+     * bounds.
+     *
+     * <p> See {@link #useTransparentBounds useTransparentBounds} for a
+     * description of transparent and opaque bounds.
+     *
+     * <p> By default, a matcher uses opaque region boundaries.
+     *
+     * @return <tt>true</tt> iff this matcher is using transparent bounds,
+     *         <tt>false</tt> otherwise.
+     * @see java.util.regex.Matcher#useTransparentBounds(boolean)
+     * @since 1.5
+     */
+    public boolean hasTransparentBounds() {
+        return transparentBounds;
+    }
+
+    /**
+     * Sets the transparency of region bounds for this matcher.
+     *
+     * <p> Invoking this method with an argument of <tt>true</tt> will set this
+     * matcher to use <i>transparent</i> bounds. If the boolean
+     * argument is <tt>false</tt>, then <i>opaque</i> bounds will be used.
+     *
+     * <p> Using transparent bounds, the boundaries of this
+     * matcher's region are transparent to lookahead, lookbehind,
+     * and boundary matching constructs. Those constructs can see beyond the
+     * boundaries of the region to see if a match is appropriate.
+     *
+     * <p> Using opaque bounds, the boundaries of this matcher's
+     * region are opaque to lookahead, lookbehind, and boundary matching
+     * constructs that may try to see beyond them. Those constructs cannot
+     * look past the boundaries so they will fail to match anything outside
+     * of the region.
+     *
+     * <p> By default, a matcher uses opaque bounds.
+     *
+     * @param  b a boolean indicating whether to use opaque or transparent
+     *         regions
+     * @return this matcher
+     * @see java.util.regex.Matcher#hasTransparentBounds
+     * @since 1.5
+     */
+    public Matcher useTransparentBounds(boolean b) {
+        synchronized (this) {
+            transparentBounds = b;
+            nativeMatcher.useTransparentBounds(b);
+        }
+        return this;
+    }
+
+    /**
+     * Queries the anchoring of region bounds for this matcher.
+     *
+     * <p> This method returns <tt>true</tt> if this matcher uses
+     * <i>anchoring</i> bounds, <tt>false</tt> otherwise.
+     *
+     * <p> See {@link #useAnchoringBounds useAnchoringBounds} for a
+     * description of anchoring bounds.
+     *
+     * <p> By default, a matcher uses anchoring region boundaries.
+     *
+     * @return <tt>true</tt> iff this matcher is using anchoring bounds,
+     *         <tt>false</tt> otherwise.
+     * @see java.util.regex.Matcher#useAnchoringBounds(boolean)
+     * @since 1.5
+     */
+    public boolean hasAnchoringBounds() {
+        return anchoringBounds;
+    }
+
+    /**
+     * Sets the anchoring of region bounds for this matcher.
+     *
+     * <p> Invoking this method with an argument of <tt>true</tt> will set this
+     * matcher to use <i>anchoring</i> bounds. If the boolean
+     * argument is <tt>false</tt>, then <i>non-anchoring</i> bounds will be
+     * used.
+     *
+     * <p> Using anchoring bounds, the boundaries of this
+     * matcher's region match anchors such as ^ and $.
+     *
+     * <p> Without anchoring bounds, the boundaries of this
+     * matcher's region will not match anchors such as ^ and $.
+     *
+     * <p> By default, a matcher uses anchoring region boundaries.
+     *
+     * @param  b a boolean indicating whether or not to use anchoring bounds.
+     * @return this matcher
+     * @see java.util.regex.Matcher#hasAnchoringBounds
+     * @since 1.5
+     */
+    public Matcher useAnchoringBounds(boolean b) {
+        synchronized (this) {
+            anchoringBounds = b;
+            nativeMatcher.useAnchoringBounds(b);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Returns the string representation of this matcher. The
+     * string representation of a <code>Matcher</code> contains information
+     * that may be useful for debugging. The exact format is unspecified.
+     *
+     * @return  The string representation of this matcher
+     * @since 1.5
+     */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("java.util.regex.Matcher");
+        sb.append("[pattern=" + pattern());
+        sb.append(" region=");
+        sb.append(regionStart() + "," + regionEnd());
+        sb.append(" lastmatch=");
+        if (matchFound && (group() != null)) {
+            sb.append(group());
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    /**
+     * <p>Returns true if the end of input was hit by the search engine in
+     * the last match operation performed by this matcher.
+     *
+     * <p>When this method returns true, then it is possible that more input
+     * would have changed the result of the last search.
+     *
+     * @return  true iff the end of input was hit in the last match; false
+     *          otherwise
+     * @since 1.5
+     */
+    public boolean hitEnd() {
+        synchronized (this) {
+            return nativeMatcher.hitEnd();
+        }
+    }
+
+    /**
+     * <p>Returns true if more input could change a positive match into a
+     * negative one.
+     *
+     * <p>If this method returns true, and a match was found, then more
+     * input could cause the match to be lost. If this method returns false
+     * and a match was found, then more input might change the match but the
+     * match won't be lost. If a match was not found, then requireEnd has no
+     * meaning.
+     *
+     * @return  true iff more input could change a positive match into a
+     *          negative one.
+     * @since 1.5
+     */
+    public boolean requireEnd() {
+        synchronized (this) {
+            return nativeMatcher.requireEnd();
+        }
+    }
+
+    /**
+     * Returns the end index of the text.
+     *
+     * @return the index after the last character in the text
+     */
+    int getTextLength() {
+        return text.length();
+    }
+
+    /**
+     * Generates a String from this Matcher's input in the specified range.
+     *
+     * @param  beginIndex   the beginning index, inclusive
+     * @param  endIndex     the ending index, exclusive
+     * @return A String generated from this Matcher's input
+     */
+    CharSequence getSubSequence(int beginIndex, int endIndex) {
+        return text.subSequence(beginIndex, endIndex);
+    }
+
+    /**
+     * Resets the Matcher. A new input sequence and a new region can be
+     * specified. Results of a previous find get lost. The next attempt to find
+     * an occurrence of the Pattern in the string will start at the beginning of
+     * the region. This is the internal version of reset() to which the several
+     * public versions delegate.
+     *
+     * @param input
+     *            the input sequence.
+     * @param start
+     *            the start of the region.
+     * @param end
+     *            the end of the region.
+     *
+     * @return the matcher itself.
+     */
+    private Matcher reset(CharSequence input, int start, int end) {
+        if (input == null) {
+            throw new IllegalArgumentException("input == null");
+        }
+
+        if (start < 0 || end < 0 || start > input.length() || end > input.length() || start > end) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        this.originalInput = input;
+        this.text = input.toString();
+        this.from = start;
+        this.to = end;
+        resetForInput();
+
+        matchFound = false;
+        appendPos = 0;
+
+        return this;
+    }
+
+    private void resetForInput() {
+        synchronized (this) {
+            nativeMatcher.setInput(text, from, to);
+            nativeMatcher.useAnchoringBounds(anchoringBounds);
+            nativeMatcher.useTransparentBounds(transparentBounds);
+        }
+    }
+
+    /**
+     * Makes sure that a successful match has been made. Is invoked internally
+     * from various places in the class.
+     *
+     * @throws IllegalStateException
+     *             if no successful match has been made.
+     */
+    private void ensureMatch() {
+        if (!matchFound) {
+            throw new IllegalStateException("No successful match so far");
+        }
+    }
+
+    private int getMatchedGroupIndex(String name) {
+        ensureMatch();
+        int result = nativeMatcher.getMatchedGroupIndex(name);
+        if (result < 0) {
+            throw new IllegalArgumentException("No capturing group in the pattern " +
+                                               "with the name " + name);
+        }
+        return result;
+    }
+
+    /**
+     * A trivial match result implementation that's based on an array of integers
+     * representing match offsets. The array is of the form
+     * {@code { start1, end1, start2, end2 ....}) where each consecutive pair of elements represents
+     * the start and end of a match respectively.
+     */
+    static final class OffsetBasedMatchResult implements MatchResult {
+        private final String input;
+        private final int[] offsets;
+
+        OffsetBasedMatchResult(String input, int[] offsets) {
+            this.input = input;
+            this.offsets = offsets.clone();
+        }
+
+        @Override
+        public int start() {
+            return start(0);
+        }
+
+        @Override
+        public int start(int group) {
+            return offsets[2 * group];
+        }
+
+        @Override
+        public int end() {
+            return end(0);
+        }
+
+        @Override
+        public int end(int group) {
+            return offsets[2 * group + 1];
+        }
+
+        @Override
+        public String group() {
+            return group(0);
+        }
+
+        @Override
+        public String group(int group) {
+            final int start = start(group);
+            final int end = end(group);
+            if (start == -1 || end == -1) {
+                return null;
+            }
+
+            return input.substring(start, end);
+        }
+
+        @Override
+        public int groupCount() {
+            return (offsets.length / 2) - 1;
+        }
+    }
+}
diff --git a/java/util/regex/Pattern.annotated.java b/java/util/regex/Pattern.annotated.java
new file mode 100644
index 0000000..66db450
--- /dev/null
+++ b/java/util/regex/Pattern.annotated.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.regex;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Pattern implements java.io.Serializable {
+
+Pattern(@libcore.util.NonNull java.lang.String p, int f) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.regex.Pattern compile(@libcore.util.NonNull java.lang.String regex) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.regex.Pattern compile(@libcore.util.NonNull java.lang.String regex, int flags) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String pattern() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher matcher(@libcore.util.NonNull java.lang.CharSequence input) { throw new RuntimeException("Stub!"); }
+
+public int flags() { throw new RuntimeException("Stub!"); }
+
+public static boolean matches(@libcore.util.NonNull java.lang.String regex, @libcore.util.NonNull java.lang.CharSequence input) { throw new RuntimeException("Stub!"); }
+
+public [email protected] String @libcore.util.NonNull [] split(@libcore.util.NonNull java.lang.CharSequence input, int limit) { throw new RuntimeException("Stub!"); }
+
+public [email protected] String @libcore.util.NonNull [] split(@libcore.util.NonNull java.lang.CharSequence input) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String quote(@libcore.util.NonNull java.lang.String s) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.function.Predicate<[email protected] String> asPredicate() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.stream.Stream<[email protected] String> splitAsStream(@libcore.util.NonNull java.lang.CharSequence input) { throw new RuntimeException("Stub!"); }
+
+public static final int CANON_EQ = 128; // 0x80
+
+public static final int CASE_INSENSITIVE = 2; // 0x2
+
+public static final int COMMENTS = 4; // 0x4
+
+public static final int DOTALL = 32; // 0x20
+
+public static final int LITERAL = 16; // 0x10
+
+public static final int MULTILINE = 8; // 0x8
+
+public static final int UNICODE_CASE = 64; // 0x40
+
+public static final int UNICODE_CHARACTER_CLASS = 256; // 0x100
+
+public static final int UNIX_LINES = 1; // 0x1
+}
diff --git a/java/util/regex/Pattern.java b/java/util/regex/Pattern.java
new file mode 100644
index 0000000..a4ead58
--- /dev/null
+++ b/java/util/regex/Pattern.java
@@ -0,0 +1,1537 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+import com.android.icu.util.regex.PatternNative;
+import dalvik.system.VMRuntime;
+
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import libcore.util.EmptyArray;
+
+// Android-changed: Document that named capturing is only available from API 26.
+// Android-changed: Android always uses unicode character classes.
+// UNICODE_CHARACTER_CLASS has no effect on Android.
+/**
+ * A compiled representation of a regular expression.
+ *
+ * <p> A regular expression, specified as a string, must first be compiled into
+ * an instance of this class.  The resulting pattern can then be used to create
+ * a {@link Matcher} object that can match arbitrary {@linkplain
+ * java.lang.CharSequence character sequences} against the regular
+ * expression.  All of the state involved in performing a match resides in the
+ * matcher, so many matchers can share the same pattern.
+ *
+ * <p> A typical invocation sequence is thus
+ *
+ * <blockquote><pre>
+ * Pattern p = Pattern.{@link #compile compile}("a*b");
+ * Matcher m = p.{@link #matcher matcher}("aaaaab");
+ * boolean b = m.{@link Matcher#matches matches}();</pre></blockquote>
+ *
+ * <p> A {@link #matches matches} method is defined by this class as a
+ * convenience for when a regular expression is used just once.  This method
+ * compiles an expression and matches an input sequence against it in a single
+ * invocation.  The statement
+ *
+ * <blockquote><pre>
+ * boolean b = Pattern.matches("a*b", "aaaaab");</pre></blockquote>
+ *
+ * is equivalent to the three statements above, though for repeated matches it
+ * is less efficient since it does not allow the compiled pattern to be reused.
+ *
+ * <p> Instances of this class are immutable and are safe for use by multiple
+ * concurrent threads.  Instances of the {@link Matcher} class are not safe for
+ * such use.
+ *
+ *
+ * <h3><a name="sum">Summary of regular-expression constructs</a></h3>
+ *
+ * <table border="0" cellpadding="1" cellspacing="0"
+ *  summary="Regular expression constructs, and what they match">
+ *
+ * <tr align="left">
+ * <th align="left" id="construct">Construct</th>
+ * <th align="left" id="matches">Matches</th>
+ * </tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="characters">Characters</th></tr>
+ *
+ * <tr><td valign="top" headers="construct characters"><i>x</i></td>
+ *     <td headers="matches">The character <i>x</i></td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\\</tt></td>
+ *     <td headers="matches">The backslash character</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>n</i></td>
+ *     <td headers="matches">The character with octal value <tt>0</tt><i>n</i>
+ *         (0&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;7)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>nn</i></td>
+ *     <td headers="matches">The character with octal value <tt>0</tt><i>nn</i>
+ *         (0&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;7)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>mnn</i></td>
+ *     <td headers="matches">The character with octal value <tt>0</tt><i>mnn</i>
+ *         (0&nbsp;<tt>&lt;=</tt>&nbsp;<i>m</i>&nbsp;<tt>&lt;=</tt>&nbsp;3,
+ *         0&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;7)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\x</tt><i>hh</i></td>
+ *     <td headers="matches">The character with hexadecimal&nbsp;value&nbsp;<tt>0x</tt><i>hh</i></td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>&#92;u</tt><i>hhhh</i></td>
+ *     <td headers="matches">The character with hexadecimal&nbsp;value&nbsp;<tt>0x</tt><i>hhhh</i></td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>&#92;x</tt><i>{h...h}</i></td>
+ *     <td headers="matches">The character with hexadecimal&nbsp;value&nbsp;<tt>0x</tt><i>h...h</i>
+ *         ({@link java.lang.Character#MIN_CODE_POINT Character.MIN_CODE_POINT}
+ *         &nbsp;&lt;=&nbsp;<tt>0x</tt><i>h...h</i>&nbsp;&lt;=&nbsp;
+ *          {@link java.lang.Character#MAX_CODE_POINT Character.MAX_CODE_POINT})</td></tr>
+ * <tr><td valign="top" headers="matches"><tt>\t</tt></td>
+ *     <td headers="matches">The tab character (<tt>'&#92;u0009'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\n</tt></td>
+ *     <td headers="matches">The newline (line feed) character (<tt>'&#92;u000A'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\r</tt></td>
+ *     <td headers="matches">The carriage-return character (<tt>'&#92;u000D'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\f</tt></td>
+ *     <td headers="matches">The form-feed character (<tt>'&#92;u000C'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\a</tt></td>
+ *     <td headers="matches">The alert (bell) character (<tt>'&#92;u0007'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\e</tt></td>
+ *     <td headers="matches">The escape character (<tt>'&#92;u001B'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\c</tt><i>x</i></td>
+ *     <td headers="matches">The control character corresponding to <i>x</i></td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="classes">Character classes</th></tr>
+ *
+ * <tr><td valign="top" headers="construct classes">{@code [abc]}</td>
+ *     <td headers="matches">{@code a}, {@code b}, or {@code c} (simple class)</td></tr>
+ * <tr><td valign="top" headers="construct classes">{@code [^abc]}</td>
+ *     <td headers="matches">Any character except {@code a}, {@code b}, or {@code c} (negation)</td></tr>
+ * <tr><td valign="top" headers="construct classes">{@code [a-zA-Z]}</td>
+ *     <td headers="matches">{@code a} through {@code z}
+ *         or {@code A} through {@code Z}, inclusive (range)</td></tr>
+ * <tr><td valign="top" headers="construct classes">{@code [a-d[m-p]]}</td>
+ *     <td headers="matches">{@code a} through {@code d},
+ *      or {@code m} through {@code p}: {@code [a-dm-p]} (union)</td></tr>
+ * <tr><td valign="top" headers="construct classes">{@code [a-z&&[def]]}</td>
+ *     <td headers="matches">{@code d}, {@code e}, or {@code f} (intersection)</tr>
+ * <tr><td valign="top" headers="construct classes">{@code [a-z&&[^bc]]}</td>
+ *     <td headers="matches">{@code a} through {@code z},
+ *         except for {@code b} and {@code c}: {@code [ad-z]} (subtraction)</td></tr>
+ * <tr><td valign="top" headers="construct classes">{@code [a-z&&[^m-p]]}</td>
+ *     <td headers="matches">{@code a} through {@code z},
+ *          and not {@code m} through {@code p}: {@code [a-lq-z]}(subtraction)</td></tr>
+ * <tr><th>&nbsp;</th></tr>
+ *
+ * <tr align="left"><th colspan="2" id="predef">Predefined character classes</th></tr>
+ *
+ * <tr><td valign="top" headers="construct predef"><tt>.</tt></td>
+ *     <td headers="matches">Any character (may or may not match <a href="#lt">line terminators</a>)</td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\d</tt></td>
+ *     <td headers="matches">A digit: <tt>[0-9]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\D</tt></td>
+ *     <td headers="matches">A non-digit: <tt>[^0-9]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\h</tt></td>
+ *     <td headers="matches">A horizontal whitespace character:
+ *     <tt>[ \t\xA0&#92;u1680&#92;u180e&#92;u2000-&#92;u200a&#92;u202f&#92;u205f&#92;u3000]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\H</tt></td>
+ *     <td headers="matches">A non-horizontal whitespace character: <tt>[^\h]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\s</tt></td>
+ *     <td headers="matches">A whitespace character: <tt>[ \t\n\x0B\f\r]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\S</tt></td>
+ *     <td headers="matches">A non-whitespace character: <tt>[^\s]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\v</tt></td>
+ *     <td headers="matches">A vertical whitespace character: <tt>[\n\x0B\f\r\x85&#92;u2028&#92;u2029]</tt>
+ *     </td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\V</tt></td>
+ *     <td headers="matches">A non-vertical whitespace character: <tt>[^\v]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\w</tt></td>
+ *     <td headers="matches">A word character: <tt>[a-zA-Z_0-9]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\W</tt></td>
+ *     <td headers="matches">A non-word character: <tt>[^\w]</tt></td></tr>
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="posix"><b>POSIX character classes (US-ASCII only)</b></th></tr>
+ *
+ * <tr><td valign="top" headers="construct posix">{@code \p{Lower}}</td>
+ *     <td headers="matches">A lower-case alphabetic character: {@code [a-z]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Upper}}</td>
+ *     <td headers="matches">An upper-case alphabetic character:{@code [A-Z]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{ASCII}}</td>
+ *     <td headers="matches">All ASCII:{@code [\x00-\x7F]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Alpha}}</td>
+ *     <td headers="matches">An alphabetic character:{@code [\p{Lower}\p{Upper}]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Digit}}</td>
+ *     <td headers="matches">A decimal digit: {@code [0-9]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Alnum}}</td>
+ *     <td headers="matches">An alphanumeric character:{@code [\p{Alpha}\p{Digit}]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Punct}}</td>
+ *     <td headers="matches">Punctuation: One of {@code !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~}</td></tr>
+ *     <!-- {@code [\!"#\$%&'\(\)\*\+,\-\./:;\<=\>\?@\[\\\]\^_`\{\|\}~]}
+ *          {@code [\X21-\X2F\X31-\X40\X5B-\X60\X7B-\X7E]} -->
+ * <tr><td valign="top" headers="construct posix">{@code \p{Graph}}</td>
+ *     <td headers="matches">A visible character: {@code [\p{Alnum}\p{Punct}]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Print}}</td>
+ *     <td headers="matches">A printable character: {@code [\p{Graph}\x20]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Blank}}</td>
+ *     <td headers="matches">A space or a tab: {@code [ \t]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Cntrl}}</td>
+ *     <td headers="matches">A control character: {@code [\x00-\x1F\x7F]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{XDigit}}</td>
+ *     <td headers="matches">A hexadecimal digit: {@code [0-9a-fA-F]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Space}}</td>
+ *     <td headers="matches">A whitespace character: {@code [ \t\n\x0B\f\r]}</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2">java.lang.Character classes (simple <a href="#jcc">java character type</a>)</th></tr>
+ *
+ * <tr><td valign="top"><tt>\p{javaLowerCase}</tt></td>
+ *     <td>Equivalent to java.lang.Character.isLowerCase()</td></tr>
+ * <tr><td valign="top"><tt>\p{javaUpperCase}</tt></td>
+ *     <td>Equivalent to java.lang.Character.isUpperCase()</td></tr>
+ * <tr><td valign="top"><tt>\p{javaWhitespace}</tt></td>
+ *     <td>Equivalent to java.lang.Character.isWhitespace()</td></tr>
+ * <tr><td valign="top"><tt>\p{javaMirrored}</tt></td>
+ *     <td>Equivalent to java.lang.Character.isMirrored()</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="unicode">Classes for Unicode scripts, blocks, categories and binary properties</th></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \p{IsLatin}}</td>
+ *     <td headers="matches">A Latin&nbsp;script character (<a href="#usc">script</a>)</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \p{InGreek}}</td>
+ *     <td headers="matches">A character in the Greek&nbsp;block (<a href="#ubc">block</a>)</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \p{Lu}}</td>
+ *     <td headers="matches">An uppercase letter (<a href="#ucc">category</a>)</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \p{IsAlphabetic}}</td>
+ *     <td headers="matches">An alphabetic character (<a href="#ubpc">binary property</a>)</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \p{Sc}}</td>
+ *     <td headers="matches">A currency symbol</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \P{InGreek}}</td>
+ *     <td headers="matches">Any character except one in the Greek block (negation)</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code [\p{L}&&[^\p{Lu}]]}</td>
+ *     <td headers="matches">Any letter except an uppercase letter (subtraction)</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="bounds">Boundary matchers</th></tr>
+ *
+ * <tr><td valign="top" headers="construct bounds"><tt>^</tt></td>
+ *     <td headers="matches">The beginning of a line</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>$</tt></td>
+ *     <td headers="matches">The end of a line</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\b</tt></td>
+ *     <td headers="matches">A word boundary</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\B</tt></td>
+ *     <td headers="matches">A non-word boundary</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\A</tt></td>
+ *     <td headers="matches">The beginning of the input</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\G</tt></td>
+ *     <td headers="matches">The end of the previous match</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\Z</tt></td>
+ *     <td headers="matches">The end of the input but for the final
+ *         <a href="#lt">terminator</a>, if&nbsp;any</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\z</tt></td>
+ *     <td headers="matches">The end of the input</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="lineending">Linebreak matcher</th></tr>
+ * <tr><td valign="top" headers="construct lineending"><tt>\R</tt></td>
+ *     <td headers="matches">Any Unicode linebreak sequence, is equivalent to
+ *     <tt>&#92;u000D&#92;u000A|[&#92;u000A&#92;u000B&#92;u000C&#92;u000D&#92;u0085&#92;u2028&#92;u2029]
+ *     </tt></td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="greedy">Greedy quantifiers</th></tr>
+ *
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>?</tt></td>
+ *     <td headers="matches"><i>X</i>, once or not at all</td></tr>
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>*</tt></td>
+ *     <td headers="matches"><i>X</i>, zero or more times</td></tr>
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>+</tt></td>
+ *     <td headers="matches"><i>X</i>, one or more times</td></tr>
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>}</tt></td>
+ *     <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>,}</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="reluc">Reluctant quantifiers</th></tr>
+ *
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>??</tt></td>
+ *     <td headers="matches"><i>X</i>, once or not at all</td></tr>
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>*?</tt></td>
+ *     <td headers="matches"><i>X</i>, zero or more times</td></tr>
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>+?</tt></td>
+ *     <td headers="matches"><i>X</i>, one or more times</td></tr>
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>}?</tt></td>
+ *     <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>,}?</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}?</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="poss">Possessive quantifiers</th></tr>
+ *
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>?+</tt></td>
+ *     <td headers="matches"><i>X</i>, once or not at all</td></tr>
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>*+</tt></td>
+ *     <td headers="matches"><i>X</i>, zero or more times</td></tr>
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>++</tt></td>
+ *     <td headers="matches"><i>X</i>, one or more times</td></tr>
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>}+</tt></td>
+ *     <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>,}+</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}+</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="logical">Logical operators</th></tr>
+ *
+ * <tr><td valign="top" headers="construct logical"><i>XY</i></td>
+ *     <td headers="matches"><i>X</i> followed by <i>Y</i></td></tr>
+ * <tr><td valign="top" headers="construct logical"><i>X</i><tt>|</tt><i>Y</i></td>
+ *     <td headers="matches">Either <i>X</i> or <i>Y</i></td></tr>
+ * <tr><td valign="top" headers="construct logical"><tt>(</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches">X, as a <a href="#cg">capturing group</a></td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="backref">Back references</th></tr>
+ *
+ * <tr><td valign="bottom" headers="construct backref"><tt>\</tt><i>n</i></td>
+ *     <td valign="bottom" headers="matches">Whatever the <i>n</i><sup>th</sup>
+ *     <a href="#cg">capturing group</a> matched</td></tr>
+ *
+ * <tr><td valign="bottom" headers="construct backref"><tt>\</tt><i>k</i>&lt;<i>name</i>&gt;</td>
+ *     <td valign="bottom" headers="matches">Whatever the
+ *     <a href="#groupname">named-capturing group</a> "name" matched. Only available for API 26 or above</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="quot">Quotation</th></tr>
+ *
+ * <tr><td valign="top" headers="construct quot"><tt>\</tt></td>
+ *     <td headers="matches">Nothing, but quotes the following character</td></tr>
+ * <tr><td valign="top" headers="construct quot"><tt>\Q</tt></td>
+ *     <td headers="matches">Nothing, but quotes all characters until <tt>\E</tt></td></tr>
+ * <tr><td valign="top" headers="construct quot"><tt>\E</tt></td>
+ *     <td headers="matches">Nothing, but ends quoting started by <tt>\Q</tt></td></tr>
+ *     <!-- Metachars: !$()*+.<>?[\]^{|} -->
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="special">Special constructs (named-capturing and non-capturing)</th></tr>
+ *
+ * <tr><td valign="top" headers="construct special"><tt>(?&lt;<a href="#groupname">name</a>&gt;</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, as a named-capturing group. Only available for API 26 or above.</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?:</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, as a non-capturing group</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?idmsuxU-idmsuxU)&nbsp;</tt></td>
+ *     <td headers="matches">Nothing, but turns match flags <a href="#CASE_INSENSITIVE">i</a>
+ * <a href="#UNIX_LINES">d</a> <a href="#MULTILINE">m</a> <a href="#DOTALL">s</a>
+ * <a href="#UNICODE_CASE">u</a> <a href="#COMMENTS">x</a> <a href="#UNICODE_CHARACTER_CLASS">U</a>
+ * on - off</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?idmsux-idmsux:</tt><i>X</i><tt>)</tt>&nbsp;&nbsp;</td>
+ *     <td headers="matches"><i>X</i>, as a <a href="#cg">non-capturing group</a> with the
+ *         given flags <a href="#CASE_INSENSITIVE">i</a> <a href="#UNIX_LINES">d</a>
+ * <a href="#MULTILINE">m</a> <a href="#DOTALL">s</a> <a href="#UNICODE_CASE">u</a >
+ * <a href="#COMMENTS">x</a> on - off</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?=</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, via zero-width positive lookahead</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?!</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, via zero-width negative lookahead</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?&lt;=</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, via zero-width positive lookbehind</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?&lt;!</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, via zero-width negative lookbehind</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?&gt;</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, as an independent, non-capturing group</td></tr>
+ *
+ * </table>
+ *
+ * <hr>
+ *
+ *
+ * <h3><a name="bs">Backslashes, escapes, and quoting</a></h3>
+ *
+ * <p> The backslash character (<tt>'\'</tt>) serves to introduce escaped
+ * constructs, as defined in the table above, as well as to quote characters
+ * that otherwise would be interpreted as unescaped constructs.  Thus the
+ * expression <tt>\\</tt> matches a single backslash and <tt>\{</tt> matches a
+ * left brace.
+ *
+ * <p> It is an error to use a backslash prior to any alphabetic character that
+ * does not denote an escaped construct; these are reserved for future
+ * extensions to the regular-expression language.  A backslash may be used
+ * prior to a non-alphabetic character regardless of whether that character is
+ * part of an unescaped construct.
+ *
+ * <p> Backslashes within string literals in Java source code are interpreted
+ * as required by
+ * <cite>The Java&trade; Language Specification</cite>
+ * as either Unicode escapes (section 3.3) or other character escapes (section 3.10.6)
+ * It is therefore necessary to double backslashes in string
+ * literals that represent regular expressions to protect them from
+ * interpretation by the Java bytecode compiler.  The string literal
+ * <tt>"&#92;b"</tt>, for example, matches a single backspace character when
+ * interpreted as a regular expression, while <tt>"&#92;&#92;b"</tt> matches a
+ * word boundary.  The string literal <tt>"&#92;(hello&#92;)"</tt> is illegal
+ * and leads to a compile-time error; in order to match the string
+ * <tt>(hello)</tt> the string literal <tt>"&#92;&#92;(hello&#92;&#92;)"</tt>
+ * must be used.
+ *
+ * <h3><a name="cc">Character Classes</a></h3>
+ *
+ *    <p> Character classes may appear within other character classes, and
+ *    may be composed by the union operator (implicit) and the intersection
+ *    operator (<tt>&amp;&amp;</tt>).
+ *    The union operator denotes a class that contains every character that is
+ *    in at least one of its operand classes.  The intersection operator
+ *    denotes a class that contains every character that is in both of its
+ *    operand classes.
+ *
+ *    <p> The precedence of character-class operators is as follows, from
+ *    highest to lowest:
+ *
+ *    <blockquote><table border="0" cellpadding="1" cellspacing="0"
+ *                 summary="Precedence of character class operators.">
+ *      <tr><th>1&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *        <td>Literal escape&nbsp;&nbsp;&nbsp;&nbsp;</td>
+ *        <td><tt>\x</tt></td></tr>
+ *     <tr><th>2&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *        <td>Grouping</td>
+ *        <td><tt>[...]</tt></td></tr>
+ *     <tr><th>3&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *        <td>Range</td>
+ *        <td><tt>a-z</tt></td></tr>
+ *      <tr><th>4&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *        <td>Union</td>
+ *        <td><tt>[a-e][i-u]</tt></td></tr>
+ *      <tr><th>5&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *        <td>Intersection</td>
+ *        <td>{@code [a-z&&[aeiou]]}</td></tr>
+ *    </table></blockquote>
+ *
+ *    <p> Note that a different set of metacharacters are in effect inside
+ *    a character class than outside a character class. For instance, the
+ *    regular expression <tt>.</tt> loses its special meaning inside a
+ *    character class, while the expression <tt>-</tt> becomes a range
+ *    forming metacharacter.
+ *
+ * <h3><a name="lt">Line terminators</a></h3>
+ *
+ * <p> A <i>line terminator</i> is a one- or two-character sequence that marks
+ * the end of a line of the input character sequence.  The following are
+ * recognized as line terminators:
+ *
+ * <ul>
+ *
+ *   <li> A newline (line feed) character&nbsp;(<tt>'\n'</tt>),
+ *
+ *   <li> A carriage-return character followed immediately by a newline
+ *   character&nbsp;(<tt>"\r\n"</tt>),
+ *
+ *   <li> A standalone carriage-return character&nbsp;(<tt>'\r'</tt>),
+ *
+ *   <li> A next-line character&nbsp;(<tt>'&#92;u0085'</tt>),
+ *
+ *   <li> A line-separator character&nbsp;(<tt>'&#92;u2028'</tt>), or
+ *
+ *   <li> A paragraph-separator character&nbsp;(<tt>'&#92;u2029</tt>).
+ *
+ * </ul>
+ * <p>If {@link #UNIX_LINES} mode is activated, then the only line terminators
+ * recognized are newline characters.
+ *
+ * <p> The regular expression <tt>.</tt> matches any character except a line
+ * terminator unless the {@link #DOTALL} flag is specified.
+ *
+ * <p> By default, the regular expressions <tt>^</tt> and <tt>$</tt> ignore
+ * line terminators and only match at the beginning and the end, respectively,
+ * of the entire input sequence. If {@link #MULTILINE} mode is activated then
+ * <tt>^</tt> matches at the beginning of input and after any line terminator
+ * except at the end of input. When in {@link #MULTILINE} mode <tt>$</tt>
+ * matches just before a line terminator or the end of the input sequence.
+ *
+ * <h3><a name="cg">Groups and capturing</a></h3>
+ *
+ * <h4><a name="gnumber">Group number</a></h4>
+ * <p> Capturing groups are numbered by counting their opening parentheses from
+ * left to right.  In the expression <tt>((A)(B(C)))</tt>, for example, there
+ * are four such groups: </p>
+ *
+ * <blockquote><table cellpadding=1 cellspacing=0 summary="Capturing group numberings">
+ * <tr><th>1&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *     <td><tt>((A)(B(C)))</tt></td></tr>
+ * <tr><th>2&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *     <td><tt>(A)</tt></td></tr>
+ * <tr><th>3&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *     <td><tt>(B(C))</tt></td></tr>
+ * <tr><th>4&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *     <td><tt>(C)</tt></td></tr>
+ * </table></blockquote>
+ *
+ * <p> Group zero always stands for the entire expression.
+ *
+ * <p> Capturing groups are so named because, during a match, each subsequence
+ * of the input sequence that matches such a group is saved.  The captured
+ * subsequence may be used later in the expression, via a back reference, and
+ * may also be retrieved from the matcher once the match operation is complete.
+ *
+ * <h4><a name="groupname">Group name</a></h4>
+ * <p>The constructs and APIs are available since API level 26. A capturing group
+ * can also be assigned a "name", a <tt>named-capturing group</tt>,
+ * and then be back-referenced later by the "name". Group names are composed of
+ * the following characters. The first character must be a <tt>letter</tt>.
+ *
+ * <ul>
+ *   <li> The uppercase letters <tt>'A'</tt> through <tt>'Z'</tt>
+ *        (<tt>'&#92;u0041'</tt>&nbsp;through&nbsp;<tt>'&#92;u005a'</tt>),
+ *   <li> The lowercase letters <tt>'a'</tt> through <tt>'z'</tt>
+ *        (<tt>'&#92;u0061'</tt>&nbsp;through&nbsp;<tt>'&#92;u007a'</tt>),
+ *   <li> The digits <tt>'0'</tt> through <tt>'9'</tt>
+ *        (<tt>'&#92;u0030'</tt>&nbsp;through&nbsp;<tt>'&#92;u0039'</tt>),
+ * </ul>
+ *
+ * <p> A <tt>named-capturing group</tt> is still numbered as described in
+ * <a href="#gnumber">Group number</a>.
+ *
+ * <p> The captured input associated with a group is always the subsequence
+ * that the group most recently matched.  If a group is evaluated a second time
+ * because of quantification then its previously-captured value, if any, will
+ * be retained if the second evaluation fails.  Matching the string
+ * <tt>"aba"</tt> against the expression <tt>(a(b)?)+</tt>, for example, leaves
+ * group two set to <tt>"b"</tt>.  All captured input is discarded at the
+ * beginning of each match.
+ *
+ * <p> Groups beginning with <tt>(?</tt> are either pure, <i>non-capturing</i> groups
+ * that do not capture text and do not count towards the group total, or
+ * <i>named-capturing</i> group.
+ *
+ * <h3> Unicode support </h3>
+ *
+ * <p> This class is in conformance with Level 1 of <a
+ * href="http://www.unicode.org/reports/tr18/"><i>Unicode Technical
+ * Standard #18: Unicode Regular Expression</i></a>, plus RL2.1
+ * Canonical Equivalents.
+ * <p>
+ * <b>Unicode escape sequences</b> such as <tt>&#92;u2014</tt> in Java source code
+ * are processed as described in section 3.3 of
+ * <cite>The Java&trade; Language Specification</cite>.
+ * Such escape sequences are also implemented directly by the regular-expression
+ * parser so that Unicode escapes can be used in expressions that are read from
+ * files or from the keyboard.  Thus the strings <tt>"&#92;u2014"</tt> and
+ * <tt>"\\u2014"</tt>, while not equal, compile into the same pattern, which
+ * matches the character with hexadecimal value <tt>0x2014</tt>.
+ * <p>
+ * A Unicode character can also be represented in a regular-expression by
+ * using its <b>Hex notation</b>(hexadecimal code point value) directly as described in construct
+ * <tt>&#92;x{...}</tt>, for example a supplementary character U+2011F
+ * can be specified as <tt>&#92;x{2011F}</tt>, instead of two consecutive
+ * Unicode escape sequences of the surrogate pair
+ * <tt>&#92;uD840</tt><tt>&#92;uDD1F</tt>.
+ * <p>
+ * Unicode scripts, blocks, categories and binary properties are written with
+ * the <tt>\p</tt> and <tt>\P</tt> constructs as in Perl.
+ * <tt>\p{</tt><i>prop</i><tt>}</tt> matches if
+ * the input has the property <i>prop</i>, while <tt>\P{</tt><i>prop</i><tt>}</tt>
+ * does not match if the input has that property.
+ * <p>
+ * Scripts, blocks, categories and binary properties can be used both inside
+ * and outside of a character class.
+ *
+ * <p>
+ * <b><a name="usc">Scripts</a></b> are specified either with the prefix {@code Is}, as in
+ * {@code IsHiragana}, or by using  the {@code script} keyword (or its short
+ * form {@code sc})as in {@code script=Hiragana} or {@code sc=Hiragana}.
+ * <p>
+ * The script names supported by <code>Pattern</code> are the valid script names
+ * accepted and defined by
+ * {@link java.lang.Character.UnicodeScript#forName(String) UnicodeScript.forName}.
+ *
+ * <p>
+ * <b><a name="ubc">Blocks</a></b> are specified with the prefix {@code In}, as in
+ * {@code InMongolian}, or by using the keyword {@code block} (or its short
+ * form {@code blk}) as in {@code block=Mongolian} or {@code blk=Mongolian}.
+ * <p>
+ * The block names supported by <code>Pattern</code> are the valid block names
+ * accepted and defined by
+ * {@link java.lang.Character.UnicodeBlock#forName(String) UnicodeBlock.forName}.
+ * <p>
+ *
+ * <b><a name="ucc">Categories</a></b> may be specified with the optional prefix {@code Is}:
+ * Both {@code \p{L}} and {@code \p{IsL}} denote the category of Unicode
+ * letters. Same as scripts and blocks, categories can also be specified
+ * by using the keyword {@code general_category} (or its short form
+ * {@code gc}) as in {@code general_category=Lu} or {@code gc=Lu}.
+ * <p>
+ * The supported categories are those of
+ * <a href="http://www.unicode.org/unicode/standard/standard.html">
+ * <i>The Unicode Standard</i></a> in the version specified by the
+ * {@link java.lang.Character Character} class. The category names are those
+ * defined in the Standard, both normative and informative.
+ * <p>
+ *
+ * <b><a name="ubpc">Binary properties</a></b> are specified with the prefix {@code Is}, as in
+ * {@code IsAlphabetic}. The supported binary properties by <code>Pattern</code>
+ * are
+ * <ul>
+ *   <li> Alphabetic
+ *   <li> Ideographic
+ *   <li> Letter
+ *   <li> Lowercase
+ *   <li> Uppercase
+ *   <li> Titlecase
+ *   <li> Punctuation
+ *   <Li> Control
+ *   <li> White_Space
+ *   <li> Digit
+ *   <li> Hex_Digit
+ *   <li> Join_Control
+ *   <li> Noncharacter_Code_Point
+ *   <li> Assigned
+ * </ul>
+ * <p>
+ * The following <b>Predefined Character classes</b> and <b>POSIX character classes</b>
+ * are in conformance with the recommendation of <i>Annex C: Compatibility Properties</i>
+ * of <a href="http://www.unicode.org/reports/tr18/"><i>Unicode Regular Expression
+ * </i></a>.
+ *
+ * <table border="0" cellpadding="1" cellspacing="0"
+ *  summary="predefined and posix character classes in Unicode mode">
+ * <tr align="left">
+ * <th align="left" id="predef_classes">Classes</th>
+ * <th align="left" id="predef_matches">Matches</th>
+ *</tr>
+ * <tr><td><tt>\p{Lower}</tt></td>
+ *     <td>A lowercase character:<tt>\p{IsLowercase}</tt></td></tr>
+ * <tr><td><tt>\p{Upper}</tt></td>
+ *     <td>An uppercase character:<tt>\p{IsUppercase}</tt></td></tr>
+ * <tr><td><tt>\p{ASCII}</tt></td>
+ *     <td>All ASCII:<tt>[\x00-\x7F]</tt></td></tr>
+ * <tr><td><tt>\p{Alpha}</tt></td>
+ *     <td>An alphabetic character:<tt>\p{IsAlphabetic}</tt></td></tr>
+ * <tr><td><tt>\p{Digit}</tt></td>
+ *     <td>A decimal digit character:<tt>p{IsDigit}</tt></td></tr>
+ * <tr><td><tt>\p{Alnum}</tt></td>
+ *     <td>An alphanumeric character:<tt>[\p{IsAlphabetic}\p{IsDigit}]</tt></td></tr>
+ * <tr><td><tt>\p{Punct}</tt></td>
+ *     <td>A punctuation character:<tt>p{IsPunctuation}</tt></td></tr>
+ * <tr><td><tt>\p{Graph}</tt></td>
+ *     <td>A visible character: <tt>[^\p{IsWhite_Space}\p{gc=Cc}\p{gc=Cs}\p{gc=Cn}]</tt></td></tr>
+ * <tr><td><tt>\p{Print}</tt></td>
+ *     <td>A printable character: {@code [\p{Graph}\p{Blank}&&[^\p{Cntrl}]]}</td></tr>
+ * <tr><td><tt>\p{Blank}</tt></td>
+ *     <td>A space or a tab: {@code [\p{IsWhite_Space}&&[^\p{gc=Zl}\p{gc=Zp}\x0a\x0b\x0c\x0d\x85]]}</td></tr>
+ * <tr><td><tt>\p{Cntrl}</tt></td>
+ *     <td>A control character: <tt>\p{gc=Cc}</tt></td></tr>
+ * <tr><td><tt>\p{XDigit}</tt></td>
+ *     <td>A hexadecimal digit: <tt>[\p{gc=Nd}\p{IsHex_Digit}]</tt></td></tr>
+ * <tr><td><tt>\p{Space}</tt></td>
+ *     <td>A whitespace character:<tt>\p{IsWhite_Space}</tt></td></tr>
+ * <tr><td><tt>\d</tt></td>
+ *     <td>A digit: <tt>\p{IsDigit}</tt></td></tr>
+ * <tr><td><tt>\D</tt></td>
+ *     <td>A non-digit: <tt>[^\d]</tt></td></tr>
+ * <tr><td><tt>\s</tt></td>
+ *     <td>A whitespace character: <tt>\p{IsWhite_Space}</tt></td></tr>
+ * <tr><td><tt>\S</tt></td>
+ *     <td>A non-whitespace character: <tt>[^\s]</tt></td></tr>
+ * <tr><td><tt>\w</tt></td>
+ *     <td>A word character: <tt>[\p{Alpha}\p{gc=Mn}\p{gc=Me}\p{gc=Mc}\p{Digit}\p{gc=Pc}\p{IsJoin_Control}]</tt></td></tr>
+ * <tr><td><tt>\W</tt></td>
+ *     <td>A non-word character: <tt>[^\w]</tt></td></tr>
+ * </table>
+ * <p>
+ * <a name="jcc">
+ * Categories that behave like the java.lang.Character
+ * boolean is<i>methodname</i> methods (except for the deprecated ones) are
+ * available through the same <tt>\p{</tt><i>prop</i><tt>}</tt> syntax where
+ * the specified property has the name <tt>java<i>methodname</i></tt></a>.
+ *
+ * <h3> Comparison to Perl 5 </h3>
+ *
+ * <p>The <code>Pattern</code> engine performs traditional NFA-based matching
+ * with ordered alternation as occurs in Perl 5.
+ *
+ * <p> Perl constructs not supported by this class: </p>
+ *
+ * <ul>
+ *    <li><p> Predefined character classes (Unicode character)
+ *    <p><tt>\X&nbsp;&nbsp;&nbsp;&nbsp;</tt>Match Unicode
+ *    <a href="http://www.unicode.org/reports/tr18/#Default_Grapheme_Clusters">
+ *    <i>extended grapheme cluster</i></a>
+ *    </p></li>
+ *
+ *    <li><p> The backreference constructs, <tt>\g{</tt><i>n</i><tt>}</tt> for
+ *    the <i>n</i><sup>th</sup><a href="#cg">capturing group</a> and
+ *    <tt>\g{</tt><i>name</i><tt>}</tt> for
+ *    <a href="#groupname">named-capturing group</a>.
+ *    </p></li>
+ *
+ *    <li><p> The named character construct, <tt>\N{</tt><i>name</i><tt>}</tt>
+ *    for a Unicode character by its name.
+ *    </p></li>
+ *
+ *    <li><p> The conditional constructs
+ *    <tt>(?(</tt><i>condition</i><tt>)</tt><i>X</i><tt>)</tt> and
+ *    <tt>(?(</tt><i>condition</i><tt>)</tt><i>X</i><tt>|</tt><i>Y</i><tt>)</tt>,
+ *    </p></li>
+ *
+ *    <li><p> The embedded code constructs <tt>(?{</tt><i>code</i><tt>})</tt>
+ *    and <tt>(??{</tt><i>code</i><tt>})</tt>,</p></li>
+ *
+ *    <li><p> The embedded comment syntax <tt>(?#comment)</tt>, and </p></li>
+ *
+ *    <li><p> The preprocessing operations <tt>\l</tt> <tt>&#92;u</tt>,
+ *    <tt>\L</tt>, and <tt>\U</tt>.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Constructs supported by this class but not by Perl: </p>
+ *
+ * <ul>
+ *
+ *    <li><p> Character-class union and intersection as described
+ *    <a href="#cc">above</a>.</p></li>
+ *
+ * </ul>
+ *
+ * <p> Notable differences from Perl: </p>
+ *
+ * <ul>
+ *
+ *    <li><p> In Perl, <tt>\1</tt> through <tt>\9</tt> are always interpreted
+ *    as back references; a backslash-escaped number greater than <tt>9</tt> is
+ *    treated as a back reference if at least that many subexpressions exist,
+ *    otherwise it is interpreted, if possible, as an octal escape.  In this
+ *    class octal escapes must always begin with a zero. In this class,
+ *    <tt>\1</tt> through <tt>\9</tt> are always interpreted as back
+ *    references, and a larger number is accepted as a back reference if at
+ *    least that many subexpressions exist at that point in the regular
+ *    expression, otherwise the parser will drop digits until the number is
+ *    smaller or equal to the existing number of groups or it is one digit.
+ *    </p></li>
+ *
+ *    <li><p> Perl uses the <tt>g</tt> flag to request a match that resumes
+ *    where the last match left off.  This functionality is provided implicitly
+ *    by the {@link Matcher} class: Repeated invocations of the {@link
+ *    Matcher#find find} method will resume where the last match left off,
+ *    unless the matcher is reset.  </p></li>
+ *
+ *    <li><p> In Perl, embedded flags at the top level of an expression affect
+ *    the whole expression.  In this class, embedded flags always take effect
+ *    at the point at which they appear, whether they are at the top level or
+ *    within a group; in the latter case, flags are restored at the end of the
+ *    group just as in Perl.  </p></li>
+ *
+ * </ul>
+ *
+ *
+ * <p> For a more precise description of the behavior of regular expression
+ * constructs, please see <a href="http://www.oreilly.com/catalog/regex3/">
+ * <i>Mastering Regular Expressions, 3nd Edition</i>, Jeffrey E. F. Friedl,
+ * O'Reilly and Associates, 2006.</a>
+ * </p>
+ *
+ * @see java.lang.String#split(String, int)
+ * @see java.lang.String#split(String)
+ *
+ * @author      Mike McCloskey
+ * @author      Mark Reinhold
+ * @author      JSR-51 Expert Group
+ * @since       1.4
+ * @spec        JSR-51
+ */
+
+public final class Pattern
+    implements java.io.Serializable
+{
+
+    /**
+     * Regular expression modifier values.  Instead of being passed as
+     * arguments, they can also be passed as inline modifiers.
+     * For example, the following statements have the same effect.
+     * <pre>
+     * RegExp r1 = RegExp.compile("abc", Pattern.I|Pattern.M);
+     * RegExp r2 = RegExp.compile("(?im)abc", 0);
+     * </pre>
+     *
+     * The flags are duplicated so that the familiar Perl match flag
+     * names are available.
+     */
+
+    /**
+     * Enables Unix lines mode.
+     *
+     * <p> In this mode, only the <tt>'\n'</tt> line terminator is recognized
+     * in the behavior of <tt>.</tt>, <tt>^</tt>, and <tt>$</tt>.
+     *
+     * <p> Unix lines mode can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?d)</tt>.
+     */
+    public static final int UNIX_LINES = 0x01;
+
+    /**
+     * Enables case-insensitive matching.
+     *
+     * <p> By default, case-insensitive matching assumes that only characters
+     * in the US-ASCII charset are being matched.  Unicode-aware
+     * case-insensitive matching can be enabled by specifying the {@link
+     * #UNICODE_CASE} flag in conjunction with this flag.
+     *
+     * <p> Case-insensitive matching can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?i)</tt>.
+     *
+     * <p> Specifying this flag may impose a slight performance penalty.  </p>
+     */
+    public static final int CASE_INSENSITIVE = 0x02;
+
+    /**
+     * Permits whitespace and comments in pattern.
+     *
+     * <p> In this mode, whitespace is ignored, and embedded comments starting
+     * with <tt>#</tt> are ignored until the end of a line.
+     *
+     * <p> Comments mode can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?x)</tt>.
+     */
+    public static final int COMMENTS = 0x04;
+
+    /**
+     * Enables multiline mode.
+     *
+     * <p> In multiline mode the expressions <tt>^</tt> and <tt>$</tt> match
+     * just after or just before, respectively, a line terminator or the end of
+     * the input sequence.  By default these expressions only match at the
+     * beginning and the end of the entire input sequence.
+     *
+     * <p> Multiline mode can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?m)</tt>.  </p>
+     */
+    public static final int MULTILINE = 0x08;
+
+    /**
+     * Enables literal parsing of the pattern.
+     *
+     * <p> When this flag is specified then the input string that specifies
+     * the pattern is treated as a sequence of literal characters.
+     * Metacharacters or escape sequences in the input sequence will be
+     * given no special meaning.
+     *
+     * <p>The flags CASE_INSENSITIVE and UNICODE_CASE retain their impact on
+     * matching when used in conjunction with this flag. The other flags
+     * become superfluous.
+     *
+     * <p> There is no embedded flag character for enabling literal parsing.
+     * @since 1.5
+     */
+    public static final int LITERAL = 0x10;
+
+    /**
+     * Enables dotall mode.
+     *
+     * <p> In dotall mode, the expression <tt>.</tt> matches any character,
+     * including a line terminator.  By default this expression does not match
+     * line terminators.
+     *
+     * <p> Dotall mode can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?s)</tt>.  (The <tt>s</tt> is a mnemonic for
+     * "single-line" mode, which is what this is called in Perl.)  </p>
+     */
+    public static final int DOTALL = 0x20;
+
+    /**
+     * Enables Unicode-aware case folding.
+     *
+     * <p> When this flag is specified then case-insensitive matching, when
+     * enabled by the {@link #CASE_INSENSITIVE} flag, is done in a manner
+     * consistent with the Unicode Standard.  By default, case-insensitive
+     * matching assumes that only characters in the US-ASCII charset are being
+     * matched.
+     *
+     * <p> Unicode-aware case folding can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?u)</tt>.
+     *
+     * <p> Specifying this flag may impose a performance penalty.  </p>
+     */
+    public static final int UNICODE_CASE = 0x40;
+
+    /**
+     * Enables canonical equivalence.
+     *
+     * <p> When this flag is specified then two characters will be considered
+     * to match if, and only if, their full canonical decompositions match.
+     * The expression <tt>"a&#92;u030A"</tt>, for example, will match the
+     * string <tt>"&#92;u00E5"</tt> when this flag is specified.  By default,
+     * matching does not take canonical equivalence into account.
+     *
+     * <p> There is no embedded flag character for enabling canonical
+     * equivalence.
+     *
+     * <p> Specifying this flag may impose a performance penalty.  </p>
+     */
+    public static final int CANON_EQ = 0x80;
+
+    // Android-changed: Android always uses unicode character classes.
+    /**
+     * Enables the Unicode version of <i>Predefined character classes</i> and
+     * <i>POSIX character classes</i> as defined by <a href="http://www.unicode.org/reports/tr18/"><i>Unicode Technical
+     * Standard #18: Unicode Regular Expression</i></a>
+     * <i>Annex C: Compatibility Properties</i>.
+     * <p>
+     *
+     * This flag has no effect on Android, unicode character classes are always
+     * used.
+     *
+     * @since 1.7
+     */
+    public static final int UNICODE_CHARACTER_CLASS = 0x100;
+
+    /* Pattern has only two serialized components: The pattern string
+     * and the flags, which are all that is needed to recompile the pattern
+     * when it is deserialized.
+     */
+
+    /** use serialVersionUID from Merlin b59 for interoperability */
+    private static final long serialVersionUID = 5073258162644648461L;
+
+    /**
+     * The original regular-expression pattern string.
+     *
+     * @serial
+     */
+    // Android-changed: reimplement matching logic natively via ICU.
+    // private String pattern;
+    private final String pattern;
+
+    /**
+     * The original pattern flags.
+     *
+     * @serial
+     */
+    // Android-changed: reimplement matching logic natively via ICU.
+    // private int flags;
+    private final int flags;
+
+    // BEGIN Android-changed: reimplement matching logic natively via ICU.
+    // We only need some tie-ins to native memory, instead of a large number
+    // of fields on the .java side.
+    /* package */ transient PatternNative nativePattern;
+    // END Android-changed: reimplement matching logic natively via ICU.
+
+    /**
+     * Compiles the given regular expression into a pattern.
+     *
+     * @param  regex
+     *         The expression to be compiled
+     * @return the given regular expression compiled into a pattern
+     * @throws  PatternSyntaxException
+     *          If the expression's syntax is invalid
+     */
+    public static Pattern compile(String regex) {
+        return new Pattern(regex, 0);
+    }
+
+    /**
+     * Compiles the given regular expression into a pattern with the given
+     * flags.
+     *
+     * @param  regex
+     *         The expression to be compiled
+     *
+     * @param  flags
+     *         Match flags, a bit mask that may include
+     *         {@link #CASE_INSENSITIVE}, {@link #MULTILINE}, {@link #DOTALL},
+     *         {@link #UNICODE_CASE}, {@link #CANON_EQ}, {@link #UNIX_LINES},
+     *         {@link #LITERAL}, {@link #UNICODE_CHARACTER_CLASS}
+     *         and {@link #COMMENTS}
+     *
+     * @return the given regular expression compiled into a pattern with the given flags
+     * @throws  IllegalArgumentException
+     *          If bit values other than those corresponding to the defined
+     *          match flags are set in <tt>flags</tt>
+     *
+     * @throws  PatternSyntaxException
+     *          If the expression's syntax is invalid
+     */
+    public static Pattern compile(String regex, int flags) {
+        return new Pattern(regex, flags);
+    }
+
+    /**
+     * Returns the regular expression from which this pattern was compiled.
+     *
+     * @return  The source of this pattern
+     */
+    public String pattern() {
+        return pattern;
+    }
+
+    /**
+     * <p>Returns the string representation of this pattern. This
+     * is the regular expression from which this pattern was
+     * compiled.</p>
+     *
+     * @return  The string representation of this pattern
+     * @since 1.5
+     */
+    public String toString() {
+        return pattern;
+    }
+
+    /**
+     * Creates a matcher that will match the given input against this pattern.
+     *
+     * @param  input
+     *         The character sequence to be matched
+     *
+     * @return  A new matcher for this pattern
+     */
+    public Matcher matcher(CharSequence input) {
+        // Android-removed: Pattern is eagerly compiled() upon construction.
+        /*
+        if (!compiled) {
+            synchronized(this) {
+                if (!compiled)
+                    compile();
+            }
+        }
+        */
+        Matcher m = new Matcher(this, input);
+        return m;
+    }
+
+    /**
+     * Returns this pattern's match flags.
+     *
+     * @return  The match flags specified when this pattern was compiled
+     */
+    public int flags() {
+        return flags;
+    }
+
+    /**
+     * Compiles the given regular expression and attempts to match the given
+     * input against it.
+     *
+     * <p> An invocation of this convenience method of the form
+     *
+     * <blockquote><pre>
+     * Pattern.matches(regex, input);</pre></blockquote>
+     *
+     * behaves in exactly the same way as the expression
+     *
+     * <blockquote><pre>
+     * Pattern.compile(regex).matcher(input).matches()</pre></blockquote>
+     *
+     * <p> If a pattern is to be used multiple times, compiling it once and reusing
+     * it will be more efficient than invoking this method each time.  </p>
+     *
+     * @param  regex
+     *         The expression to be compiled
+     *
+     * @param  input
+     *         The character sequence to be matched
+     * @return whether or not the regular expression matches on the input
+     * @throws  PatternSyntaxException
+     *          If the expression's syntax is invalid
+     */
+    public static boolean matches(String regex, CharSequence input) {
+        Pattern p = Pattern.compile(regex);
+        Matcher m = p.matcher(input);
+        return m.matches();
+    }
+
+    // Android-changed: Adopt split() behavior change only for apps targeting API > 28.
+    // http://b/109659282#comment7
+    /**
+     * Splits the given input sequence around matches of this pattern.
+     *
+     * <p> The array returned by this method contains each substring of the
+     * input sequence that is terminated by another subsequence that matches
+     * this pattern or is terminated by the end of the input sequence.  The
+     * substrings in the array are in the order in which they occur in the
+     * input. If this pattern does not match any subsequence of the input then
+     * the resulting array has just one element, namely the input sequence in
+     * string form.
+     *
+     * <p> When there is a positive-width match at the beginning of the input
+     * sequence then an empty leading substring is included at the beginning
+     * of the resulting array. A zero-width match at the beginning however
+     * can only produce such an empty leading substring for apps running on or
+     * targeting API versions <= 28.
+     *
+     * <p> The <tt>limit</tt> parameter controls the number of times the
+     * pattern is applied and therefore affects the length of the resulting
+     * array.  If the limit <i>n</i> is greater than zero then the pattern
+     * will be applied at most <i>n</i>&nbsp;-&nbsp;1 times, the array's
+     * length will be no greater than <i>n</i>, and the array's last entry
+     * will contain all input beyond the last matched delimiter.  If <i>n</i>
+     * is non-positive then the pattern will be applied as many times as
+     * possible and the array can have any length.  If <i>n</i> is zero then
+     * the pattern will be applied as many times as possible, the array can
+     * have any length, and trailing empty strings will be discarded.
+     *
+     * <p> The input <tt>"boo:and:foo"</tt>, for example, yields the following
+     * results with these parameters:
+     *
+     * <blockquote><table cellpadding=1 cellspacing=0
+     *              summary="Split examples showing regex, limit, and result">
+     * <tr><th align="left"><i>Regex&nbsp;&nbsp;&nbsp;&nbsp;</i></th>
+     *     <th align="left"><i>Limit&nbsp;&nbsp;&nbsp;&nbsp;</i></th>
+     *     <th align="left"><i>Result&nbsp;&nbsp;&nbsp;&nbsp;</i></th></tr>
+     * <tr><td align=center>:</td>
+     *     <td align=center>2</td>
+     *     <td><tt>{ "boo", "and:foo" }</tt></td></tr>
+     * <tr><td align=center>:</td>
+     *     <td align=center>5</td>
+     *     <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
+     * <tr><td align=center>:</td>
+     *     <td align=center>-2</td>
+     *     <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
+     * <tr><td align=center>o</td>
+     *     <td align=center>5</td>
+     *     <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
+     * <tr><td align=center>o</td>
+     *     <td align=center>-2</td>
+     *     <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
+     * <tr><td align=center>o</td>
+     *     <td align=center>0</td>
+     *     <td><tt>{ "b", "", ":and:f" }</tt></td></tr>
+     * </table></blockquote>
+     *
+     * @param  input
+     *         The character sequence to be split
+     *
+     * @param  limit
+     *         The result threshold, as described above
+     *
+     * @return  The array of strings computed by splitting the input
+     *          around matches of this pattern
+     */
+    public String[] split(CharSequence input, int limit) {
+        // BEGIN Android-added: fastSplit() to speed up simple cases.
+        String[] fast = fastSplit(pattern, input.toString(), limit);
+        if (fast != null) {
+            return fast;
+        }
+        // END Android-added: fastSplit() to speed up simple cases.
+        int index = 0;
+        boolean matchLimited = limit > 0;
+        ArrayList<String> matchList = new ArrayList<>();
+        Matcher m = matcher(input);
+
+        // Add segments before each match found
+        while(m.find()) {
+            if (!matchLimited || matchList.size() < limit - 1) {
+                if (index == 0 && index == m.start() && m.start() == m.end()) {
+                    // no empty leading substring included for zero-width match
+                    // at the beginning of the input char sequence.
+                    // BEGIN Android-changed: split() compat behavior for apps targeting <= 28.
+                    // continue;
+                    int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+                    if (targetSdkVersion > 28) {
+                        continue;
+                    }
+                    // END Android-changed: split() compat behavior for apps targeting <= 28.
+                }
+                String match = input.subSequence(index, m.start()).toString();
+                matchList.add(match);
+                index = m.end();
+            } else if (matchList.size() == limit - 1) { // last one
+                String match = input.subSequence(index,
+                                                 input.length()).toString();
+                matchList.add(match);
+                index = m.end();
+            }
+        }
+
+        // If no match was found, return this
+        if (index == 0)
+            return new String[] {input.toString()};
+
+        // Add remaining segment
+        if (!matchLimited || matchList.size() < limit)
+            matchList.add(input.subSequence(index, input.length()).toString());
+
+        // Construct result
+        int resultSize = matchList.size();
+        if (limit == 0)
+            while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
+                resultSize--;
+        String[] result = new String[resultSize];
+        return matchList.subList(0, resultSize).toArray(result);
+    }
+
+    // BEGIN Android-added: fastSplit() to speed up simple cases.
+    private static final String FASTSPLIT_METACHARACTERS = "\\?*+[](){}^$.|";
+
+    /**
+     * Returns a result equivalent to {@code s.split(separator, limit)} if it's able
+     * to compute it more cheaply than native impl, or null if the caller should fall back to
+     * using native impl.
+     *
+     *  fastpath will work  if the regex is a
+     *   (1)one-char String and this character is not one of the
+     *      RegEx's meta characters ".$|()[{^?*+\\", or
+     *   (2)two-char String and the first char is the backslash and
+     *      the second is one of regEx's meta characters ".$|()[{^?*+\\".
+     * @hide
+     */
+    public static String[] fastSplit(String re, String input, int limit) {
+        // Can we do it cheaply?
+        int len = re.length();
+        if (len == 0) {
+            return null;
+        }
+        char ch = re.charAt(0);
+        if (len == 1 && FASTSPLIT_METACHARACTERS.indexOf(ch) == -1) {
+            // We're looking for a single non-metacharacter. Easy.
+        } else if (len == 2 && ch == '\\') {
+            // We're looking for a quoted character.
+            // Quoted metacharacters are effectively single non-metacharacters.
+            ch = re.charAt(1);
+            if (FASTSPLIT_METACHARACTERS.indexOf(ch) == -1) {
+                return null;
+            }
+        } else {
+            return null;
+        }
+
+        // We can do this cheaply...
+
+        // Unlike Perl, which considers the result of splitting the empty string to be the empty
+        // array, Java returns an array containing the empty string.
+        if (input.isEmpty()) {
+            return new String[] { "" };
+        }
+
+        // Count separators
+        int separatorCount = 0;
+        int begin = 0;
+        int end;
+        while (separatorCount + 1 != limit && (end = input.indexOf(ch, begin)) != -1) {
+            ++separatorCount;
+            begin = end + 1;
+        }
+        int lastPartEnd = input.length();
+        if (limit == 0 && begin == lastPartEnd) {
+            // Last part is empty for limit == 0, remove all trailing empty matches.
+            if (separatorCount == lastPartEnd) {
+                // Input contains only separators.
+                return EmptyArray.STRING;
+            }
+            // Find the beginning of trailing separators.
+            do {
+                --begin;
+            } while (input.charAt(begin - 1) == ch);
+            // Reduce separatorCount and fix lastPartEnd.
+            separatorCount -= input.length() - begin;
+            lastPartEnd = begin;
+        }
+
+        // Collect the result parts.
+        String[] result = new String[separatorCount + 1];
+        begin = 0;
+        for (int i = 0; i != separatorCount; ++i) {
+            end = input.indexOf(ch, begin);
+            result[i] = input.substring(begin, end);
+            begin = end + 1;
+        }
+        // Add last part.
+        result[separatorCount] = input.substring(begin, lastPartEnd);
+        return result;
+    }
+    // END Android-added: fastSplit() to speed up simple cases.
+
+    /**
+     * Splits the given input sequence around matches of this pattern.
+     *
+     * <p> This method works as if by invoking the two-argument {@link
+     * #split(java.lang.CharSequence, int) split} method with the given input
+     * sequence and a limit argument of zero.  Trailing empty strings are
+     * therefore not included in the resulting array. </p>
+     *
+     * <p> The input <tt>"boo:and:foo"</tt>, for example, yields the following
+     * results with these expressions:
+     *
+     * <blockquote><table cellpadding=1 cellspacing=0
+     *              summary="Split examples showing regex and result">
+     * <tr><th align="left"><i>Regex&nbsp;&nbsp;&nbsp;&nbsp;</i></th>
+     *     <th align="left"><i>Result</i></th></tr>
+     * <tr><td align=center>:</td>
+     *     <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
+     * <tr><td align=center>o</td>
+     *     <td><tt>{ "b", "", ":and:f" }</tt></td></tr>
+     * </table></blockquote>
+     *
+     *
+     * @param  input
+     *         The character sequence to be split
+     *
+     * @return  The array of strings computed by splitting the input
+     *          around matches of this pattern
+     */
+    public String[] split(CharSequence input) {
+        return split(input, 0);
+    }
+
+    /**
+     * Returns a literal pattern <code>String</code> for the specified
+     * <code>String</code>.
+     *
+     * <p>This method produces a <code>String</code> that can be used to
+     * create a <code>Pattern</code> that would match the string
+     * <code>s</code> as if it were a literal pattern.</p> Metacharacters
+     * or escape sequences in the input sequence will be given no special
+     * meaning.
+     *
+     * @param  s The string to be literalized
+     * @return  A literal string replacement
+     * @since 1.5
+     */
+    public static String quote(String s) {
+        int slashEIndex = s.indexOf("\\E");
+        if (slashEIndex == -1)
+            return "\\Q" + s + "\\E";
+
+        StringBuilder sb = new StringBuilder(s.length() * 2);
+        sb.append("\\Q");
+        slashEIndex = 0;
+        int current = 0;
+        while ((slashEIndex = s.indexOf("\\E", current)) != -1) {
+            sb.append(s.substring(current, slashEIndex));
+            current = slashEIndex + 2;
+            sb.append("\\E\\\\E\\Q");
+        }
+        sb.append(s.substring(current, s.length()));
+        sb.append("\\E");
+        return sb.toString();
+    }
+
+    /**
+     * Recompile the Pattern instance from a stream.  The original pattern
+     * string is read in and the object tree is recompiled from it.
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        // Read in all fields
+        s.defaultReadObject();
+
+        // Android-removed: reimplement matching logic natively via ICU.
+        // // Initialize counts
+        // capturingGroupCount = 1;
+        // localCount = 0;
+
+        // Android-changed: Pattern is eagerly compiled() upon construction.
+        /*
+        // if length > 0, the Pattern is lazily compiled
+        compiled = false;
+        if (pattern.length() == 0) {
+            root = new Start(lastAccept);
+            matchRoot = lastAccept;
+            compiled = true;
+        }
+        */
+        compile();
+    }
+
+    // Android-changed: reimplement matching logic natively via ICU.
+    // Dropped documentation reference to Start and LastNode implementation
+    // details which do not apply on Android.
+    /**
+     * This private constructor is used to create all Patterns. The pattern
+     * string and match flags are all that is needed to completely describe
+     * a Pattern.
+     */
+    private Pattern(String p, int f) {
+        pattern = p;
+        flags = f;
+
+        // BEGIN Android-changed: Only specific flags are supported.
+        /*
+        // to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
+        if ((flags & UNICODE_CHARACTER_CLASS) != 0)
+            flags |= UNICODE_CASE;
+
+        // Reset group index count
+        capturingGroupCount = 1;
+        localCount = 0;
+        */
+        if ((f & CANON_EQ) != 0) {
+            throw new UnsupportedOperationException("CANON_EQ flag not supported");
+        }
+        int supportedFlags = CASE_INSENSITIVE | COMMENTS | DOTALL | LITERAL | MULTILINE | UNICODE_CASE | UNIX_LINES;
+        if ((f & ~supportedFlags) != 0) {
+            throw new IllegalArgumentException("Unsupported flags: " + (f & ~supportedFlags));
+        }
+        // END Android-changed: Only specific flags are supported.
+
+        // BEGIN Android-removed: Pattern is eagerly compiled() upon construction.
+        // if (pattern.length() > 0) {
+        // END Android-removed: Pattern is eagerly compiled() upon construction.
+            compile();
+        // Android-removed: reimplement matching logic natively via ICU.
+        /*
+        } else {
+            root = new Start(lastAccept);
+            matchRoot = lastAccept;
+        }
+        */
+    }
+
+    // BEGIN Android-changed: reimplement matching logic natively via ICU.
+    // Use native implementation instead of > 3000 lines of helper methods.
+    private void compile() throws PatternSyntaxException {
+        if (pattern == null) {
+            throw new NullPointerException("pattern == null");
+        }
+
+        String icuPattern = pattern;
+        if ((flags & LITERAL) != 0) {
+            icuPattern = quote(pattern);
+        }
+
+        // These are the flags natively supported by ICU.
+        // They even have the same value in native code.
+        int icuFlags = flags & (CASE_INSENSITIVE | COMMENTS | MULTILINE | DOTALL | UNIX_LINES);
+        nativePattern = PatternNative.create(icuPattern, icuFlags);
+    }
+    // END Android-changed: reimplement matching logic natively via ICU.
+
+    /**
+     * Creates a predicate which can be used to match a string.
+     *
+     * @return  The predicate which can be used for matching on a string
+     * @since   1.8
+     */
+    public Predicate<String> asPredicate() {
+        return s -> matcher(s).find();
+    }
+
+    /**
+     * Creates a stream from the given input sequence around matches of this
+     * pattern.
+     *
+     * <p> The stream returned by this method contains each substring of the
+     * input sequence that is terminated by another subsequence that matches
+     * this pattern or is terminated by the end of the input sequence.  The
+     * substrings in the stream are in the order in which they occur in the
+     * input. Trailing empty strings will be discarded and not encountered in
+     * the stream.
+     *
+     * <p> If this pattern does not match any subsequence of the input then
+     * the resulting stream has just one element, namely the input sequence in
+     * string form.
+     *
+     * <p> When there is a positive-width match at the beginning of the input
+     * sequence then an empty leading substring is included at the beginning
+     * of the stream. A zero-width match at the beginning however never produces
+     * such empty leading substring.
+     *
+     * <p> If the input sequence is mutable, it must remain constant during the
+     * execution of the terminal stream operation.  Otherwise, the result of the
+     * terminal stream operation is undefined.
+     *
+     * @param   input
+     *          The character sequence to be split
+     *
+     * @return  The stream of strings computed by splitting the input
+     *          around matches of this pattern
+     * @see     #split(CharSequence)
+     * @since   1.8
+     */
+    public Stream<String> splitAsStream(final CharSequence input) {
+        class MatcherIterator implements Iterator<String> {
+            private final Matcher matcher;
+            // The start position of the next sub-sequence of input
+            // when current == input.length there are no more elements
+            private int current;
+            // null if the next element, if any, needs to obtained
+            private String nextElement;
+            // > 0 if there are N next empty elements
+            private int emptyElementCount;
+
+            MatcherIterator() {
+                this.matcher = matcher(input);
+            }
+
+            public String next() {
+                if (!hasNext())
+                    throw new NoSuchElementException();
+
+                if (emptyElementCount == 0) {
+                    String n = nextElement;
+                    nextElement = null;
+                    return n;
+                } else {
+                    emptyElementCount--;
+                    return "";
+                }
+            }
+
+            public boolean hasNext() {
+                if (nextElement != null || emptyElementCount > 0)
+                    return true;
+
+                if (current == input.length())
+                    return false;
+
+                // Consume the next matching element
+                // Count sequence of matching empty elements
+                while (matcher.find()) {
+                    nextElement = input.subSequence(current, matcher.start()).toString();
+                    current = matcher.end();
+                    if (!nextElement.isEmpty()) {
+                        return true;
+                    } else if (current > 0) { // no empty leading substring for zero-width
+                                              // match at the beginning of the input
+                        emptyElementCount++;
+                    }
+                }
+
+                // Consume last matching element
+                nextElement = input.subSequence(current, input.length()).toString();
+                current = input.length();
+                if (!nextElement.isEmpty()) {
+                    return true;
+                } else {
+                    // Ignore a terminal sequence of matching empty elements
+                    emptyElementCount = 0;
+                    nextElement = null;
+                    return false;
+                }
+            }
+        }
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+                new MatcherIterator(), Spliterator.ORDERED | Spliterator.NONNULL), false);
+    }
+}
diff --git a/java/util/regex/PatternSyntaxException.java b/java/util/regex/PatternSyntaxException.java
new file mode 100644
index 0000000..d6ac72a
--- /dev/null
+++ b/java/util/regex/PatternSyntaxException.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+import sun.security.action.GetPropertyAction;
+
+
+/**
+ * Unchecked exception thrown to indicate a syntax error in a
+ * regular-expression pattern.
+ *
+ * @author  unascribed
+ * @since 1.4
+ * @spec JSR-51
+ */
+
+public class PatternSyntaxException
+    extends IllegalArgumentException
+{
+    private static final long serialVersionUID = -3864639126226059218L;
+
+    private final String desc;
+    private final String pattern;
+    private final int index;
+
+    /**
+     * Constructs a new instance of this class.
+     *
+     * @param  desc
+     *         A description of the error
+     *
+     * @param  regex
+     *         The erroneous pattern
+     *
+     * @param  index
+     *         The approximate index in the pattern of the error,
+     *         or <tt>-1</tt> if the index is not known
+     */
+    public PatternSyntaxException(String desc, String regex, int index) {
+        this.desc = desc;
+        this.pattern = regex;
+        this.index = index;
+    }
+
+    /**
+     * Retrieves the error index.
+     *
+     * @return  The approximate index in the pattern of the error,
+     *         or <tt>-1</tt> if the index is not known
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * Retrieves the description of the error.
+     *
+     * @return  The description of the error
+     */
+    public String getDescription() {
+        return desc;
+    }
+
+    /**
+     * Retrieves the erroneous regular-expression pattern.
+     *
+     * @return  The erroneous pattern
+     */
+    public String getPattern() {
+        return pattern;
+    }
+
+    private static final String nl =
+        java.security.AccessController
+            .doPrivileged(new GetPropertyAction("line.separator"));
+
+    /**
+     * Returns a multi-line string containing the description of the syntax
+     * error and its index, the erroneous regular-expression pattern, and a
+     * visual indication of the error index within the pattern.
+     *
+     * @return  The full detail message
+     */
+    public String getMessage() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(desc);
+        if (index >= 0) {
+            sb.append(" near index ");
+            sb.append(index);
+        }
+        sb.append(nl);
+        sb.append(pattern);
+        if (index >= 0) {
+            sb.append(nl);
+            for (int i = 0; i < index; i++) sb.append(' ');
+            sb.append('^');
+        }
+        return sb.toString();
+    }
+
+}
diff --git a/java/util/stream/AbstractPipeline.java b/java/util/stream/AbstractPipeline.java
new file mode 100644
index 0000000..627bb32
--- /dev/null
+++ b/java/util/stream/AbstractPipeline.java
@@ -0,0 +1,723 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for "pipeline" classes, which are the core
+ * implementations of the Stream interface and its primitive specializations.
+ * Manages construction and evaluation of stream pipelines.
+ *
+ * <p>An {@code AbstractPipeline} represents an initial portion of a stream
+ * pipeline, encapsulating a stream source and zero or more intermediate
+ * operations.  The individual {@code AbstractPipeline} objects are often
+ * referred to as <em>stages</em>, where each stage describes either the stream
+ * source or an intermediate operation.
+ *
+ * <p>A concrete intermediate stage is generally built from an
+ * {@code AbstractPipeline}, a shape-specific pipeline class which extends it
+ * (e.g., {@code IntPipeline}) which is also abstract, and an operation-specific
+ * concrete class which extends that.  {@code AbstractPipeline} contains most of
+ * the mechanics of evaluating the pipeline, and implements methods that will be
+ * used by the operation; the shape-specific classes add helper methods for
+ * dealing with collection of results into the appropriate shape-specific
+ * containers.
+ *
+ * <p>After chaining a new intermediate operation, or executing a terminal
+ * operation, the stream is considered to be consumed, and no more intermediate
+ * or terminal operations are permitted on this stream instance.
+ *
+ * @implNote
+ * <p>For sequential streams, and parallel streams without
+ * <a href="package-summary.html#StreamOps">stateful intermediate
+ * operations</a>, parallel streams, pipeline evaluation is done in a single
+ * pass that "jams" all the operations together.  For parallel streams with
+ * stateful operations, execution is divided into segments, where each
+ * stateful operations marks the end of a segment, and each segment is
+ * evaluated separately and the result used as the input to the next
+ * segment.  In all cases, the source data is not consumed until a terminal
+ * operation begins.
+ *
+ * @param <E_IN>  type of input elements
+ * @param <E_OUT> type of output elements
+ * @param <S> type of the subclass implementing {@code BaseStream}
+ * @since 1.8
+ * @hide Made public for CTS tests only (OpenJDK 8 streams tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class AbstractPipeline<E_IN, E_OUT, S extends BaseStream<E_OUT, S>>
+        extends PipelineHelper<E_OUT> implements BaseStream<E_OUT, S> {
+    private static final String MSG_STREAM_LINKED = "stream has already been operated upon or closed";
+    private static final String MSG_CONSUMED = "source already consumed or closed";
+
+    /**
+     * Backlink to the head of the pipeline chain (self if this is the source
+     * stage).
+     */
+    @SuppressWarnings("rawtypes")
+    private final AbstractPipeline sourceStage;
+
+    /**
+     * The "upstream" pipeline, or null if this is the source stage.
+     */
+    @SuppressWarnings("rawtypes")
+    private final AbstractPipeline previousStage;
+
+    /**
+     * The operation flags for the intermediate operation represented by this
+     * pipeline object.
+     */
+    protected final int sourceOrOpFlags;
+
+    /**
+     * The next stage in the pipeline, or null if this is the last stage.
+     * Effectively final at the point of linking to the next pipeline.
+     */
+    @SuppressWarnings("rawtypes")
+    private AbstractPipeline nextStage;
+
+    /**
+     * The number of intermediate operations between this pipeline object
+     * and the stream source if sequential, or the previous stateful if parallel.
+     * Valid at the point of pipeline preparation for evaluation.
+     */
+    private int depth;
+
+    /**
+     * The combined source and operation flags for the source and all operations
+     * up to and including the operation represented by this pipeline object.
+     * Valid at the point of pipeline preparation for evaluation.
+     */
+    private int combinedFlags;
+
+    /**
+     * The source spliterator. Only valid for the head pipeline.
+     * Before the pipeline is consumed if non-null then {@code sourceSupplier}
+     * must be null. After the pipeline is consumed if non-null then is set to
+     * null.
+     */
+    private Spliterator<?> sourceSpliterator;
+
+    /**
+     * The source supplier. Only valid for the head pipeline. Before the
+     * pipeline is consumed if non-null then {@code sourceSpliterator} must be
+     * null. After the pipeline is consumed if non-null then is set to null.
+     */
+    private Supplier<? extends Spliterator<?>> sourceSupplier;
+
+    /**
+     * True if this pipeline has been linked or consumed
+     */
+    private boolean linkedOrConsumed;
+
+    /**
+     * True if there are any stateful ops in the pipeline; only valid for the
+     * source stage.
+     */
+    private boolean sourceAnyStateful;
+
+    private Runnable sourceCloseAction;
+
+    /**
+     * True if pipeline is parallel, otherwise the pipeline is sequential; only
+     * valid for the source stage.
+     */
+    private boolean parallel;
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     * @param parallel True if the pipeline is parallel
+     */
+    AbstractPipeline(Supplier<? extends Spliterator<?>> source,
+                     int sourceFlags, boolean parallel) {
+        this.previousStage = null;
+        this.sourceSupplier = source;
+        this.sourceStage = this;
+        this.sourceOrOpFlags = sourceFlags & StreamOpFlag.STREAM_MASK;
+        // The following is an optimization of:
+        // StreamOpFlag.combineOpFlags(sourceOrOpFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+        this.combinedFlags = (~(sourceOrOpFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE;
+        this.depth = 0;
+        this.parallel = parallel;
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    AbstractPipeline(Spliterator<?> source,
+                     int sourceFlags, boolean parallel) {
+        this.previousStage = null;
+        this.sourceSpliterator = source;
+        this.sourceStage = this;
+        this.sourceOrOpFlags = sourceFlags & StreamOpFlag.STREAM_MASK;
+        // The following is an optimization of:
+        // StreamOpFlag.combineOpFlags(sourceOrOpFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+        this.combinedFlags = (~(sourceOrOpFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE;
+        this.depth = 0;
+        this.parallel = parallel;
+    }
+
+    /**
+     * Constructor for appending an intermediate operation stage onto an
+     * existing pipeline.
+     *
+     * @param previousStage the upstream pipeline stage
+     * @param opFlags the operation flags for the new stage, described in
+     * {@link StreamOpFlag}
+     */
+    AbstractPipeline(AbstractPipeline<?, E_IN, ?> previousStage, int opFlags) {
+        if (previousStage.linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        previousStage.linkedOrConsumed = true;
+        previousStage.nextStage = this;
+
+        this.previousStage = previousStage;
+        this.sourceOrOpFlags = opFlags & StreamOpFlag.OP_MASK;
+        this.combinedFlags = StreamOpFlag.combineOpFlags(opFlags, previousStage.combinedFlags);
+        this.sourceStage = previousStage.sourceStage;
+        if (opIsStateful())
+            sourceStage.sourceAnyStateful = true;
+        this.depth = previousStage.depth + 1;
+    }
+
+
+    // Terminal evaluation methods
+
+    /**
+     * Evaluate the pipeline with a terminal operation to produce a result.
+     *
+     * @param <R> the type of result
+     * @param terminalOp the terminal operation to be applied to the pipeline.
+     * @return the result
+     */
+    final <R> R evaluate(TerminalOp<E_OUT, R> terminalOp) {
+        assert getOutputShape() == terminalOp.inputShape();
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        return isParallel()
+               ? terminalOp.evaluateParallel(this, sourceSpliterator(terminalOp.getOpFlags()))
+               : terminalOp.evaluateSequential(this, sourceSpliterator(terminalOp.getOpFlags()));
+    }
+
+    /**
+     * Collect the elements output from the pipeline stage.
+     *
+     * @param generator the array generator to be used to create array instances
+     * @return a flat array-backed Node that holds the collected output elements
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public final Node<E_OUT> evaluateToArrayNode(IntFunction<E_OUT[]> generator) {
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        // If the last intermediate operation is stateful then
+        // evaluate directly to avoid an extra collection step
+        if (isParallel() && previousStage != null && opIsStateful()) {
+            // Set the depth of this, last, pipeline stage to zero to slice the
+            // pipeline such that this operation will not be included in the
+            // upstream slice and upstream operations will not be included
+            // in this slice
+            depth = 0;
+            return opEvaluateParallel(previousStage, previousStage.sourceSpliterator(0), generator);
+        }
+        else {
+            return evaluate(sourceSpliterator(0), true, generator);
+        }
+    }
+
+    /**
+     * Gets the source stage spliterator if this pipeline stage is the source
+     * stage.  The pipeline is consumed after this method is called and
+     * returns successfully.
+     *
+     * @return the source stage spliterator
+     * @throws IllegalStateException if this pipeline stage is not the source
+     *         stage.
+     */
+    @SuppressWarnings("unchecked")
+    final Spliterator<E_OUT> sourceStageSpliterator() {
+        if (this != sourceStage)
+            throw new IllegalStateException();
+
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        if (sourceStage.sourceSpliterator != null) {
+            @SuppressWarnings("unchecked")
+            Spliterator<E_OUT> s = sourceStage.sourceSpliterator;
+            sourceStage.sourceSpliterator = null;
+            return s;
+        }
+        else if (sourceStage.sourceSupplier != null) {
+            @SuppressWarnings("unchecked")
+            Spliterator<E_OUT> s = (Spliterator<E_OUT>) sourceStage.sourceSupplier.get();
+            sourceStage.sourceSupplier = null;
+            return s;
+        }
+        else {
+            throw new IllegalStateException(MSG_CONSUMED);
+        }
+    }
+
+    // BaseStream
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final S sequential() {
+        sourceStage.parallel = false;
+        return (S) this;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final S parallel() {
+        sourceStage.parallel = true;
+        return (S) this;
+    }
+
+    @Override
+    public void close() {
+        linkedOrConsumed = true;
+        sourceSupplier = null;
+        sourceSpliterator = null;
+        if (sourceStage.sourceCloseAction != null) {
+            Runnable closeAction = sourceStage.sourceCloseAction;
+            sourceStage.sourceCloseAction = null;
+            closeAction.run();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public S onClose(Runnable closeHandler) {
+        Runnable existingHandler = sourceStage.sourceCloseAction;
+        sourceStage.sourceCloseAction =
+                (existingHandler == null)
+                ? closeHandler
+                : Streams.composeWithExceptions(existingHandler, closeHandler);
+        return (S) this;
+    }
+
+    // Primitive specialization use co-variant overrides, hence is not final
+    @Override
+    @SuppressWarnings("unchecked")
+    public Spliterator<E_OUT> spliterator() {
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        if (this == sourceStage) {
+            if (sourceStage.sourceSpliterator != null) {
+                @SuppressWarnings("unchecked")
+                Spliterator<E_OUT> s = (Spliterator<E_OUT>) sourceStage.sourceSpliterator;
+                sourceStage.sourceSpliterator = null;
+                return s;
+            }
+            else if (sourceStage.sourceSupplier != null) {
+                @SuppressWarnings("unchecked")
+                Supplier<Spliterator<E_OUT>> s = (Supplier<Spliterator<E_OUT>>) sourceStage.sourceSupplier;
+                sourceStage.sourceSupplier = null;
+                return lazySpliterator(s);
+            }
+            else {
+                throw new IllegalStateException(MSG_CONSUMED);
+            }
+        }
+        else {
+            return wrap(this, () -> sourceSpliterator(0), isParallel());
+        }
+    }
+
+    @Override
+    public final boolean isParallel() {
+        return sourceStage.parallel;
+    }
+
+
+    /**
+     * Returns the composition of stream flags of the stream source and all
+     * intermediate operations.
+     *
+     * @return the composition of stream flags of the stream source and all
+     *         intermediate operations
+     * @see StreamOpFlag
+     */
+    // Android-changed: Made public for CTS tests only.
+    public final int getStreamFlags() {
+        return StreamOpFlag.toStreamFlags(combinedFlags);
+    }
+
+    /**
+     * Get the source spliterator for this pipeline stage.  For a sequential or
+     * stateless parallel pipeline, this is the source spliterator.  For a
+     * stateful parallel pipeline, this is a spliterator describing the results
+     * of all computations up to and including the most recent stateful
+     * operation.
+     */
+    @SuppressWarnings("unchecked")
+    private Spliterator<?> sourceSpliterator(int terminalFlags) {
+        // Get the source spliterator of the pipeline
+        Spliterator<?> spliterator = null;
+        if (sourceStage.sourceSpliterator != null) {
+            spliterator = sourceStage.sourceSpliterator;
+            sourceStage.sourceSpliterator = null;
+        }
+        else if (sourceStage.sourceSupplier != null) {
+            spliterator = (Spliterator<?>) sourceStage.sourceSupplier.get();
+            sourceStage.sourceSupplier = null;
+        }
+        else {
+            throw new IllegalStateException(MSG_CONSUMED);
+        }
+
+        if (isParallel() && sourceStage.sourceAnyStateful) {
+            // Adapt the source spliterator, evaluating each stateful op
+            // in the pipeline up to and including this pipeline stage.
+            // The depth and flags of each pipeline stage are adjusted accordingly.
+            int depth = 1;
+            for (@SuppressWarnings("rawtypes") AbstractPipeline u = sourceStage, p = sourceStage.nextStage, e = this;
+                 u != e;
+                 u = p, p = p.nextStage) {
+
+                int thisOpFlags = p.sourceOrOpFlags;
+                if (p.opIsStateful()) {
+                    depth = 0;
+
+                    if (StreamOpFlag.SHORT_CIRCUIT.isKnown(thisOpFlags)) {
+                        // Clear the short circuit flag for next pipeline stage
+                        // This stage encapsulates short-circuiting, the next
+                        // stage may not have any short-circuit operations, and
+                        // if so spliterator.forEachRemaining should be used
+                        // for traversal
+                        thisOpFlags = thisOpFlags & ~StreamOpFlag.IS_SHORT_CIRCUIT;
+                    }
+
+                    spliterator = p.opEvaluateParallelLazy(u, spliterator);
+
+                    // Inject or clear SIZED on the source pipeline stage
+                    // based on the stage's spliterator
+                    thisOpFlags = spliterator.hasCharacteristics(Spliterator.SIZED)
+                            ? (thisOpFlags & ~StreamOpFlag.NOT_SIZED) | StreamOpFlag.IS_SIZED
+                            : (thisOpFlags & ~StreamOpFlag.IS_SIZED) | StreamOpFlag.NOT_SIZED;
+                }
+                p.depth = depth++;
+                p.combinedFlags = StreamOpFlag.combineOpFlags(thisOpFlags, u.combinedFlags);
+            }
+        }
+
+        if (terminalFlags != 0)  {
+            // Apply flags from the terminal operation to last pipeline stage
+            combinedFlags = StreamOpFlag.combineOpFlags(terminalFlags, combinedFlags);
+        }
+
+        return spliterator;
+    }
+
+    // PipelineHelper
+
+    @Override
+    final StreamShape getSourceShape() {
+        @SuppressWarnings("rawtypes")
+        AbstractPipeline p = AbstractPipeline.this;
+        while (p.depth > 0) {
+            p = p.previousStage;
+        }
+        return p.getOutputShape();
+    }
+
+    @Override
+    final <P_IN> long exactOutputSizeIfKnown(Spliterator<P_IN> spliterator) {
+        return StreamOpFlag.SIZED.isKnown(getStreamAndOpFlags()) ? spliterator.getExactSizeIfKnown() : -1;
+    }
+
+    @Override
+    final <P_IN, S extends Sink<E_OUT>> S wrapAndCopyInto(S sink, Spliterator<P_IN> spliterator) {
+        copyInto(wrapSink(Objects.requireNonNull(sink)), spliterator);
+        return sink;
+    }
+
+    @Override
+    final <P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
+        Objects.requireNonNull(wrappedSink);
+
+        if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
+            wrappedSink.begin(spliterator.getExactSizeIfKnown());
+            spliterator.forEachRemaining(wrappedSink);
+            wrappedSink.end();
+        }
+        else {
+            copyIntoWithCancel(wrappedSink, spliterator);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    final <P_IN> void copyIntoWithCancel(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
+        @SuppressWarnings({"rawtypes","unchecked"})
+        AbstractPipeline p = AbstractPipeline.this;
+        while (p.depth > 0) {
+            p = p.previousStage;
+        }
+        wrappedSink.begin(spliterator.getExactSizeIfKnown());
+        p.forEachWithCancel(spliterator, wrappedSink);
+        wrappedSink.end();
+    }
+
+    @Override
+    // Android-changed: Made public for CTS tests only.
+    public final int getStreamAndOpFlags() {
+        return combinedFlags;
+    }
+
+    final boolean isOrdered() {
+        return StreamOpFlag.ORDERED.isKnown(combinedFlags);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public final <P_IN> Sink<P_IN> wrapSink(Sink<E_OUT> sink) {
+        Objects.requireNonNull(sink);
+
+        for ( @SuppressWarnings("rawtypes") AbstractPipeline p=AbstractPipeline.this; p.depth > 0; p=p.previousStage) {
+            sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
+        }
+        return (Sink<P_IN>) sink;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    final <P_IN> Spliterator<E_OUT> wrapSpliterator(Spliterator<P_IN> sourceSpliterator) {
+        if (depth == 0) {
+            return (Spliterator<E_OUT>) sourceSpliterator;
+        }
+        else {
+            return wrap(this, () -> sourceSpliterator, isParallel());
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public final <P_IN> Node<E_OUT> evaluate(Spliterator<P_IN> spliterator,
+                                      boolean flatten,
+                                      IntFunction<E_OUT[]> generator) {
+        if (isParallel()) {
+            // @@@ Optimize if op of this pipeline stage is a stateful op
+            return evaluateToNode(this, spliterator, flatten, generator);
+        }
+        else {
+            Node.Builder<E_OUT> nb = makeNodeBuilder(
+                    exactOutputSizeIfKnown(spliterator), generator);
+            return wrapAndCopyInto(nb, spliterator).build();
+        }
+    }
+
+
+    // Shape-specific abstract methods, implemented by XxxPipeline classes
+
+    /**
+     * Get the output shape of the pipeline.  If the pipeline is the head,
+     * then it's output shape corresponds to the shape of the source.
+     * Otherwise, it's output shape corresponds to the output shape of the
+     * associated operation.
+     *
+     * @return the output shape
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract StreamShape getOutputShape();
+
+    /**
+     * Collect elements output from a pipeline into a Node that holds elements
+     * of this shape.
+     *
+     * @param helper the pipeline helper describing the pipeline stages
+     * @param spliterator the source spliterator
+     * @param flattenTree true if the returned node should be flattened
+     * @param generator the array generator
+     * @return a Node holding the output of the pipeline
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract <P_IN> Node<E_OUT> evaluateToNode(PipelineHelper<E_OUT> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      boolean flattenTree,
+                                                      IntFunction<E_OUT[]> generator);
+
+    /**
+     * Create a spliterator that wraps a source spliterator, compatible with
+     * this stream shape, and operations associated with a {@link
+     * PipelineHelper}.
+     *
+     * @param ph the pipeline helper describing the pipeline stages
+     * @param supplier the supplier of a spliterator
+     * @return a wrapping spliterator compatible with this shape
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract <P_IN> Spliterator<E_OUT> wrap(PipelineHelper<E_OUT> ph,
+                                                   Supplier<Spliterator<P_IN>> supplier,
+                                                   boolean isParallel);
+
+    /**
+     * Create a lazy spliterator that wraps and obtains the supplied the
+     * spliterator when a method is invoked on the lazy spliterator.
+     * @param supplier the supplier of a spliterator
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract Spliterator<E_OUT> lazySpliterator(Supplier<? extends Spliterator<E_OUT>> supplier);
+
+    /**
+     * Traverse the elements of a spliterator compatible with this stream shape,
+     * pushing those elements into a sink.   If the sink requests cancellation,
+     * no further elements will be pulled or pushed.
+     *
+     * @param spliterator the spliterator to pull elements from
+     * @param sink the sink to push elements to
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract void forEachWithCancel(Spliterator<E_OUT> spliterator, Sink<E_OUT> sink);
+
+    /**
+     * Make a node builder compatible with this stream shape.
+     *
+     * @param exactSizeIfKnown if {@literal >=0}, then a node builder will be
+     * created that has a fixed capacity of at most sizeIfKnown elements. If
+     * {@literal < 0}, then the node builder has an unfixed capacity. A fixed
+     * capacity node builder will throw exceptions if an element is added after
+     * builder has reached capacity, or is built before the builder has reached
+     * capacity.
+     *
+     * @param generator the array generator to be used to create instances of a
+     * T[] array. For implementations supporting primitive nodes, this parameter
+     * may be ignored.
+     * @return a node builder
+     */
+    @Override
+    // Android-changed: Made public for CTS tests only.
+    public abstract Node.Builder<E_OUT> makeNodeBuilder(long exactSizeIfKnown,
+                                                        IntFunction<E_OUT[]> generator);
+
+
+    // Op-specific abstract methods, implemented by the operation class
+
+    /**
+     * Returns whether this operation is stateful or not.  If it is stateful,
+     * then the method
+     * {@link #opEvaluateParallel(PipelineHelper, java.util.Spliterator, java.util.function.IntFunction)}
+     * must be overridden.
+     *
+     * @return {@code true} if this operation is stateful
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract boolean opIsStateful();
+
+    /**
+     * Accepts a {@code Sink} which will receive the results of this operation,
+     * and return a {@code Sink} which accepts elements of the input type of
+     * this operation and which performs the operation, passing the results to
+     * the provided {@code Sink}.
+     *
+     * @apiNote
+     * The implementation may use the {@code flags} parameter to optimize the
+     * sink wrapping.  For example, if the input is already {@code DISTINCT},
+     * the implementation for the {@code Stream#distinct()} method could just
+     * return the sink it was passed.
+     *
+     * @param flags The combined stream and operation flags up to, but not
+     *        including, this operation
+     * @param sink sink to which elements should be sent after processing
+     * @return a sink which accepts elements, perform the operation upon
+     *         each element, and passes the results (if any) to the provided
+     *         {@code Sink}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink);
+
+    /**
+     * Performs a parallel evaluation of the operation using the specified
+     * {@code PipelineHelper} which describes the upstream intermediate
+     * operations.  Only called on stateful operations.  If {@link
+     * #opIsStateful()} returns true then implementations must override the
+     * default implementation.
+     *
+     * @implSpec The default implementation always throw
+     * {@code UnsupportedOperationException}.
+     *
+     * @param helper the pipeline helper describing the pipeline stages
+     * @param spliterator the source {@code Spliterator}
+     * @param generator the array generator
+     * @return a {@code Node} describing the result of the evaluation
+     */
+    // Android-changed: Made public for CTS tests only.
+    public <P_IN> Node<E_OUT> opEvaluateParallel(PipelineHelper<E_OUT> helper,
+                                          Spliterator<P_IN> spliterator,
+                                          IntFunction<E_OUT[]> generator) {
+        throw new UnsupportedOperationException("Parallel evaluation is not supported");
+    }
+
+    /**
+     * Returns a {@code Spliterator} describing a parallel evaluation of the
+     * operation, using the specified {@code PipelineHelper} which describes the
+     * upstream intermediate operations.  Only called on stateful operations.
+     * It is not necessary (though acceptable) to do a full computation of the
+     * result here; it is preferable, if possible, to describe the result via a
+     * lazily evaluated spliterator.
+     *
+     * @implSpec The default implementation behaves as if:
+     * <pre>{@code
+     *     return evaluateParallel(helper, i -> (E_OUT[]) new
+     * Object[i]).spliterator();
+     * }</pre>
+     * and is suitable for implementations that cannot do better than a full
+     * synchronous evaluation.
+     *
+     * @param helper the pipeline helper
+     * @param spliterator the source {@code Spliterator}
+     * @return a {@code Spliterator} describing the result of the evaluation
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public <P_IN> Spliterator<E_OUT> opEvaluateParallelLazy(PipelineHelper<E_OUT> helper,
+                                                     Spliterator<P_IN> spliterator) {
+        return opEvaluateParallel(helper, spliterator, i -> (E_OUT[]) new Object[i]).spliterator();
+    }
+}
diff --git a/java/util/stream/AbstractShortCircuitTask.java b/java/util/stream/AbstractShortCircuitTask.java
new file mode 100644
index 0000000..bbf09f0
--- /dev/null
+++ b/java/util/stream/AbstractShortCircuitTask.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Abstract class for fork-join tasks used to implement short-circuiting
+ * stream ops, which can produce a result without processing all elements of the
+ * stream.
+ *
+ * @param <P_IN> type of input elements to the pipeline
+ * @param <P_OUT> type of output elements from the pipeline
+ * @param <R> type of intermediate result, may be different from operation
+ *        result type
+ * @param <K> type of child and sibling tasks
+ * @since 1.8
+ */
+@SuppressWarnings("serial")
+abstract class AbstractShortCircuitTask<P_IN, P_OUT, R,
+                                        K extends AbstractShortCircuitTask<P_IN, P_OUT, R, K>>
+        extends AbstractTask<P_IN, P_OUT, R, K> {
+    /**
+     * The result for this computation; this is shared among all tasks and set
+     * exactly once
+     */
+    protected final AtomicReference<R> sharedResult;
+
+    /**
+     * Indicates whether this task has been canceled.  Tasks may cancel other
+     * tasks in the computation under various conditions, such as in a
+     * find-first operation, a task that finds a value will cancel all tasks
+     * that are later in the encounter order.
+     */
+    protected volatile boolean canceled;
+
+    /**
+     * Constructor for root tasks.
+     *
+     * @param helper the {@code PipelineHelper} describing the stream pipeline
+     *               up to this operation
+     * @param spliterator the {@code Spliterator} describing the source for this
+     *                    pipeline
+     */
+    protected AbstractShortCircuitTask(PipelineHelper<P_OUT> helper,
+                                       Spliterator<P_IN> spliterator) {
+        super(helper, spliterator);
+        sharedResult = new AtomicReference<>(null);
+    }
+
+    /**
+     * Constructor for non-root nodes.
+     *
+     * @param parent parent task in the computation tree
+     * @param spliterator the {@code Spliterator} for the portion of the
+     *                    computation tree described by this task
+     */
+    protected AbstractShortCircuitTask(K parent,
+                                       Spliterator<P_IN> spliterator) {
+        super(parent, spliterator);
+        sharedResult = parent.sharedResult;
+    }
+
+    /**
+     * Returns the value indicating the computation completed with no task
+     * finding a short-circuitable result.  For example, for a "find" operation,
+     * this might be null or an empty {@code Optional}.
+     *
+     * @return the result to return when no task finds a result
+     */
+    protected abstract R getEmptyResult();
+
+    /**
+     * Overrides AbstractTask version to include checks for early
+     * exits while splitting or computing.
+     */
+    @Override
+    public void compute() {
+        Spliterator<P_IN> rs = spliterator, ls;
+        long sizeEstimate = rs.estimateSize();
+        long sizeThreshold = getTargetSize(sizeEstimate);
+        boolean forkRight = false;
+        @SuppressWarnings("unchecked") K task = (K) this;
+        AtomicReference<R> sr = sharedResult;
+        R result;
+        while ((result = sr.get()) == null) {
+            if (task.taskCanceled()) {
+                result = task.getEmptyResult();
+                break;
+            }
+            if (sizeEstimate <= sizeThreshold || (ls = rs.trySplit()) == null) {
+                result = task.doLeaf();
+                break;
+            }
+            K leftChild, rightChild, taskToFork;
+            task.leftChild  = leftChild = task.makeChild(ls);
+            task.rightChild = rightChild = task.makeChild(rs);
+            task.setPendingCount(1);
+            if (forkRight) {
+                forkRight = false;
+                rs = ls;
+                task = leftChild;
+                taskToFork = rightChild;
+            }
+            else {
+                forkRight = true;
+                task = rightChild;
+                taskToFork = leftChild;
+            }
+            taskToFork.fork();
+            sizeEstimate = rs.estimateSize();
+        }
+        task.setLocalResult(result);
+        task.tryComplete();
+    }
+
+
+    /**
+     * Declares that a globally valid result has been found.  If another task has
+     * not already found the answer, the result is installed in
+     * {@code sharedResult}.  The {@code compute()} method will check
+     * {@code sharedResult} before proceeding with computation, so this causes
+     * the computation to terminate early.
+     *
+     * @param result the result found
+     */
+    protected void shortCircuit(R result) {
+        if (result != null)
+            sharedResult.compareAndSet(null, result);
+    }
+
+    /**
+     * Sets a local result for this task.  If this task is the root, set the
+     * shared result instead (if not already set).
+     *
+     * @param localResult The result to set for this task
+     */
+    @Override
+    protected void setLocalResult(R localResult) {
+        if (isRoot()) {
+            if (localResult != null)
+                sharedResult.compareAndSet(null, localResult);
+        }
+        else
+            super.setLocalResult(localResult);
+    }
+
+    /**
+     * Retrieves the local result for this task
+     */
+    @Override
+    public R getRawResult() {
+        return getLocalResult();
+    }
+
+    /**
+     * Retrieves the local result for this task.  If this task is the root,
+     * retrieves the shared result instead.
+     */
+    @Override
+    public R getLocalResult() {
+        if (isRoot()) {
+            R answer = sharedResult.get();
+            return (answer == null) ? getEmptyResult() : answer;
+        }
+        else
+            return super.getLocalResult();
+    }
+
+    /**
+     * Mark this task as canceled
+     */
+    protected void cancel() {
+        canceled = true;
+    }
+
+    /**
+     * Queries whether this task is canceled.  A task is considered canceled if
+     * it or any of its parents have been canceled.
+     *
+     * @return {@code true} if this task or any parent is canceled.
+     */
+    protected boolean taskCanceled() {
+        boolean cancel = canceled;
+        if (!cancel) {
+            for (K parent = getParent(); !cancel && parent != null; parent = parent.getParent())
+                cancel = parent.canceled;
+        }
+
+        return cancel;
+    }
+
+    /**
+     * Cancels all tasks which succeed this one in the encounter order.  This
+     * includes canceling all the current task's right sibling, as well as the
+     * later right siblings of all its parents.
+     */
+    protected void cancelLaterNodes() {
+        // Go up the tree, cancel right siblings of this node and all parents
+        for (@SuppressWarnings("unchecked") K parent = getParent(), node = (K) this;
+             parent != null;
+             node = parent, parent = parent.getParent()) {
+            // If node is a left child of parent, then has a right sibling
+            if (parent.leftChild == node) {
+                K rightSibling = parent.rightChild;
+                if (!rightSibling.canceled)
+                    rightSibling.cancel();
+            }
+        }
+    }
+}
diff --git a/java/util/stream/AbstractSpinedBuffer.java b/java/util/stream/AbstractSpinedBuffer.java
new file mode 100644
index 0000000..46fdf4d
--- /dev/null
+++ b/java/util/stream/AbstractSpinedBuffer.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * Base class for a data structure for gathering elements into a buffer and then
+ * iterating them. Maintains an array of increasingly sized arrays, so there is
+ * no copying cost associated with growing the data structure.
+ * @since 1.8
+ */
+abstract class AbstractSpinedBuffer {
+    /**
+     * Minimum power-of-two for the first chunk.
+     */
+    public static final int MIN_CHUNK_POWER = 4;
+
+    /**
+     * Minimum size for the first chunk.
+     */
+    public static final int MIN_CHUNK_SIZE = 1 << MIN_CHUNK_POWER;
+
+    /**
+     * Max power-of-two for chunks.
+     */
+    public static final int MAX_CHUNK_POWER = 30;
+
+    /**
+     * Minimum array size for array-of-chunks.
+     */
+    public static final int MIN_SPINE_SIZE = 8;
+
+
+    /**
+     * log2 of the size of the first chunk.
+     */
+    protected final int initialChunkPower;
+
+    /**
+     * Index of the *next* element to write; may point into, or just outside of,
+     * the current chunk.
+     */
+    protected int elementIndex;
+
+    /**
+     * Index of the *current* chunk in the spine array, if the spine array is
+     * non-null.
+     */
+    protected int spineIndex;
+
+    /**
+     * Count of elements in all prior chunks.
+     */
+    protected long[] priorElementCount;
+
+    /**
+     * Construct with an initial capacity of 16.
+     */
+    protected AbstractSpinedBuffer() {
+        this.initialChunkPower = MIN_CHUNK_POWER;
+    }
+
+    /**
+     * Construct with a specified initial capacity.
+     *
+     * @param initialCapacity The minimum expected number of elements
+     */
+    protected AbstractSpinedBuffer(int initialCapacity) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
+
+        this.initialChunkPower = Math.max(MIN_CHUNK_POWER,
+                                          Integer.SIZE - Integer.numberOfLeadingZeros(initialCapacity - 1));
+    }
+
+    /**
+     * Is the buffer currently empty?
+     */
+    public boolean isEmpty() {
+        return (spineIndex == 0) && (elementIndex == 0);
+    }
+
+    /**
+     * How many elements are currently in the buffer?
+     */
+    public long count() {
+        return (spineIndex == 0)
+               ? elementIndex
+               : priorElementCount[spineIndex] + elementIndex;
+    }
+
+    /**
+     * How big should the nth chunk be?
+     */
+    protected int chunkSize(int n) {
+        int power = (n == 0 || n == 1)
+                    ? initialChunkPower
+                    : Math.min(initialChunkPower + n - 1, AbstractSpinedBuffer.MAX_CHUNK_POWER);
+        return 1 << power;
+    }
+
+    /**
+     * Remove all data from the buffer
+     */
+    public abstract void clear();
+}
diff --git a/java/util/stream/AbstractTask.java b/java/util/stream/AbstractTask.java
new file mode 100644
index 0000000..33de7d5
--- /dev/null
+++ b/java/util/stream/AbstractTask.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinPool;
+
+/**
+ * Abstract base class for most fork-join tasks used to implement stream ops.
+ * Manages splitting logic, tracking of child tasks, and intermediate results.
+ * Each task is associated with a {@link Spliterator} that describes the portion
+ * of the input associated with the subtree rooted at this task.
+ * Tasks may be leaf nodes (which will traverse the elements of
+ * the {@code Spliterator}) or internal nodes (which split the
+ * {@code Spliterator} into multiple child tasks).
+ *
+ * @implNote
+ * <p>This class is based on {@link CountedCompleter}, a form of fork-join task
+ * where each task has a semaphore-like count of uncompleted children, and the
+ * task is implicitly completed and notified when its last child completes.
+ * Internal node tasks will likely override the {@code onCompletion} method from
+ * {@code CountedCompleter} to merge the results from child tasks into the
+ * current task's result.
+ *
+ * <p>Splitting and setting up the child task links is done by {@code compute()}
+ * for internal nodes.  At {@code compute()} time for leaf nodes, it is
+ * guaranteed that the parent's child-related fields (including sibling links
+ * for the parent's children) will be set up for all children.
+ *
+ * <p>For example, a task that performs a reduce would override {@code doLeaf()}
+ * to perform a reduction on that leaf node's chunk using the
+ * {@code Spliterator}, and override {@code onCompletion()} to merge the results
+ * of the child tasks for internal nodes:
+ *
+ * <pre>{@code
+ *     protected S doLeaf() {
+ *         spliterator.forEach(...);
+ *         return localReductionResult;
+ *     }
+ *
+ *     public void onCompletion(CountedCompleter caller) {
+ *         if (!isLeaf()) {
+ *             ReduceTask<P_IN, P_OUT, T, R> child = children;
+ *             R result = child.getLocalResult();
+ *             child = child.nextSibling;
+ *             for (; child != null; child = child.nextSibling)
+ *                 result = combine(result, child.getLocalResult());
+ *             setLocalResult(result);
+ *         }
+ *     }
+ * }</pre>
+ *
+ * <p>Serialization is not supported as there is no intention to serialize
+ * tasks managed by stream ops.
+ *
+ * @param <P_IN> Type of elements input to the pipeline
+ * @param <P_OUT> Type of elements output from the pipeline
+ * @param <R> Type of intermediate result, which may be different from operation
+ *        result type
+ * @param <K> Type of parent, child and sibling tasks
+ * @since 1.8
+ */
+@SuppressWarnings("serial")
+abstract class AbstractTask<P_IN, P_OUT, R,
+                            K extends AbstractTask<P_IN, P_OUT, R, K>>
+        extends CountedCompleter<R> {
+
+    /**
+     * Default target factor of leaf tasks for parallel decomposition.
+     * To allow load balancing, we over-partition, currently to approximately
+     * four tasks per processor, which enables others to help out
+     * if leaf tasks are uneven or some processors are otherwise busy.
+     */
+    static final int LEAF_TARGET = ForkJoinPool.getCommonPoolParallelism() << 2;
+
+    /** The pipeline helper, common to all tasks in a computation */
+    protected final PipelineHelper<P_OUT> helper;
+
+    /**
+     * The spliterator for the portion of the input associated with the subtree
+     * rooted at this task
+     */
+    protected Spliterator<P_IN> spliterator;
+
+    /** Target leaf size, common to all tasks in a computation */
+    protected long targetSize; // may be laziliy initialized
+
+    /**
+     * The left child.
+     * null if no children
+     * if non-null rightChild is non-null
+     */
+    protected K leftChild;
+
+    /**
+     * The right child.
+     * null if no children
+     * if non-null leftChild is non-null
+     */
+    protected K rightChild;
+
+    /** The result of this node, if completed */
+    private R localResult;
+
+    /**
+     * Constructor for root nodes.
+     *
+     * @param helper The {@code PipelineHelper} describing the stream pipeline
+     *               up to this operation
+     * @param spliterator The {@code Spliterator} describing the source for this
+     *                    pipeline
+     */
+    protected AbstractTask(PipelineHelper<P_OUT> helper,
+                           Spliterator<P_IN> spliterator) {
+        super(null);
+        this.helper = helper;
+        this.spliterator = spliterator;
+        this.targetSize = 0L;
+    }
+
+    /**
+     * Constructor for non-root nodes.
+     *
+     * @param parent this node's parent task
+     * @param spliterator {@code Spliterator} describing the subtree rooted at
+     *        this node, obtained by splitting the parent {@code Spliterator}
+     */
+    protected AbstractTask(K parent,
+                           Spliterator<P_IN> spliterator) {
+        super(parent);
+        this.spliterator = spliterator;
+        this.helper = parent.helper;
+        this.targetSize = parent.targetSize;
+    }
+
+    /**
+     * Constructs a new node of type T whose parent is the receiver; must call
+     * the AbstractTask(T, Spliterator) constructor with the receiver and the
+     * provided Spliterator.
+     *
+     * @param spliterator {@code Spliterator} describing the subtree rooted at
+     *        this node, obtained by splitting the parent {@code Spliterator}
+     * @return newly constructed child node
+     */
+    protected abstract K makeChild(Spliterator<P_IN> spliterator);
+
+    /**
+     * Computes the result associated with a leaf node.  Will be called by
+     * {@code compute()} and the result passed to @{code setLocalResult()}
+     *
+     * @return the computed result of a leaf node
+     */
+    protected abstract R doLeaf();
+
+    /**
+     * Returns a suggested target leaf size based on the initial size estimate.
+     *
+     * @return suggested target leaf size
+     */
+    public static long suggestTargetSize(long sizeEstimate) {
+        long est = sizeEstimate / LEAF_TARGET;
+        return est > 0L ? est : 1L;
+    }
+
+    /**
+     * Returns the targetSize, initializing it via the supplied
+     * size estimate if not already initialized.
+     */
+    protected final long getTargetSize(long sizeEstimate) {
+        long s;
+        return ((s = targetSize) != 0 ? s :
+                (targetSize = suggestTargetSize(sizeEstimate)));
+    }
+
+    /**
+     * Returns the local result, if any. Subclasses should use
+     * {@link #setLocalResult(Object)} and {@link #getLocalResult()} to manage
+     * results.  This returns the local result so that calls from within the
+     * fork-join framework will return the correct result.
+     *
+     * @return local result for this node previously stored with
+     * {@link #setLocalResult}
+     */
+    @Override
+    public R getRawResult() {
+        return localResult;
+    }
+
+    /**
+     * Does nothing; instead, subclasses should use
+     * {@link #setLocalResult(Object)}} to manage results.
+     *
+     * @param result must be null, or an exception is thrown (this is a safety
+     *        tripwire to detect when {@code setRawResult()} is being used
+     *        instead of {@code setLocalResult()}
+     */
+    @Override
+    protected void setRawResult(R result) {
+        if (result != null)
+            throw new IllegalStateException();
+    }
+
+    /**
+     * Retrieves a result previously stored with {@link #setLocalResult}
+     *
+     * @return local result for this node previously stored with
+     * {@link #setLocalResult}
+     */
+    protected R getLocalResult() {
+        return localResult;
+    }
+
+    /**
+     * Associates the result with the task, can be retrieved with
+     * {@link #getLocalResult}
+     *
+     * @param localResult local result for this node
+     */
+    protected void setLocalResult(R localResult) {
+        this.localResult = localResult;
+    }
+
+    /**
+     * Indicates whether this task is a leaf node.  (Only valid after
+     * {@link #compute} has been called on this node).  If the node is not a
+     * leaf node, then children will be non-null and numChildren will be
+     * positive.
+     *
+     * @return {@code true} if this task is a leaf node
+     */
+    protected boolean isLeaf() {
+        return leftChild == null;
+    }
+
+    /**
+     * Indicates whether this task is the root node
+     *
+     * @return {@code true} if this task is the root node.
+     */
+    protected boolean isRoot() {
+        return getParent() == null;
+    }
+
+    /**
+     * Returns the parent of this task, or null if this task is the root
+     *
+     * @return the parent of this task, or null if this task is the root
+     */
+    @SuppressWarnings("unchecked")
+    protected K getParent() {
+        return (K) getCompleter();
+    }
+
+    /**
+     * Decides whether or not to split a task further or compute it
+     * directly. If computing directly, calls {@code doLeaf} and pass
+     * the result to {@code setRawResult}. Otherwise splits off
+     * subtasks, forking one and continuing as the other.
+     *
+     * <p> The method is structured to conserve resources across a
+     * range of uses.  The loop continues with one of the child tasks
+     * when split, to avoid deep recursion. To cope with spliterators
+     * that may be systematically biased toward left-heavy or
+     * right-heavy splits, we alternate which child is forked versus
+     * continued in the loop.
+     */
+    @Override
+    public void compute() {
+        Spliterator<P_IN> rs = spliterator, ls; // right, left spliterators
+        long sizeEstimate = rs.estimateSize();
+        long sizeThreshold = getTargetSize(sizeEstimate);
+        boolean forkRight = false;
+        @SuppressWarnings("unchecked") K task = (K) this;
+        while (sizeEstimate > sizeThreshold && (ls = rs.trySplit()) != null) {
+            K leftChild, rightChild, taskToFork;
+            task.leftChild  = leftChild = task.makeChild(ls);
+            task.rightChild = rightChild = task.makeChild(rs);
+            task.setPendingCount(1);
+            if (forkRight) {
+                forkRight = false;
+                rs = ls;
+                task = leftChild;
+                taskToFork = rightChild;
+            }
+            else {
+                forkRight = true;
+                task = rightChild;
+                taskToFork = leftChild;
+            }
+            taskToFork.fork();
+            sizeEstimate = rs.estimateSize();
+        }
+        task.setLocalResult(task.doLeaf());
+        task.tryComplete();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote
+     * Clears spliterator and children fields.  Overriders MUST call
+     * {@code super.onCompletion} as the last thing they do if they want these
+     * cleared.
+     */
+    @Override
+    public void onCompletion(CountedCompleter<?> caller) {
+        spliterator = null;
+        leftChild = rightChild = null;
+    }
+
+    /**
+     * Returns whether this node is a "leftmost" node -- whether the path from
+     * the root to this node involves only traversing leftmost child links.  For
+     * a leaf node, this means it is the first leaf node in the encounter order.
+     *
+     * @return {@code true} if this node is a "leftmost" node
+     */
+    protected boolean isLeftmostNode() {
+        @SuppressWarnings("unchecked")
+        K node = (K) this;
+        while (node != null) {
+            K parent = node.getParent();
+            if (parent != null && parent.leftChild != node)
+                return false;
+            node = parent;
+        }
+        return true;
+    }
+}
diff --git a/java/util/stream/BaseStream.java b/java/util/stream/BaseStream.java
new file mode 100644
index 0000000..35d46e0
--- /dev/null
+++ b/java/util/stream/BaseStream.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.IntConsumer;
+import java.util.function.Predicate;
+
+/**
+ * Base interface for streams, which are sequences of elements supporting
+ * sequential and parallel aggregate operations.  The following example
+ * illustrates an aggregate operation using the stream types {@link Stream}
+ * and {@link IntStream}, computing the sum of the weights of the red widgets:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism, which governs the behavior of all stream types.
+ *
+ * @param <T> the type of the stream elements
+ * @param <S> the type of of the stream implementing {@code BaseStream}
+ * @since 1.8
+ * @see Stream
+ * @see IntStream
+ * @see LongStream
+ * @see DoubleStream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface BaseStream<T, S extends BaseStream<T, S>>
+        extends AutoCloseable {
+    /**
+     * Returns an iterator for the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return the element iterator for this stream
+     */
+    Iterator<T> iterator();
+
+    /**
+     * Returns a spliterator for the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return the element spliterator for this stream
+     */
+    Spliterator<T> spliterator();
+
+    /**
+     * Returns whether this stream, if a terminal operation were to be executed,
+     * would execute in parallel.  Calling this method after invoking an
+     * terminal stream operation method may yield unpredictable results.
+     *
+     * @return {@code true} if this stream would execute in parallel if executed
+     */
+    boolean isParallel();
+
+    /**
+     * Returns an equivalent stream that is sequential.  May return
+     * itself, either because the stream was already sequential, or because
+     * the underlying stream state was modified to be sequential.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a sequential stream
+     */
+    S sequential();
+
+    /**
+     * Returns an equivalent stream that is parallel.  May return
+     * itself, either because the stream was already parallel, or because
+     * the underlying stream state was modified to be parallel.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a parallel stream
+     */
+    S parallel();
+
+    /**
+     * Returns an equivalent stream that is
+     * <a href="package-summary.html#Ordering">unordered</a>.  May return
+     * itself, either because the stream was already unordered, or because
+     * the underlying stream state was modified to be unordered.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return an unordered stream
+     */
+    S unordered();
+
+    /**
+     * Returns an equivalent stream with an additional close handler.  Close
+     * handlers are run when the {@link #close()} method
+     * is called on the stream, and are executed in the order they were
+     * added.  All close handlers are run, even if earlier close handlers throw
+     * exceptions.  If any close handler throws an exception, the first
+     * exception thrown will be relayed to the caller of {@code close()}, with
+     * any remaining exceptions added to that exception as suppressed exceptions
+     * (unless one of the remaining exceptions is the same exception as the
+     * first exception, since an exception cannot suppress itself.)  May
+     * return itself.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param closeHandler A task to execute when the stream is closed
+     * @return a stream with a handler that is run if the stream is closed
+     */
+    S onClose(Runnable closeHandler);
+
+    /**
+     * Closes this stream, causing all close handlers for this stream pipeline
+     * to be called.
+     *
+     * @see AutoCloseable#close()
+     */
+    @Override
+    void close();
+}
diff --git a/java/util/stream/Collector.java b/java/util/stream/Collector.java
new file mode 100644
index 0000000..e409d56
--- /dev/null
+++ b/java/util/stream/Collector.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * A <a href="package-summary.html#Reduction">mutable reduction operation</a> that
+ * accumulates input elements into a mutable result container, optionally transforming
+ * the accumulated result into a final representation after all input elements
+ * have been processed.  Reduction operations can be performed either sequentially
+ * or in parallel.
+ *
+ * <p>Examples of mutable reduction operations include:
+ * accumulating elements into a {@code Collection}; concatenating
+ * strings using a {@code StringBuilder}; computing summary information about
+ * elements such as sum, min, max, or average; computing "pivot table" summaries
+ * such as "maximum valued transaction by seller", etc.  The class {@link Collectors}
+ * provides implementations of many common mutable reductions.
+ *
+ * <p>A {@code Collector} is specified by four functions that work together to
+ * accumulate entries into a mutable result container, and optionally perform
+ * a final transform on the result.  They are: <ul>
+ *     <li>creation of a new result container ({@link #supplier()})</li>
+ *     <li>incorporating a new data element into a result container ({@link #accumulator()})</li>
+ *     <li>combining two result containers into one ({@link #combiner()})</li>
+ *     <li>performing an optional final transform on the container ({@link #finisher()})</li>
+ * </ul>
+ *
+ * <p>Collectors also have a set of characteristics, such as
+ * {@link Characteristics#CONCURRENT}, that provide hints that can be used by a
+ * reduction implementation to provide better performance.
+ *
+ * <p>A sequential implementation of a reduction using a collector would
+ * create a single result container using the supplier function, and invoke the
+ * accumulator function once for each input element.  A parallel implementation
+ * would partition the input, create a result container for each partition,
+ * accumulate the contents of each partition into a subresult for that partition,
+ * and then use the combiner function to merge the subresults into a combined
+ * result.
+ *
+ * <p>To ensure that sequential and parallel executions produce equivalent
+ * results, the collector functions must satisfy an <em>identity</em> and an
+ * <a href="package-summary.html#Associativity">associativity</a> constraints.
+ *
+ * <p>The identity constraint says that for any partially accumulated result,
+ * combining it with an empty result container must produce an equivalent
+ * result.  That is, for a partially accumulated result {@code a} that is the
+ * result of any series of accumulator and combiner invocations, {@code a} must
+ * be equivalent to {@code combiner.apply(a, supplier.get())}.
+ *
+ * <p>The associativity constraint says that splitting the computation must
+ * produce an equivalent result.  That is, for any input elements {@code t1}
+ * and {@code t2}, the results {@code r1} and {@code r2} in the computation
+ * below must be equivalent:
+ * <pre>{@code
+ *     A a1 = supplier.get();
+ *     accumulator.accept(a1, t1);
+ *     accumulator.accept(a1, t2);
+ *     R r1 = finisher.apply(a1);  // result without splitting
+ *
+ *     A a2 = supplier.get();
+ *     accumulator.accept(a2, t1);
+ *     A a3 = supplier.get();
+ *     accumulator.accept(a3, t2);
+ *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
+ * } </pre>
+ *
+ * <p>For collectors that do not have the {@code UNORDERED} characteristic,
+ * two accumulated results {@code a1} and {@code a2} are equivalent if
+ * {@code finisher.apply(a1).equals(finisher.apply(a2))}.  For unordered
+ * collectors, equivalence is relaxed to allow for non-equality related to
+ * differences in order.  (For example, an unordered collector that accumulated
+ * elements to a {@code List} would consider two lists equivalent if they
+ * contained the same elements, ignoring order.)
+ *
+ * <p>Libraries that implement reduction based on {@code Collector}, such as
+ * {@link Stream#collect(Collector)}, must adhere to the following constraints:
+ * <ul>
+ *     <li>The first argument passed to the accumulator function, both
+ *     arguments passed to the combiner function, and the argument passed to the
+ *     finisher function must be the result of a previous invocation of the
+ *     result supplier, accumulator, or combiner functions.</li>
+ *     <li>The implementation should not do anything with the result of any of
+ *     the result supplier, accumulator, or combiner functions other than to
+ *     pass them again to the accumulator, combiner, or finisher functions,
+ *     or return them to the caller of the reduction operation.</li>
+ *     <li>If a result is passed to the combiner or finisher
+ *     function, and the same object is not returned from that function, it is
+ *     never used again.</li>
+ *     <li>Once a result is passed to the combiner or finisher function, it
+ *     is never passed to the accumulator function again.</li>
+ *     <li>For non-concurrent collectors, any result returned from the result
+ *     supplier, accumulator, or combiner functions must be serially
+ *     thread-confined.  This enables collection to occur in parallel without
+ *     the {@code Collector} needing to implement any additional synchronization.
+ *     The reduction implementation must manage that the input is properly
+ *     partitioned, that partitions are processed in isolation, and combining
+ *     happens only after accumulation is complete.</li>
+ *     <li>For concurrent collectors, an implementation is free to (but not
+ *     required to) implement reduction concurrently.  A concurrent reduction
+ *     is one where the accumulator function is called concurrently from
+ *     multiple threads, using the same concurrently-modifiable result container,
+ *     rather than keeping the result isolated during accumulation.
+ *     A concurrent reduction should only be applied if the collector has the
+ *     {@link Characteristics#UNORDERED} characteristics or if the
+ *     originating data is unordered.</li>
+ * </ul>
+ *
+ * <p>In addition to the predefined implementations in {@link Collectors}, the
+ * static factory methods {@link #of(Supplier, BiConsumer, BinaryOperator, Characteristics...)}
+ * can be used to construct collectors.  For example, you could create a collector
+ * that accumulates widgets into a {@code TreeSet} with:
+ *
+ * <pre>{@code
+ *     Collector<Widget, ?, TreeSet<Widget>> intoSet =
+ *         Collector.of(TreeSet::new, TreeSet::add,
+ *                      (left, right) -> { left.addAll(right); return left; });
+ * }</pre>
+ *
+ * (This behavior is also implemented by the predefined collector
+ * {@link Collectors#toCollection(Supplier)}).
+ *
+ * @apiNote
+ * Performing a reduction operation with a {@code Collector} should produce a
+ * result equivalent to:
+ * <pre>{@code
+ *     R container = collector.supplier().get();
+ *     for (T t : data)
+ *         collector.accumulator().accept(container, t);
+ *     return collector.finisher().apply(container);
+ * }</pre>
+ *
+ * <p>However, the library is free to partition the input, perform the reduction
+ * on the partitions, and then use the combiner function to combine the partial
+ * results to achieve a parallel reduction.  (Depending on the specific reduction
+ * operation, this may perform better or worse, depending on the relative cost
+ * of the accumulator and combiner functions.)
+ *
+ * <p>Collectors are designed to be <em>composed</em>; many of the methods
+ * in {@link Collectors} are functions that take a collector and produce
+ * a new collector.  For example, given the following collector that computes
+ * the sum of the salaries of a stream of employees:
+ *
+ * <pre>{@code
+ *     Collector<Employee, ?, Integer> summingSalaries
+ *         = Collectors.summingInt(Employee::getSalary))
+ * }</pre>
+ *
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse the "sum of salaries" logic using
+ * {@link Collectors#groupingBy(Function, Collector)}:
+ *
+ * <pre>{@code
+ *     Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
+ *         = Collectors.groupingBy(Employee::getDepartment, summingSalaries);
+ * }</pre>
+ *
+ * @see Stream#collect(Collector)
+ * @see Collectors
+ *
+ * @param <T> the type of input elements to the reduction operation
+ * @param <A> the mutable accumulation type of the reduction operation (often
+ *            hidden as an implementation detail)
+ * @param <R> the result type of the reduction operation
+ * @since 1.8
+ */
+public interface Collector<T, A, R> {
+    /**
+     * A function that creates and returns a new mutable result container.
+     *
+     * @return a function which returns a new, mutable result container
+     */
+    Supplier<A> supplier();
+
+    /**
+     * A function that folds a value into a mutable result container.
+     *
+     * @return a function which folds a value into a mutable result container
+     */
+    BiConsumer<A, T> accumulator();
+
+    /**
+     * A function that accepts two partial results and merges them.  The
+     * combiner function may fold state from one argument into the other and
+     * return that, or may return a new result container.
+     *
+     * @return a function which combines two partial results into a combined
+     * result
+     */
+    BinaryOperator<A> combiner();
+
+    /**
+     * Perform the final transformation from the intermediate accumulation type
+     * {@code A} to the final result type {@code R}.
+     *
+     * <p>If the characteristic {@code IDENTITY_TRANSFORM} is
+     * set, this function may be presumed to be an identity transform with an
+     * unchecked cast from {@code A} to {@code R}.
+     *
+     * @return a function which transforms the intermediate result to the final
+     * result
+     */
+    Function<A, R> finisher();
+
+    /**
+     * Returns a {@code Set} of {@code Collector.Characteristics} indicating
+     * the characteristics of this Collector.  This set should be immutable.
+     *
+     * @return an immutable set of collector characteristics
+     */
+    Set<Characteristics> characteristics();
+
+    /**
+     * Returns a new {@code Collector} described by the given {@code supplier},
+     * {@code accumulator}, and {@code combiner} functions.  The resulting
+     * {@code Collector} has the {@code Collector.Characteristics.IDENTITY_FINISH}
+     * characteristic.
+     *
+     * @param supplier The supplier function for the new collector
+     * @param accumulator The accumulator function for the new collector
+     * @param combiner The combiner function for the new collector
+     * @param characteristics The collector characteristics for the new
+     *                        collector
+     * @param <T> The type of input elements for the new collector
+     * @param <R> The type of intermediate accumulation result, and final result,
+     *           for the new collector
+     * @throws NullPointerException if any argument is null
+     * @return the new {@code Collector}
+     */
+    public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
+                                              BiConsumer<R, T> accumulator,
+                                              BinaryOperator<R> combiner,
+                                              Characteristics... characteristics) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        Objects.requireNonNull(characteristics);
+        Set<Characteristics> cs = (characteristics.length == 0)
+                                  ? Collectors.CH_ID
+                                  : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
+                                                                           characteristics));
+        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);
+    }
+
+    /**
+     * Returns a new {@code Collector} described by the given {@code supplier},
+     * {@code accumulator}, {@code combiner}, and {@code finisher} functions.
+     *
+     * @param supplier The supplier function for the new collector
+     * @param accumulator The accumulator function for the new collector
+     * @param combiner The combiner function for the new collector
+     * @param finisher The finisher function for the new collector
+     * @param characteristics The collector characteristics for the new
+     *                        collector
+     * @param <T> The type of input elements for the new collector
+     * @param <A> The intermediate accumulation type of the new collector
+     * @param <R> The final result type of the new collector
+     * @throws NullPointerException if any argument is null
+     * @return the new {@code Collector}
+     */
+    public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
+                                                 BiConsumer<A, T> accumulator,
+                                                 BinaryOperator<A> combiner,
+                                                 Function<A, R> finisher,
+                                                 Characteristics... characteristics) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        Objects.requireNonNull(finisher);
+        Objects.requireNonNull(characteristics);
+        Set<Characteristics> cs = Collectors.CH_NOID;
+        if (characteristics.length > 0) {
+            cs = EnumSet.noneOf(Characteristics.class);
+            Collections.addAll(cs, characteristics);
+            cs = Collections.unmodifiableSet(cs);
+        }
+        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
+    }
+
+    /**
+     * Characteristics indicating properties of a {@code Collector}, which can
+     * be used to optimize reduction implementations.
+     */
+    enum Characteristics {
+        /**
+         * Indicates that this collector is <em>concurrent</em>, meaning that
+         * the result container can support the accumulator function being
+         * called concurrently with the same result container from multiple
+         * threads.
+         *
+         * <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED},
+         * then it should only be evaluated concurrently if applied to an
+         * unordered data source.
+         */
+        CONCURRENT,
+
+        /**
+         * Indicates that the collection operation does not commit to preserving
+         * the encounter order of input elements.  (This might be true if the
+         * result container has no intrinsic order, such as a {@link Set}.)
+         */
+        UNORDERED,
+
+        /**
+         * Indicates that the finisher function is the identity function and
+         * can be elided.  If set, it must be the case that an unchecked cast
+         * from A to R will succeed.
+         */
+        IDENTITY_FINISH
+    }
+}
diff --git a/java/util/stream/CollectorOps.java b/java/util/stream/CollectorOps.java
new file mode 100644
index 0000000..c849415
--- /dev/null
+++ b/java/util/stream/CollectorOps.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+/** Test helper class for java.util.stream test framework */
+public final class CollectorOps {
+    private CollectorOps() { }
+
+    public static <E_IN> StatefulTestOp<E_IN> collector() {
+        return new StatefulCollector<>(0, StreamShape.REFERENCE);
+    }
+
+    /* Utility classes for collecting output of intermediate pipeline stages */
+    public static class StatefulCollector<E_IN> implements StatefulTestOp<E_IN> {
+        private final int opFlags;
+        private final StreamShape inputShape;
+
+        public StatefulCollector(int opFlags, StreamShape inputShape) {
+            this.opFlags = opFlags;
+            this.inputShape = inputShape;
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public StreamShape outputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public int opGetFlags() {
+            return opFlags;
+        }
+
+        @Override
+        public Sink<E_IN> opWrapSink(int flags, boolean parallel, Sink<E_IN> sink) {
+            return sink;
+        }
+
+        @Override
+        public <P_IN> Node<E_IN> opEvaluateParallel(PipelineHelper<E_IN> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    IntFunction<E_IN[]> generator) {
+            return helper.evaluate(spliterator, false, generator);
+        }
+    }
+
+    public static class TestParallelSizedOp<T> extends StatefulCollector<T> {
+        public TestParallelSizedOp() {
+            this(StreamShape.REFERENCE);
+        }
+
+        protected TestParallelSizedOp(StreamShape shape) {
+            super(0, shape);
+        }
+
+        @Override
+        public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 IntFunction<T[]> generator) {
+            int flags = helper.getStreamAndOpFlags();
+
+            Assert.assertTrue(StreamOpFlag.SIZED.isKnown(flags));
+            return super.opEvaluateParallel(helper, spliterator, generator);
+        }
+
+        public static class OfInt extends TestParallelSizedOp<Integer> {
+            public OfInt() {
+                super(StreamShape.INT_VALUE);
+            }
+        }
+
+        public static class OfLong extends TestParallelSizedOp<Long> {
+            public OfLong() {
+                super(StreamShape.LONG_VALUE);
+            }
+        }
+
+        public static class OfDouble extends TestParallelSizedOp<Double> {
+            public OfDouble() {
+                super(StreamShape.DOUBLE_VALUE);
+            }
+        }
+    }
+}
diff --git a/java/util/stream/Collectors.java b/java/util/stream/Collectors.java
new file mode 100644
index 0000000..a338ec2
--- /dev/null
+++ b/java/util/stream/Collectors.java
@@ -0,0 +1,1568 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.DoubleSummaryStatistics;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IntSummaryStatistics;
+import java.util.Iterator;
+import java.util.List;
+import java.util.LongSummaryStatistics;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+/**
+ * Implementations of {@link Collector} that implement various useful reduction
+ * operations, such as accumulating elements into collections, summarizing
+ * elements according to various criteria, etc.
+ *
+ * <p>The following are examples of using the predefined collectors to perform
+ * common mutable reduction tasks:
+ *
+ * <pre>{@code
+ *     // Accumulate names into a List
+ *     List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
+ *
+ *     // Accumulate names into a TreeSet
+ *     Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
+ *
+ *     // Convert elements to strings and concatenate them, separated by commas
+ *     String joined = things.stream()
+ *                           .map(Object::toString)
+ *                           .collect(Collectors.joining(", "));
+ *
+ *     // Compute sum of salaries of employee
+ *     int total = employees.stream()
+ *                          .collect(Collectors.summingInt(Employee::getSalary)));
+ *
+ *     // Group employees by department
+ *     Map<Department, List<Employee>> byDept
+ *         = employees.stream()
+ *                    .collect(Collectors.groupingBy(Employee::getDepartment));
+ *
+ *     // Compute sum of salaries by department
+ *     Map<Department, Integer> totalByDept
+ *         = employees.stream()
+ *                    .collect(Collectors.groupingBy(Employee::getDepartment,
+ *                                                   Collectors.summingInt(Employee::getSalary)));
+ *
+ *     // Partition students into passing and failing
+ *     Map<Boolean, List<Student>> passingFailing =
+ *         students.stream()
+ *                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
+ *
+ * }</pre>
+ *
+ * @since 1.8
+ */
+public final class Collectors {
+
+    static final Set<Collector.Characteristics> CH_CONCURRENT_ID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
+                                                     Collector.Characteristics.UNORDERED,
+                                                     Collector.Characteristics.IDENTITY_FINISH));
+    static final Set<Collector.Characteristics> CH_CONCURRENT_NOID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
+                                                     Collector.Characteristics.UNORDERED));
+    static final Set<Collector.Characteristics> CH_ID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
+    static final Set<Collector.Characteristics> CH_UNORDERED_ID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
+                                                     Collector.Characteristics.IDENTITY_FINISH));
+    static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
+
+    private Collectors() { }
+
+    /**
+     * Returns a merge function, suitable for use in
+     * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or
+     * {@link #toMap(Function, Function, BinaryOperator) toMap()}, which always
+     * throws {@code IllegalStateException}.  This can be used to enforce the
+     * assumption that the elements being collected are distinct.
+     *
+     * @param <T> the type of input arguments to the merge function
+     * @return a merge function which always throw {@code IllegalStateException}
+     */
+    private static <T> BinaryOperator<T> throwingMerger() {
+        return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <I, R> Function<I, R> castingIdentity() {
+        return i -> (R) i;
+    }
+
+    /**
+     * Simple implementation class for {@code Collector}.
+     *
+     * @param <T> the type of elements to be collected
+     * @param <R> the type of the result
+     */
+    static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
+        private final Supplier<A> supplier;
+        private final BiConsumer<A, T> accumulator;
+        private final BinaryOperator<A> combiner;
+        private final Function<A, R> finisher;
+        private final Set<Characteristics> characteristics;
+
+        CollectorImpl(Supplier<A> supplier,
+                      BiConsumer<A, T> accumulator,
+                      BinaryOperator<A> combiner,
+                      Function<A,R> finisher,
+                      Set<Characteristics> characteristics) {
+            this.supplier = supplier;
+            this.accumulator = accumulator;
+            this.combiner = combiner;
+            this.finisher = finisher;
+            this.characteristics = characteristics;
+        }
+
+        CollectorImpl(Supplier<A> supplier,
+                      BiConsumer<A, T> accumulator,
+                      BinaryOperator<A> combiner,
+                      Set<Characteristics> characteristics) {
+            this(supplier, accumulator, combiner, castingIdentity(), characteristics);
+        }
+
+        @Override
+        public BiConsumer<A, T> accumulator() {
+            return accumulator;
+        }
+
+        @Override
+        public Supplier<A> supplier() {
+            return supplier;
+        }
+
+        @Override
+        public BinaryOperator<A> combiner() {
+            return combiner;
+        }
+
+        @Override
+        public Function<A, R> finisher() {
+            return finisher;
+        }
+
+        @Override
+        public Set<Characteristics> characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code Collection}, in encounter order.  The {@code Collection} is
+     * created by the provided factory.
+     *
+     * @param <T> the type of the input elements
+     * @param <C> the type of the resulting {@code Collection}
+     * @param collectionFactory a {@code Supplier} which returns a new, empty
+     * {@code Collection} of the appropriate type
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code Collection}, in encounter order
+     */
+    public static <T, C extends Collection<T>>
+    Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
+        return new CollectorImpl<>(collectionFactory, Collection<T>::add,
+                                   (r1, r2) -> { r1.addAll(r2); return r1; },
+                                   CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code List}. There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code List} returned; if more
+     * control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code List}, in encounter order
+     */
+    public static <T>
+    Collector<T, ?, List<T>> toList() {
+        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
+                                   (left, right) -> { left.addAll(right); return left; },
+                                   CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code Set}. There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Set} returned; if more
+     * control over the returned {@code Set} is required, use
+     * {@link #toCollection(Supplier)}.
+     *
+     * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
+     * Collector.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code Set}
+     */
+    public static <T>
+    Collector<T, ?, Set<T>> toSet() {
+        return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
+                                   (left, right) -> { left.addAll(right); return left; },
+                                   CH_UNORDERED_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} that concatenates the input elements into a
+     * {@code String}, in encounter order.
+     *
+     * @return a {@code Collector} that concatenates the input elements into a
+     * {@code String}, in encounter order
+     */
+    public static Collector<CharSequence, ?, String> joining() {
+        return new CollectorImpl<CharSequence, StringBuilder, String>(
+                StringBuilder::new, StringBuilder::append,
+                (r1, r2) -> { r1.append(r2); return r1; },
+                StringBuilder::toString, CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that concatenates the input elements,
+     * separated by the specified delimiter, in encounter order.
+     *
+     * @param delimiter the delimiter to be used between each element
+     * @return A {@code Collector} which concatenates CharSequence elements,
+     * separated by the specified delimiter, in encounter order
+     */
+    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
+        return joining(delimiter, "", "");
+    }
+
+    /**
+     * Returns a {@code Collector} that concatenates the input elements,
+     * separated by the specified delimiter, with the specified prefix and
+     * suffix, in encounter order.
+     *
+     * @param delimiter the delimiter to be used between each element
+     * @param  prefix the sequence of characters to be used at the beginning
+     *                of the joined result
+     * @param  suffix the sequence of characters to be used at the end
+     *                of the joined result
+     * @return A {@code Collector} which concatenates CharSequence elements,
+     * separated by the specified delimiter, in encounter order
+     */
+    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
+                                                             CharSequence prefix,
+                                                             CharSequence suffix) {
+        return new CollectorImpl<>(
+                () -> new StringJoiner(delimiter, prefix, suffix),
+                StringJoiner::add, StringJoiner::merge,
+                StringJoiner::toString, CH_NOID);
+    }
+
+    /**
+     * {@code BinaryOperator<Map>} that merges the contents of its right
+     * argument into its left argument, using the provided merge function to
+     * handle duplicate keys.
+     *
+     * @param <K> type of the map keys
+     * @param <V> type of the map values
+     * @param <M> type of the map
+     * @param mergeFunction A merge function suitable for
+     * {@link Map#merge(Object, Object, BiFunction) Map.merge()}
+     * @return a merge function for two maps
+     */
+    private static <K, V, M extends Map<K,V>>
+    BinaryOperator<M> mapMerger(BinaryOperator<V> mergeFunction) {
+        return (m1, m2) -> {
+            for (Map.Entry<K,V> e : m2.entrySet())
+                m1.merge(e.getKey(), e.getValue(), mergeFunction);
+            return m1;
+        };
+    }
+
+    /**
+     * Adapts a {@code Collector} accepting elements of type {@code U} to one
+     * accepting elements of type {@code T} by applying a mapping function to
+     * each input element before accumulation.
+     *
+     * @apiNote
+     * The {@code mapping()} collectors are most useful when used in a
+     * multi-level reduction, such as downstream of a {@code groupingBy} or
+     * {@code partitioningBy}.  For example, given a stream of
+     * {@code Person}, to accumulate the set of last names in each city:
+     * <pre>{@code
+     *     Map<City, Set<String>> lastNamesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <U> type of elements accepted by downstream collector
+     * @param <A> intermediate accumulation type of the downstream collector
+     * @param <R> result type of collector
+     * @param mapper a function to be applied to the input elements
+     * @param downstream a collector which will accept mapped values
+     * @return a collector which applies the mapping function to the input
+     * elements and provides the mapped results to the downstream collector
+     */
+    public static <T, U, A, R>
+    Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
+                               Collector<? super U, A, R> downstream) {
+        BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
+        return new CollectorImpl<>(downstream.supplier(),
+                                   (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)),
+                                   downstream.combiner(), downstream.finisher(),
+                                   downstream.characteristics());
+    }
+
+    /**
+     * Adapts a {@code Collector} to perform an additional finishing
+     * transformation.  For example, one could adapt the {@link #toList()}
+     * collector to always produce an immutable list with:
+     * <pre>{@code
+     *     List<String> people
+     *         = people.stream().collect(collectingAndThen(toList(), Collections::unmodifiableList));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <A> intermediate accumulation type of the downstream collector
+     * @param <R> result type of the downstream collector
+     * @param <RR> result type of the resulting collector
+     * @param downstream a collector
+     * @param finisher a function to be applied to the final result of the downstream collector
+     * @return a collector which performs the action of the downstream collector,
+     * followed by an additional finishing step
+     */
+    public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,
+                                                                Function<R,RR> finisher) {
+        Set<Collector.Characteristics> characteristics = downstream.characteristics();
+        if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            if (characteristics.size() == 1)
+                characteristics = Collectors.CH_NOID;
+            else {
+                characteristics = EnumSet.copyOf(characteristics);
+                characteristics.remove(Collector.Characteristics.IDENTITY_FINISH);
+                characteristics = Collections.unmodifiableSet(characteristics);
+            }
+        }
+        return new CollectorImpl<>(downstream.supplier(),
+                                   downstream.accumulator(),
+                                   downstream.combiner(),
+                                   downstream.finisher().andThen(finisher),
+                                   characteristics);
+    }
+
+    /**
+     * Returns a {@code Collector} accepting elements of type {@code T} that
+     * counts the number of input elements.  If no elements are present, the
+     * result is 0.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(0L, e -> 1L, Long::sum)
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} that counts the input elements
+     */
+    public static <T> Collector<T, ?, Long>
+    counting() {
+        return reducing(0L, e -> 1L, Long::sum);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the minimal element according
+     * to a given {@code Comparator}, described as an {@code Optional<T>}.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(BinaryOperator.minBy(comparator))
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param comparator a {@code Comparator} for comparing elements
+     * @return a {@code Collector} that produces the minimal value
+     */
+    public static <T> Collector<T, ?, Optional<T>>
+    minBy(Comparator<? super T> comparator) {
+        return reducing(BinaryOperator.minBy(comparator));
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the maximal element according
+     * to a given {@code Comparator}, described as an {@code Optional<T>}.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(BinaryOperator.maxBy(comparator))
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param comparator a {@code Comparator} for comparing elements
+     * @return a {@code Collector} that produces the maximal value
+     */
+    public static <T> Collector<T, ?, Optional<T>>
+    maxBy(Comparator<? super T> comparator) {
+        return reducing(BinaryOperator.maxBy(comparator));
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the sum of a integer-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Integer>
+    summingInt(ToIntFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new int[1],
+                (a, t) -> { a[0] += mapper.applyAsInt(t); },
+                (a, b) -> { a[0] += b[0]; return a; },
+                a -> a[0], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the sum of a long-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Long>
+    summingLong(ToLongFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new long[1],
+                (a, t) -> { a[0] += mapper.applyAsLong(t); },
+                (a, b) -> { a[0] += b[0]; return a; },
+                a -> a[0], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the sum of a double-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * <p>The sum returned can vary depending upon the order in which
+     * values are recorded, due to accumulated rounding error in
+     * addition of values of differing magnitudes. Values sorted by increasing
+     * absolute magnitude tend to yield more accurate results.  If any recorded
+     * value is a {@code NaN} or the sum is at any point a {@code NaN} then the
+     * sum will be {@code NaN}.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    summingDouble(ToDoubleFunction<? super T> mapper) {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the low-order bits of the sum computed via compensated
+         * summation, and index 2 holds the simple sum used to compute
+         * the proper result if the stream contains infinite values of
+         * the same sign.
+         */
+        return new CollectorImpl<>(
+                () -> new double[3],
+                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t));
+                            a[2] += mapper.applyAsDouble(t);},
+                (a, b) -> { sumWithCompensation(a, b[0]);
+                            a[2] += b[2];
+                            return sumWithCompensation(a, b[1]); },
+                a -> computeFinalSum(a),
+                CH_NOID);
+    }
+
+    /**
+     * Incorporate a new double value using Kahan summation /
+     * compensation summation.
+     *
+     * High-order bits of the sum are in intermediateSum[0], low-order
+     * bits of the sum are in intermediateSum[1], any additional
+     * elements are application-specific.
+     *
+     * @param intermediateSum the high-order and low-order words of the intermediate sum
+     * @param value the name value to be included in the running sum
+     */
+    static double[] sumWithCompensation(double[] intermediateSum, double value) {
+        double tmp = value - intermediateSum[1];
+        double sum = intermediateSum[0];
+        double velvel = sum + tmp; // Little wolf of rounding error
+        intermediateSum[1] = (velvel - sum) - tmp;
+        intermediateSum[0] = velvel;
+        return intermediateSum;
+    }
+
+    /**
+     * If the compensated sum is spuriously NaN from accumulating one
+     * or more same-signed infinite values, return the
+     * correctly-signed infinity stored in the simple sum.
+     */
+    static double computeFinalSum(double[] summands) {
+        // Better error bounds to add both terms as the final sum
+        double tmp = summands[0] + summands[1];
+        double simpleSum = summands[summands.length - 1];
+        if (Double.isNaN(tmp) && Double.isInfinite(simpleSum))
+            return simpleSum;
+        else
+            return tmp;
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the arithmetic mean of an integer-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    averagingInt(ToIntFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new long[2],
+                (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
+                (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
+                a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the arithmetic mean of a long-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    averagingLong(ToLongFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new long[2],
+                (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; },
+                (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
+                a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the arithmetic mean of a double-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * <p>The average returned can vary depending upon the order in which
+     * values are recorded, due to accumulated rounding error in
+     * addition of values of differing magnitudes. Values sorted by increasing
+     * absolute magnitude tend to yield more accurate results.  If any recorded
+     * value is a {@code NaN} or the sum is at any point a {@code NaN} then the
+     * average will be {@code NaN}.
+     *
+     * @implNote The {@code double} format can represent all
+     * consecutive integers in the range -2<sup>53</sup> to
+     * 2<sup>53</sup>. If the pipeline has more than 2<sup>53</sup>
+     * values, the divisor in the average computation will saturate at
+     * 2<sup>53</sup>, leading to additional numerical errors.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    averagingDouble(ToDoubleFunction<? super T> mapper) {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the low-order bits of the sum computed via compensated
+         * summation, and index 2 holds the number of values seen.
+         */
+        return new CollectorImpl<>(
+                () -> new double[4],
+                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);},
+                (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; },
+                a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]),
+                CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} which performs a reduction of its
+     * input elements under a specified {@code BinaryOperator} using the
+     * provided identity.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple reduction on a stream,
+     * use {@link Stream#reduce(Object, BinaryOperator)}} instead.
+     *
+     * @param <T> element type for the input and output of the reduction
+     * @param identity the identity value for the reduction (also, the value
+     *                 that is returned when there are no input elements)
+     * @param op a {@code BinaryOperator<T>} used to reduce the input elements
+     * @return a {@code Collector} which implements the reduction operation
+     *
+     * @see #reducing(BinaryOperator)
+     * @see #reducing(Object, Function, BinaryOperator)
+     */
+    public static <T> Collector<T, ?, T>
+    reducing(T identity, BinaryOperator<T> op) {
+        return new CollectorImpl<>(
+                boxSupplier(identity),
+                (a, t) -> { a[0] = op.apply(a[0], t); },
+                (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
+                a -> a[0],
+                CH_NOID);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> Supplier<T[]> boxSupplier(T identity) {
+        return () -> (T[]) new Object[] { identity };
+    }
+
+    /**
+     * Returns a {@code Collector} which performs a reduction of its
+     * input elements under a specified {@code BinaryOperator}.  The result
+     * is described as an {@code Optional<T>}.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple reduction on a stream,
+     * use {@link Stream#reduce(BinaryOperator)} instead.
+     *
+     * <p>For example, given a stream of {@code Person}, to calculate tallest
+     * person in each city:
+     * <pre>{@code
+     *     Comparator<Person> byHeight = Comparator.comparing(Person::getHeight);
+     *     Map<City, Person> tallestByCity
+     *         = people.stream().collect(groupingBy(Person::getCity, reducing(BinaryOperator.maxBy(byHeight))));
+     * }</pre>
+     *
+     * @param <T> element type for the input and output of the reduction
+     * @param op a {@code BinaryOperator<T>} used to reduce the input elements
+     * @return a {@code Collector} which implements the reduction operation
+     *
+     * @see #reducing(Object, BinaryOperator)
+     * @see #reducing(Object, Function, BinaryOperator)
+     */
+    public static <T> Collector<T, ?, Optional<T>>
+    reducing(BinaryOperator<T> op) {
+        class OptionalBox implements Consumer<T> {
+            T value = null;
+            boolean present = false;
+
+            @Override
+            public void accept(T t) {
+                if (present) {
+                    value = op.apply(value, t);
+                }
+                else {
+                    value = t;
+                    present = true;
+                }
+            }
+        }
+
+        return new CollectorImpl<T, OptionalBox, Optional<T>>(
+                OptionalBox::new, OptionalBox::accept,
+                (a, b) -> { if (b.present) a.accept(b.value); return a; },
+                a -> Optional.ofNullable(a.value), CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} which performs a reduction of its
+     * input elements under a specified mapping function and
+     * {@code BinaryOperator}. This is a generalization of
+     * {@link #reducing(Object, BinaryOperator)} which allows a transformation
+     * of the elements before reduction.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple map-reduce on a stream,
+     * use {@link Stream#map(Function)} and {@link Stream#reduce(Object, BinaryOperator)}
+     * instead.
+     *
+     * <p>For example, given a stream of {@code Person}, to calculate the longest
+     * last name of residents in each city:
+     * <pre>{@code
+     *     Comparator<String> byLength = Comparator.comparing(String::length);
+     *     Map<City, String> longestLastNameByCity
+     *         = people.stream().collect(groupingBy(Person::getCity,
+     *                                              reducing(Person::getLastName, BinaryOperator.maxBy(byLength))));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <U> the type of the mapped values
+     * @param identity the identity value for the reduction (also, the value
+     *                 that is returned when there are no input elements)
+     * @param mapper a mapping function to apply to each input value
+     * @param op a {@code BinaryOperator<U>} used to reduce the mapped values
+     * @return a {@code Collector} implementing the map-reduce operation
+     *
+     * @see #reducing(Object, BinaryOperator)
+     * @see #reducing(BinaryOperator)
+     */
+    public static <T, U>
+    Collector<T, ?, U> reducing(U identity,
+                                Function<? super T, ? extends U> mapper,
+                                BinaryOperator<U> op) {
+        return new CollectorImpl<>(
+                boxSupplier(identity),
+                (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); },
+                (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
+                a -> a[0], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a "group by" operation on
+     * input elements of type {@code T}, grouping elements according to a
+     * classification function, and returning the results in a {@code Map}.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The collector produces a {@code Map<K, List<T>>} whose keys are the
+     * values resulting from applying the classification function to the input
+     * elements, and whose corresponding values are {@code List}s containing the
+     * input elements which map to the associated key under the classification
+     * function.
+     *
+     * <p>There are no guarantees on the type, mutability, serializability, or
+     * thread-safety of the {@code Map} or {@code List} objects returned.
+     * @implSpec
+     * This produces a result similar to:
+     * <pre>{@code
+     *     groupingBy(classifier, toList());
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If
+     * preservation of the order in which elements appear in the resulting {@code Map}
+     * collector is not required, using {@link #groupingByConcurrent(Function)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param classifier the classifier function mapping input elements to keys
+     * @return a {@code Collector} implementing the group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingBy(Function, Supplier, Collector)
+     * @see #groupingByConcurrent(Function)
+     */
+    public static <T, K> Collector<T, ?, Map<K, List<T>>>
+    groupingBy(Function<? super T, ? extends K> classifier) {
+        return groupingBy(classifier, toList());
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a cascaded "group by" operation
+     * on input elements of type {@code T}, grouping elements according to a
+     * classification function, and then performing a reduction operation on
+     * the values associated with a given key using the specified downstream
+     * {@code Collector}.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} returned.
+     *
+     * <p>For example, to compute the set of last names of people in each city:
+     * <pre>{@code
+     *     Map<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If
+     * preservation of the order in which elements are presented to the downstream
+     * collector is not required, using {@link #groupingByConcurrent(Function, Collector)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @return a {@code Collector} implementing the cascaded group-by operation
+     * @see #groupingBy(Function)
+     *
+     * @see #groupingBy(Function, Supplier, Collector)
+     * @see #groupingByConcurrent(Function, Collector)
+     */
+    public static <T, K, A, D>
+    Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
+                                          Collector<? super T, A, D> downstream) {
+        return groupingBy(classifier, HashMap::new, downstream);
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a cascaded "group by" operation
+     * on input elements of type {@code T}, grouping elements according to a
+     * classification function, and then performing a reduction operation on
+     * the values associated with a given key using the specified downstream
+     * {@code Collector}.  The {@code Map} produced by the Collector is created
+     * with the supplied factory function.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     *     Map<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity, TreeMap::new,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If
+     * preservation of the order in which elements are presented to the downstream
+     * collector is not required, using {@link #groupingByConcurrent(Function, Supplier, Collector)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param <M> the type of the resulting {@code Map}
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @param mapFactory a function which, when called, produces a new empty
+     *                   {@code Map} of the desired type
+     * @return a {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingBy(Function)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K, D, A, M extends Map<K, D>>
+    Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
+                                  Supplier<M> mapFactory,
+                                  Collector<? super T, A, D> downstream) {
+        Supplier<A> downstreamSupplier = downstream.supplier();
+        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
+        BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
+            K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+            A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+            downstreamAccumulator.accept(container, t);
+        };
+        BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());
+        @SuppressWarnings("unchecked")
+        Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;
+
+        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
+        }
+        else {
+            @SuppressWarnings("unchecked")
+            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
+            Function<Map<K, A>, M> finisher = intermediate -> {
+                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
+                @SuppressWarnings("unchecked")
+                M castResult = (M) intermediate;
+                return castResult;
+            };
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
+        }
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} implementing a "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The collector produces a {@code ConcurrentMap<K, List<T>>} whose keys are the
+     * values resulting from applying the classification function to the input
+     * elements, and whose corresponding values are {@code List}s containing the
+     * input elements which map to the associated key under the classification
+     * function.
+     *
+     * <p>There are no guarantees on the type, mutability, or serializability
+     * of the {@code Map} or {@code List} objects returned, or of the
+     * thread-safety of the {@code List} objects returned.
+     * @implSpec
+     * This produces a result similar to:
+     * <pre>{@code
+     *     groupingByConcurrent(classifier, toList());
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param classifier a classifier function mapping input elements to keys
+     * @return a concurrent, unordered {@code Collector} implementing the group-by operation
+     *
+     * @see #groupingBy(Function)
+     * @see #groupingByConcurrent(Function, Collector)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K>
+    Collector<T, ?, ConcurrentMap<K, List<T>>>
+    groupingByConcurrent(Function<? super T, ? extends K> classifier) {
+        return groupingByConcurrent(classifier, ConcurrentHashMap::new, toList());
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} implementing a cascaded "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function, and then performing a reduction
+     * operation on the values associated with a given key using the specified
+     * downstream {@code Collector}.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     *     ConcurrentMap<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingByConcurrent(Person::getCity,
+     *                                                        mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @return a concurrent, unordered {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingByConcurrent(Function)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K, A, D>
+    Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier,
+                                                              Collector<? super T, A, D> downstream) {
+        return groupingByConcurrent(classifier, ConcurrentHashMap::new, downstream);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} implementing a cascaded "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function, and then performing a reduction
+     * operation on the values associated with a given key using the specified
+     * downstream {@code Collector}.  The {@code ConcurrentMap} produced by the
+     * Collector is created with the supplied factory function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     *     ConcurrentMap<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity, ConcurrentSkipListMap::new,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param <M> the type of the resulting {@code ConcurrentMap}
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @param mapFactory a function which, when called, produces a new empty
+     *                   {@code ConcurrentMap} of the desired type
+     * @return a concurrent, unordered {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingByConcurrent(Function)
+     * @see #groupingByConcurrent(Function, Collector)
+     * @see #groupingBy(Function, Supplier, Collector)
+     */
+    public static <T, K, A, D, M extends ConcurrentMap<K, D>>
+    Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
+                                            Supplier<M> mapFactory,
+                                            Collector<? super T, A, D> downstream) {
+        Supplier<A> downstreamSupplier = downstream.supplier();
+        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
+        BinaryOperator<ConcurrentMap<K, A>> merger = Collectors.<K, A, ConcurrentMap<K, A>>mapMerger(downstream.combiner());
+        @SuppressWarnings("unchecked")
+        Supplier<ConcurrentMap<K, A>> mangledFactory = (Supplier<ConcurrentMap<K, A>>) mapFactory;
+        BiConsumer<ConcurrentMap<K, A>, T> accumulator;
+        if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) {
+            accumulator = (m, t) -> {
+                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+                A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+                downstreamAccumulator.accept(resultContainer, t);
+            };
+        }
+        else {
+            accumulator = (m, t) -> {
+                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+                A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+                synchronized (resultContainer) {
+                    downstreamAccumulator.accept(resultContainer, t);
+                }
+            };
+        }
+
+        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_CONCURRENT_ID);
+        }
+        else {
+            @SuppressWarnings("unchecked")
+            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
+            Function<ConcurrentMap<K, A>, M> finisher = intermediate -> {
+                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
+                @SuppressWarnings("unchecked")
+                M castResult = (M) intermediate;
+                return castResult;
+            };
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_CONCURRENT_NOID);
+        }
+    }
+
+    /**
+     * Returns a {@code Collector} which partitions the input elements according
+     * to a {@code Predicate}, and organizes them into a
+     * {@code Map<Boolean, List<T>>}.
+     *
+     * There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} returned.
+     *
+     * @param <T> the type of the input elements
+     * @param predicate a predicate used for classifying input elements
+     * @return a {@code Collector} implementing the partitioning operation
+     *
+     * @see #partitioningBy(Predicate, Collector)
+     */
+    public static <T>
+    Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
+        return partitioningBy(predicate, toList());
+    }
+
+    /**
+     * Returns a {@code Collector} which partitions the input elements according
+     * to a {@code Predicate}, reduces the values in each partition according to
+     * another {@code Collector}, and organizes them into a
+     * {@code Map<Boolean, D>} whose values are the result of the downstream
+     * reduction.
+     *
+     * <p>There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} returned.
+     *
+     * @param <T> the type of the input elements
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param predicate a predicate used for classifying input elements
+     * @param downstream a {@code Collector} implementing the downstream
+     *                   reduction
+     * @return a {@code Collector} implementing the cascaded partitioning
+     *         operation
+     *
+     * @see #partitioningBy(Predicate)
+     */
+    public static <T, D, A>
+    Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
+                                                    Collector<? super T, A, D> downstream) {
+        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
+        BiConsumer<Partition<A>, T> accumulator = (result, t) ->
+                downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t);
+        BinaryOperator<A> op = downstream.combiner();
+        BinaryOperator<Partition<A>> merger = (left, right) ->
+                new Partition<>(op.apply(left.forTrue, right.forTrue),
+                                op.apply(left.forFalse, right.forFalse));
+        Supplier<Partition<A>> supplier = () ->
+                new Partition<>(downstream.supplier().get(),
+                                downstream.supplier().get());
+        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
+        }
+        else {
+            Function<Partition<A>, Map<Boolean, D>> finisher = par ->
+                    new Partition<>(downstream.finisher().apply(par.forTrue),
+                                    downstream.finisher().apply(par.forFalse));
+            return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
+        }
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates elements into a
+     * {@code Map} whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contains duplicates (according to
+     * {@link Object#equals(Object)}), an {@code IllegalStateException} is
+     * thrown when the collection operation is performed.  If the mapped keys
+     * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
+     * instead.
+     *
+     * @apiNote
+     * It is common for either the key or the value to be the input elements.
+     * In this case, the utility method
+     * {@link java.util.function.Function#identity()} may be helpful.
+     * For example, the following produces a {@code Map} mapping
+     * students to their grade point average:
+     * <pre>{@code
+     *     Map<Student, Double> studentToGPA
+     *         students.stream().collect(toMap(Functions.identity(),
+     *                                         student -> computeGPA(student)));
+     * }</pre>
+     * And the following produces a {@code Map} mapping a unique identifier to
+     * students:
+     * <pre>{@code
+     *     Map<String, Student> studentIdToStudent
+     *         students.stream().collect(toMap(Student::getId,
+     *                                         Functions.identity());
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If it is
+     * not required that results are inserted into the {@code Map} in encounter
+     * order, using {@link #toConcurrentMap(Function, Function)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys and values are the result of applying mapping functions to
+     * the input elements
+     *
+     * @see #toMap(Function, Function, BinaryOperator)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toConcurrentMap(Function, Function)
+     */
+    public static <T, K, U>
+    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
+                                    Function<? super T, ? extends U> valueMapper) {
+        return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates elements into a
+     * {@code Map} whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped
+     * keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.
+     *
+     * @apiNote
+     * There are multiple ways to deal with collisions between multiple elements
+     * mapping to the same key.  The other forms of {@code toMap} simply use
+     * a merge function that throws unconditionally, but you can easily write
+     * more flexible merge policies.  For example, if you have a stream
+     * of {@code Person}, and you want to produce a "phone book" mapping name to
+     * address, but it is possible that two persons have the same name, you can
+     * do as follows to gracefully deals with these collisions, and produce a
+     * {@code Map} mapping names to a concatenated list of addresses:
+     * <pre>{@code
+     *     Map<String, String> phoneBook
+     *         people.stream().collect(toMap(Person::getName,
+     *                                       Person::getAddress,
+     *                                       (s, a) -> s + ", " + a));
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If it is
+     * not required that results are merged into the {@code Map} in encounter
+     * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys are the result of applying a key mapping function to the input
+     * elements, and whose values are the result of applying a value mapping
+     * function to all input elements equal to the key and combining them
+     * using the merge function
+     *
+     * @see #toMap(Function, Function)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     */
+    public static <T, K, U>
+    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
+                                    Function<? super T, ? extends U> valueMapper,
+                                    BinaryOperator<U> mergeFunction) {
+        return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates elements into a
+     * {@code Map} whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped
+     * keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.  The {@code Map}
+     * is created by a provided supplier function.
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If it is
+     * not required that results are merged into the {@code Map} in encounter
+     * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator, Supplier)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param <M> the type of the resulting {@code Map}
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @param mapSupplier a function which returns a new, empty {@code Map} into
+     *                    which the results will be inserted
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys are the result of applying a key mapping function to the input
+     * elements, and whose values are the result of applying a value mapping
+     * function to all input elements equal to the key and combining them
+     * using the merge function
+     *
+     * @see #toMap(Function, Function)
+     * @see #toMap(Function, Function, BinaryOperator)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U, M extends Map<K, U>>
+    Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
+                                Function<? super T, ? extends U> valueMapper,
+                                BinaryOperator<U> mergeFunction,
+                                Supplier<M> mapSupplier) {
+        BiConsumer<M, T> accumulator
+                = (map, element) -> map.merge(keyMapper.apply(element),
+                                              valueMapper.apply(element), mergeFunction);
+        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} that accumulates elements into a
+     * {@code ConcurrentMap} whose keys and values are the result of applying
+     * the provided mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contains duplicates (according to
+     * {@link Object#equals(Object)}), an {@code IllegalStateException} is
+     * thrown when the collection operation is performed.  If the mapped keys
+     * may have duplicates, use
+     * {@link #toConcurrentMap(Function, Function, BinaryOperator)} instead.
+     *
+     * @apiNote
+     * It is common for either the key or the value to be the input elements.
+     * In this case, the utility method
+     * {@link java.util.function.Function#identity()} may be helpful.
+     * For example, the following produces a {@code Map} mapping
+     * students to their grade point average:
+     * <pre>{@code
+     *     Map<Student, Double> studentToGPA
+     *         students.stream().collect(toMap(Functions.identity(),
+     *                                         student -> computeGPA(student)));
+     * }</pre>
+     * And the following produces a {@code Map} mapping a unique identifier to
+     * students:
+     * <pre>{@code
+     *     Map<String, Student> studentIdToStudent
+     *         students.stream().collect(toConcurrentMap(Student::getId,
+     *                                                   Functions.identity());
+     * }</pre>
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper the mapping function to produce keys
+     * @param valueMapper the mapping function to produce values
+     * @return a concurrent, unordered {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to the input elements
+     *
+     * @see #toMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U>
+    Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                                                        Function<? super T, ? extends U> valueMapper) {
+        return toConcurrentMap(keyMapper, valueMapper, throwingMerger(), ConcurrentHashMap::new);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} that accumulates elements into a
+     * {@code ConcurrentMap} whose keys and values are the result of applying
+     * the provided mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.
+     *
+     * @apiNote
+     * There are multiple ways to deal with collisions between multiple elements
+     * mapping to the same key.  The other forms of {@code toConcurrentMap} simply use
+     * a merge function that throws unconditionally, but you can easily write
+     * more flexible merge policies.  For example, if you have a stream
+     * of {@code Person}, and you want to produce a "phone book" mapping name to
+     * address, but it is possible that two persons have the same name, you can
+     * do as follows to gracefully deals with these collisions, and produce a
+     * {@code Map} mapping names to a concatenated list of addresses:
+     * <pre>{@code
+     *     Map<String, String> phoneBook
+     *         people.stream().collect(toConcurrentMap(Person::getName,
+     *                                                 Person::getAddress,
+     *                                                 (s, a) -> s + ", " + a));
+     * }</pre>
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @return a concurrent, unordered {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to all input elements equal to the key
+     * and combining them using the merge function
+     *
+     * @see #toConcurrentMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toMap(Function, Function, BinaryOperator)
+     */
+    public static <T, K, U>
+    Collector<T, ?, ConcurrentMap<K,U>>
+    toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                    Function<? super T, ? extends U> valueMapper,
+                    BinaryOperator<U> mergeFunction) {
+        return toConcurrentMap(keyMapper, valueMapper, mergeFunction, ConcurrentHashMap::new);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} that accumulates elements into a
+     * {@code ConcurrentMap} whose keys and values are the result of applying
+     * the provided mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.  The
+     * {@code ConcurrentMap} is created by a provided supplier function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param <M> the type of the resulting {@code ConcurrentMap}
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @param mapSupplier a function which returns a new, empty {@code Map} into
+     *                    which the results will be inserted
+     * @return a concurrent, unordered {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to all input elements equal to the key
+     * and combining them using the merge function
+     *
+     * @see #toConcurrentMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U, M extends ConcurrentMap<K, U>>
+    Collector<T, ?, M> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                                       Function<? super T, ? extends U> valueMapper,
+                                       BinaryOperator<U> mergeFunction,
+                                       Supplier<M> mapSupplier) {
+        BiConsumer<M, T> accumulator
+                = (map, element) -> map.merge(keyMapper.apply(element),
+                                              valueMapper.apply(element), mergeFunction);
+        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_CONCURRENT_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code int}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #summarizingDouble(ToDoubleFunction)
+     * @see #summarizingLong(ToLongFunction)
+     */
+    public static <T>
+    Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) {
+        return new CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>(
+                IntSummaryStatistics::new,
+                (r, t) -> r.accept(mapper.applyAsInt(t)),
+                (l, r) -> { l.combine(r); return l; }, CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code long}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper the mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #summarizingDouble(ToDoubleFunction)
+     * @see #summarizingInt(ToIntFunction)
+     */
+    public static <T>
+    Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) {
+        return new CollectorImpl<T, LongSummaryStatistics, LongSummaryStatistics>(
+                LongSummaryStatistics::new,
+                (r, t) -> r.accept(mapper.applyAsLong(t)),
+                (l, r) -> { l.combine(r); return l; }, CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code double}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #summarizingLong(ToLongFunction)
+     * @see #summarizingInt(ToIntFunction)
+     */
+    public static <T>
+    Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) {
+        return new CollectorImpl<T, DoubleSummaryStatistics, DoubleSummaryStatistics>(
+                DoubleSummaryStatistics::new,
+                (r, t) -> r.accept(mapper.applyAsDouble(t)),
+                (l, r) -> { l.combine(r); return l; }, CH_ID);
+    }
+
+    /**
+     * Implementation class used by partitioningBy.
+     */
+    private static final class Partition<T>
+            extends AbstractMap<Boolean, T>
+            implements Map<Boolean, T> {
+        final T forTrue;
+        final T forFalse;
+
+        Partition(T forTrue, T forFalse) {
+            this.forTrue = forTrue;
+            this.forFalse = forFalse;
+        }
+
+        @Override
+        public Set<Map.Entry<Boolean, T>> entrySet() {
+            return new AbstractSet<Map.Entry<Boolean, T>>() {
+                @Override
+                public Iterator<Map.Entry<Boolean, T>> iterator() {
+                    Map.Entry<Boolean, T> falseEntry = new SimpleImmutableEntry<>(false, forFalse);
+                    Map.Entry<Boolean, T> trueEntry = new SimpleImmutableEntry<>(true, forTrue);
+                    return Arrays.asList(falseEntry, trueEntry).iterator();
+                }
+
+                @Override
+                public int size() {
+                    return 2;
+                }
+            };
+        }
+    }
+}
diff --git a/java/util/stream/DistinctOps.java b/java/util/stream/DistinctOps.java
new file mode 100644
index 0000000..22fbe05
--- /dev/null
+++ b/java/util/stream/DistinctOps.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.IntFunction;
+
+/**
+ * Factory methods for transforming streams into duplicate-free streams, using
+ * {@link Object#equals(Object)} to determine equality.
+ *
+ * @since 1.8
+ */
+final class DistinctOps {
+
+    private DistinctOps() { }
+
+    /**
+     * Appends a "distinct" operation to the provided stream, and returns the
+     * new stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     * @return the new stream
+     */
+    static <T> ReferencePipeline<T, T> makeRef(AbstractPipeline<?, T, ?> upstream) {
+        return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
+                                                      StreamOpFlag.IS_DISTINCT | StreamOpFlag.NOT_SIZED) {
+
+            <P_IN> Node<T> reduce(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
+                // If the stream is SORTED then it should also be ORDERED so the following will also
+                // preserve the sort order
+                TerminalOp<T, LinkedHashSet<T>> reduceOp
+                        = ReduceOps.<T, LinkedHashSet<T>>makeRef(LinkedHashSet::new, LinkedHashSet::add,
+                                                                 LinkedHashSet::addAll);
+                return Nodes.node(reduceOp.evaluateParallel(helper, spliterator));
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                              Spliterator<P_IN> spliterator,
+                                              IntFunction<T[]> generator) {
+                if (StreamOpFlag.DISTINCT.isKnown(helper.getStreamAndOpFlags())) {
+                    // No-op
+                    return helper.evaluate(spliterator, false, generator);
+                }
+                else if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return reduce(helper, spliterator);
+                }
+                else {
+                    // Holder of null state since ConcurrentHashMap does not support null values
+                    AtomicBoolean seenNull = new AtomicBoolean(false);
+                    ConcurrentHashMap<T, Boolean> map = new ConcurrentHashMap<>();
+                    TerminalOp<T, Void> forEachOp = ForEachOps.makeRef(t -> {
+                        if (t == null)
+                            seenNull.set(true);
+                        else
+                            map.putIfAbsent(t, Boolean.TRUE);
+                    }, false);
+                    forEachOp.evaluateParallel(helper, spliterator);
+
+                    // If null has been seen then copy the key set into a HashSet that supports null values
+                    // and add null
+                    Set<T> keys = map.keySet();
+                    if (seenNull.get()) {
+                        // TODO Implement a more efficient set-union view, rather than copying
+                        keys = new HashSet<>(keys);
+                        keys.add(null);
+                    }
+                    return Nodes.node(keys);
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
+                if (StreamOpFlag.DISTINCT.isKnown(helper.getStreamAndOpFlags())) {
+                    // No-op
+                    return helper.wrapSpliterator(spliterator);
+                }
+                else if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    // Not lazy, barrier required to preserve order
+                    return reduce(helper, spliterator).spliterator();
+                }
+                else {
+                    // Lazy
+                    return new StreamSpliterators.DistinctSpliterator<>(helper.wrapSpliterator(spliterator));
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<T> opWrapSink(int flags, Sink<T> sink) {
+                Objects.requireNonNull(sink);
+
+                if (StreamOpFlag.DISTINCT.isKnown(flags)) {
+                    return sink;
+                } else if (StreamOpFlag.SORTED.isKnown(flags)) {
+                    return new Sink.ChainedReference<T, T>(sink) {
+                        boolean seenNull;
+                        T lastSeen;
+
+                        @Override
+                        public void begin(long size) {
+                            seenNull = false;
+                            lastSeen = null;
+                            downstream.begin(-1);
+                        }
+
+                        @Override
+                        public void end() {
+                            seenNull = false;
+                            lastSeen = null;
+                            downstream.end();
+                        }
+
+                        @Override
+                        public void accept(T t) {
+                            if (t == null) {
+                                if (!seenNull) {
+                                    seenNull = true;
+                                    downstream.accept(lastSeen = null);
+                                }
+                            } else if (lastSeen == null || !t.equals(lastSeen)) {
+                                downstream.accept(lastSeen = t);
+                            }
+                        }
+                    };
+                } else {
+                    return new Sink.ChainedReference<T, T>(sink) {
+                        Set<T> seen;
+
+                        @Override
+                        public void begin(long size) {
+                            seen = new HashSet<>();
+                            downstream.begin(-1);
+                        }
+
+                        @Override
+                        public void end() {
+                            seen = null;
+                            downstream.end();
+                        }
+
+                        @Override
+                        public void accept(T t) {
+                            if (!seen.contains(t)) {
+                                seen.add(t);
+                                downstream.accept(t);
+                            }
+                        }
+                    };
+                }
+            }
+        };
+    }
+}
diff --git a/java/util/stream/DoubleNodeTest.java b/java/util/stream/DoubleNodeTest.java
new file mode 100644
index 0000000..c1e8a30
--- /dev/null
+++ b/java/util/stream/DoubleNodeTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class DoubleNodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            double[] array = new double[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Double>> nodes = new ArrayList<>();
+
+            nodes.add(Nodes.node(array));
+            nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
+            nodes.add(tree(toList(array), l -> Nodes.node(toDoubleArray(l))));
+            nodes.add(fill(array, Nodes.doubleBuilder(array.length)));
+            nodes.add(fill(array, Nodes.doubleBuilder()));
+
+            for (Node<Double> node : nodes) {
+                params.add(new Object[]{array, node});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    private static void assertEqualsListDoubleArray(List<Double> list, double[] array) {
+        assertEquals(list.size(), array.length);
+        for (int i = 0; i < array.length; i++)
+            assertEquals(array[i], list.get(i));
+    }
+
+    private List<Double> toList(double[] a) {
+        List<Double> l = new ArrayList<>();
+        for (double i : a) {
+            l.add(i);
+        }
+
+        return l;
+    }
+
+    private double[] toDoubleArray(List<Double> l) {
+        double[] a = new double[l.size()];
+
+        int i = 0;
+        for (Double e : l) {
+            a[i++] = e;
+        }
+        return a;
+    }
+
+    private Node.OfDouble fill(double[] array, Node.Builder.OfDouble nb) {
+        nb.begin(array.length);
+        for (double i : array)
+            nb.accept(i);
+        nb.end();
+        return nb.build();
+    }
+
+    private Node.OfDouble degenerateTree(PrimitiveIterator.OfDouble it) {
+        if (!it.hasNext()) {
+            return Nodes.node(new double[0]);
+        }
+
+        double i = it.nextDouble();
+        if (it.hasNext()) {
+            return new Nodes.ConcNode.OfDouble(Nodes.node(new double[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new double[] {i});
+        }
+    }
+
+    private Node.OfDouble tree(List<Double> l, Function<List<Double>, Node.OfDouble> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.ConcNode.OfDouble(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(double[] array, Node.OfDouble n) {
+        assertEquals(n.asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(double[] array, Node.OfDouble n) {
+        assertEquals(Nodes.flattenDouble(n).asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(double[] array, Node.OfDouble n) {
+        double[] copy = new double[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(double[] array, Node.OfDouble n) {
+        List<Double> l = new ArrayList<>((int) n.count());
+        n.forEach((double e) -> {
+            l.add(e);
+        });
+
+        assertEqualsListDoubleArray(l, array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(double[] array, Node.OfDouble n) {
+        TestData.OfDouble data = TestData.Factory.ofNode("Node", n);
+
+        exerciseOps(data, s -> s);
+
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes", groups={ "serialization-hostile" })
+    // throws SOE on serialization of DoubleConcNode[size=1000]
+    public void testSpliterator(double[] array, Node.OfDouble n) {
+        SpliteratorTestHelper.testDoubleSpliterator(n::spliterator);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testTruncate(double[] array, Node.OfDouble n) {
+        int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+        for (int start : nums)
+            for (int end : nums) {
+                if (start < 0 || end < 0 || end < start || end > array.length)
+                    continue;
+                Node.OfDouble slice = n.truncate(start, end, Double[]::new);
+                double[] asArray = slice.asPrimitiveArray();
+                for (int k = start; k < end; k++)
+                    assertEquals(array[k], asArray[k - start]);
+            }
+    }
+}
diff --git a/java/util/stream/DoublePipeline.java b/java/util/stream/DoublePipeline.java
new file mode 100644
index 0000000..e61e5de
--- /dev/null
+++ b/java/util/stream/DoublePipeline.java
@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.DoubleSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleFunction;
+import java.util.function.DoublePredicate;
+import java.util.function.DoubleToIntFunction;
+import java.util.function.DoubleToLongFunction;
+import java.util.function.DoubleUnaryOperator;
+import java.util.function.IntFunction;
+import java.util.function.ObjDoubleConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code double}.
+ *
+ * @param <E_IN> type of elements in the upstream source
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class DoublePipeline<E_IN>
+        extends AbstractPipeline<E_IN, Double, DoubleStream>
+        implements DoubleStream {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     */
+    DoublePipeline(Supplier<? extends Spliterator<Double>> source,
+                   int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     */
+    DoublePipeline(Spliterator<Double> source,
+                   int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing
+     * pipeline.
+     *
+     * @param upstream the upstream element source.
+     * @param opFlags the operation flags
+     */
+    DoublePipeline(AbstractPipeline<?, E_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    /**
+     * Adapt a {@code Sink<Double> to a {@code DoubleConsumer}, ideally simply
+     * by casting.
+     */
+    private static DoubleConsumer adapt(Sink<Double> sink) {
+        if (sink instanceof DoubleConsumer) {
+            return (DoubleConsumer) sink;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using DoubleStream.adapt(Sink<Double> s)");
+            return sink::accept;
+        }
+    }
+
+    /**
+     * Adapt a {@code Spliterator<Double>} to a {@code Spliterator.OfDouble}.
+     *
+     * @implNote
+     * The implementation attempts to cast to a Spliterator.OfDouble, and throws
+     * an exception if this cast is not possible.
+     */
+    private static Spliterator.OfDouble adapt(Spliterator<Double> s) {
+        if (s instanceof Spliterator.OfDouble) {
+            return (Spliterator.OfDouble) s;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using DoubleStream.adapt(Spliterator<Double> s)");
+            throw new UnsupportedOperationException("DoubleStream.adapt(Spliterator<Double> s)");
+        }
+    }
+
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.DOUBLE_VALUE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<Double> evaluateToNode(PipelineHelper<Double> helper,
+                                             Spliterator<P_IN> spliterator,
+                                             boolean flattenTree,
+                                             IntFunction<Double[]> generator) {
+        return Nodes.collectDouble(helper, spliterator, flattenTree);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<Double> wrap(PipelineHelper<Double> ph,
+                                          Supplier<Spliterator<P_IN>> supplier,
+                                          boolean isParallel) {
+        return new StreamSpliterators.DoubleWrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator.OfDouble lazySpliterator(Supplier<? extends Spliterator<Double>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator.OfDouble((Supplier<Spliterator.OfDouble>) supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final void forEachWithCancel(Spliterator<Double> spliterator, Sink<Double> sink) {
+        Spliterator.OfDouble spl = adapt(spliterator);
+        DoubleConsumer adaptedSink = adapt(sink);
+        do { } while (!sink.cancellationRequested() && spl.tryAdvance(adaptedSink));
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<Double> makeNodeBuilder(long exactSizeIfKnown, IntFunction<Double[]> generator) {
+        return Nodes.doubleBuilder(exactSizeIfKnown);
+    }
+
+
+    // DoubleStream
+
+    @Override
+    public final PrimitiveIterator.OfDouble iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public final Spliterator.OfDouble spliterator() {
+        return adapt(super.spliterator());
+    }
+
+    // Stateless intermediate ops from DoubleStream
+
+    @Override
+    public final Stream<Double> boxed() {
+        return mapToObj(Double::valueOf);
+    }
+
+    @Override
+    public final DoubleStream map(DoubleUnaryOperator mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                       StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.applyAsDouble(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        return new ReferencePipeline.StatelessOp<Double, U>(this, StreamShape.DOUBLE_VALUE,
+                                                            StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedDouble<U>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream mapToInt(DoubleToIntFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new IntPipeline.StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                                   StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedDouble<Integer>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.applyAsInt(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream mapToLong(DoubleToLongFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new LongPipeline.StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                                    StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedDouble<Long>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.applyAsLong(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper) {
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(double t) {
+                        try (DoubleStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public DoubleStream unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream filter(DoublePredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                       StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(double t) {
+                        if (predicate.test(t))
+                            downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream peek(DoubleConsumer action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                       0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        action.accept(t);
+                        downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate ops from DoubleStream
+
+    @Override
+    public final DoubleStream limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeDouble(this, (long) 0, maxSize);
+    }
+
+    @Override
+    public final DoubleStream skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else {
+            long limit = -1;
+            return SliceOps.makeDouble(this, n, limit);
+        }
+    }
+
+    @Override
+    public final DoubleStream sorted() {
+        return SortedOps.makeDouble(this);
+    }
+
+    @Override
+    public final DoubleStream distinct() {
+        // While functional and quick to implement, this approach is not very efficient.
+        // An efficient version requires a double-specific map/set implementation.
+        return boxed().distinct().mapToDouble(i -> (double) i);
+    }
+
+    // Terminal ops from DoubleStream
+
+    @Override
+    public void forEach(DoubleConsumer consumer) {
+        evaluate(ForEachOps.makeDouble(consumer, false));
+    }
+
+    @Override
+    public void forEachOrdered(DoubleConsumer consumer) {
+        evaluate(ForEachOps.makeDouble(consumer, true));
+    }
+
+    @Override
+    public final double sum() {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the low-order bits of the sum computed via compensated
+         * summation, and index 2 holds the simple sum used to compute
+         * the proper result if the stream contains infinite values of
+         * the same sign.
+         */
+        double[] summation = collect(() -> new double[3],
+                               (ll, d) -> {
+                                   Collectors.sumWithCompensation(ll, d);
+                                   ll[2] += d;
+                               },
+                               (ll, rr) -> {
+                                   Collectors.sumWithCompensation(ll, rr[0]);
+                                   Collectors.sumWithCompensation(ll, rr[1]);
+                                   ll[2] += rr[2];
+                               });
+
+        return Collectors.computeFinalSum(summation);
+    }
+
+    @Override
+    public final OptionalDouble min() {
+        return reduce(Math::min);
+    }
+
+    @Override
+    public final OptionalDouble max() {
+        return reduce(Math::max);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote The {@code double} format can represent all
+     * consecutive integers in the range -2<sup>53</sup> to
+     * 2<sup>53</sup>. If the pipeline has more than 2<sup>53</sup>
+     * values, the divisor in the average computation will saturate at
+     * 2<sup>53</sup>, leading to additional numerical errors.
+     */
+    @Override
+    public final OptionalDouble average() {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the low-order bits of the sum computed via compensated
+         * summation, index 2 holds the number of values seen, index 3
+         * holds the simple sum.
+         */
+        double[] avg = collect(() -> new double[4],
+                               (ll, d) -> {
+                                   ll[2]++;
+                                   Collectors.sumWithCompensation(ll, d);
+                                   ll[3] += d;
+                               },
+                               (ll, rr) -> {
+                                   Collectors.sumWithCompensation(ll, rr[0]);
+                                   Collectors.sumWithCompensation(ll, rr[1]);
+                                   ll[2] += rr[2];
+                                   ll[3] += rr[3];
+                               });
+        return avg[2] > 0
+            ? OptionalDouble.of(Collectors.computeFinalSum(avg) / avg[2])
+            : OptionalDouble.empty();
+    }
+
+    @Override
+    public final long count() {
+        return mapToLong(e -> 1L).sum();
+    }
+
+    @Override
+    public final DoubleSummaryStatistics summaryStatistics() {
+        return collect(DoubleSummaryStatistics::new, DoubleSummaryStatistics::accept,
+                       DoubleSummaryStatistics::combine);
+    }
+
+    @Override
+    public final double reduce(double identity, DoubleBinaryOperator op) {
+        return evaluate(ReduceOps.makeDouble(identity, op));
+    }
+
+    @Override
+    public final OptionalDouble reduce(DoubleBinaryOperator op) {
+        return evaluate(ReduceOps.makeDouble(op));
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               ObjDoubleConsumer<R> accumulator,
+                               BiConsumer<R, R> combiner) {
+        BinaryOperator<R> operator = (left, right) -> {
+            combiner.accept(left, right);
+            return left;
+        };
+        return evaluate(ReduceOps.makeDouble(supplier, accumulator, operator));
+    }
+
+    @Override
+    public final boolean anyMatch(DoublePredicate predicate) {
+        return evaluate(MatchOps.makeDouble(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(DoublePredicate predicate) {
+        return evaluate(MatchOps.makeDouble(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(DoublePredicate predicate) {
+        return evaluate(MatchOps.makeDouble(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final OptionalDouble findFirst() {
+        return evaluate(FindOps.makeDouble(true));
+    }
+
+    @Override
+    public final OptionalDouble findAny() {
+        return evaluate(FindOps.makeDouble(false));
+    }
+
+    @Override
+    public final double[] toArray() {
+        return Nodes.flattenDouble((Node.OfDouble) evaluateToArrayNode(Double[]::new))
+                        .asPrimitiveArray();
+    }
+
+    //
+
+    /**
+     * Source stage of a DoubleStream
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @hide Made public for CTS tests only (OpenJDK 8 streams tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN> extends DoublePipeline<E_IN> {
+        /**
+         * Constructor for the source stage of a DoubleStream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<Double>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of a DoubleStream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<Double> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Made public for CTS tests only.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Made public for CTS tests only.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<Double> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(DoubleConsumer consumer) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(consumer);
+            }
+            else {
+                super.forEach(consumer);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(DoubleConsumer consumer) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(consumer);
+            }
+            else {
+                super.forEachOrdered(consumer);
+            }
+        }
+
+    }
+
+    /**
+     * Base class for a stateless intermediate stage of a DoubleStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN> extends DoublePipeline<E_IN> {
+        /**
+         * Construct a new DoubleStream by appending a stateless intermediate
+         * operation to an existing stream.
+         *
+         * @param upstream the upstream pipeline stage
+         * @param inputShape the stream shape for the upstream pipeline stage
+         * @param opFlags operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of a DoubleStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN> extends DoublePipeline<E_IN> {
+        /**
+         * Construct a new DoubleStream by appending a stateful intermediate
+         * operation to an existing stream.
+         *
+         * @param upstream the upstream pipeline stage
+         * @param inputShape the stream shape for the upstream pipeline stage
+         * @param opFlags operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                        Spliterator<P_IN> spliterator,
+                                                        IntFunction<Double[]> generator);
+    }
+}
diff --git a/java/util/stream/DoubleStream.java b/java/util/stream/DoubleStream.java
new file mode 100644
index 0000000..4d5d23d
--- /dev/null
+++ b/java/util/stream/DoubleStream.java
@@ -0,0 +1,894 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.DoubleSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleFunction;
+import java.util.function.DoublePredicate;
+import java.util.function.DoubleSupplier;
+import java.util.function.DoubleToIntFunction;
+import java.util.function.DoubleToLongFunction;
+import java.util.function.DoubleUnaryOperator;
+import java.util.function.Function;
+import java.util.function.ObjDoubleConsumer;
+import java.util.function.Supplier;
+
+/**
+ * A sequence of primitive double-valued elements supporting sequential and parallel
+ * aggregate operations.  This is the {@code double} primitive specialization of
+ * {@link Stream}.
+ *
+ * <p>The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link DoubleStream}, computing the sum of the weights of the
+ * red widgets:
+ *
+ * <pre>{@code
+ *     double sum = widgets.stream()
+ *                         .filter(w -> w.getColor() == RED)
+ *                         .mapToDouble(w -> w.getWeight())
+ *                         .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism.
+ *
+ * @since 1.8
+ * @see Stream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface DoubleStream extends BaseStream<Double, DoubleStream> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    DoubleStream filter(DoublePredicate predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream map(DoubleUnaryOperator mapper);
+
+    /**
+     * Returns an object-valued {@code Stream} consisting of the results of
+     * applying the given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param <U> the element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream mapToInt(DoubleToIntFunction mapper);
+
+    /**
+     * Returns a {@code LongStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream mapToLong(DoubleToLongFunction mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a
+     *               {@code DoubleStream} of new values
+     * @return the new stream
+     * @see Stream#flatMap(Function)
+     */
+    DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper);
+
+    /**
+     * Returns a stream consisting of the distinct elements of this stream. The
+     * elements are compared for equality according to
+     * {@link java.lang.Double#compare(double, double)}.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the result stream
+     */
+    DoubleStream distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream in sorted
+     * order. The elements are compared for equality according to
+     * {@link java.lang.Double#compare(double, double)}.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the result stream
+     */
+    DoubleStream sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     DoubleStream.of(1, 2, 3, 4)
+     *         .filter(e -> e > 2)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(e -> e * e)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .sum();
+     * }</pre>
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements as
+     *               they are consumed from the stream
+     * @return the new stream
+     */
+    DoubleStream peek(DoubleConsumer action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(DoubleSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    DoubleStream limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(DoubleSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    DoubleStream skip(long n);
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(DoubleConsumer action);
+
+    /**
+     * Performs an action for each element of this stream, guaranteeing that
+     * each element is processed in encounter order for streams that have a
+     * defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(DoubleConsumer)
+     */
+    void forEachOrdered(DoubleConsumer action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array containing the elements of this stream
+     */
+    double[] toArray();
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     double result = identity;
+     *     for (double element : this stream)
+     *         result = accumulator.applyAsDouble(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code x},
+     * {@code accumulator.apply(identity, x)} is equal to {@code x}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min, max, and average are all special cases of reduction.
+     * Summing a stream of numbers can be expressed as:
+
+     * <pre>{@code
+     *     double sum = numbers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or more compactly:
+     *
+     * <pre>{@code
+     *     double sum = numbers.reduce(0, Double::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #sum()
+     * @see #min()
+     * @see #max()
+     * @see #average()
+     */
+    double reduce(double identity, DoubleBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code OptionalDouble} describing the reduced
+     * value, if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     double result = null;
+     *     for (double element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.applyAsDouble(result, element);
+     *     }
+     *     return foundAny ? OptionalDouble.of(result) : OptionalDouble.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #reduce(double, DoubleBinaryOperator)
+     */
+    OptionalDouble reduce(DoubleBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (double element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(double, DoubleBinaryOperator)}, {@code collect}
+     * operations can be parallelized without requiring additional
+     * synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param <R> type of the result
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for incorporating an additional element into a result
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values, which must be
+     *                    compatible with the accumulator function
+     * @return the result of the reduction
+     * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
+     */
+    <R> R collect(Supplier<R> supplier,
+                  ObjDoubleConsumer<R> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Returns the sum of elements in this stream.
+     *
+     * Summation is a special case of a <a
+     * href="package-summary.html#Reduction">reduction</a>. If
+     * floating-point summation were exact, this method would be
+     * equivalent to:
+     *
+     * <pre>{@code
+     *     return reduce(0, Double::sum);
+     * }</pre>
+     *
+     * However, since floating-point summation is not exact, the above
+     * code is not necessarily equivalent to the summation computation
+     * done by this method.
+     *
+     * <p>If any stream element is a NaN or the sum is at any point a NaN
+     * then the sum will be NaN.
+     *
+     * The value of a floating-point sum is a function both
+     * of the input values as well as the order of addition
+     * operations. The order of addition operations of this method is
+     * intentionally not defined to allow for implementation
+     * flexibility to improve the speed and accuracy of the computed
+     * result.
+     *
+     * In particular, this method may be implemented using compensated
+     * summation or other technique to reduce the error bound in the
+     * numerical sum compared to a simple summation of {@code double}
+     * values.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Elements sorted by increasing absolute magnitude tend
+     * to yield more accurate results.
+     *
+     * @return the sum of elements in this stream
+     */
+    double sum();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the minimum element of this
+     * stream, or an empty OptionalDouble if this stream is empty.  The minimum
+     * element will be {@code Double.NaN} if any stream element was NaN. Unlike
+     * the numerical comparison operators, this method considers negative zero
+     * to be strictly smaller than positive zero. This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return reduce(Double::min);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the minimum element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble min();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the maximum element of this
+     * stream, or an empty OptionalDouble if this stream is empty.  The maximum
+     * element will be {@code Double.NaN} if any stream element was NaN. Unlike
+     * the numerical comparison operators, this method considers negative zero
+     * to be strictly smaller than positive zero. This is a
+     * special case of a
+     * <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return reduce(Double::max);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the maximum element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble max();
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return mapToLong(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the arithmetic
+     * mean of elements of this stream, or an empty optional if this
+     * stream is empty.
+     *
+     * If any recorded value is a NaN or the sum is at any point a NaN
+     * then the average will be NaN.
+     *
+     * <p>The average returned can vary depending upon the order in
+     * which values are recorded.
+     *
+     * This method may be implemented using compensated summation or
+     * other technique to reduce the error bound in the {@link #sum
+     * numerical sum} used to compute the average.
+     *
+     *  <p>The average is a special case of a <a
+     *  href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Elements sorted by increasing absolute magnitude tend
+     * to yield more accurate results.
+     *
+     * @return an {@code OptionalDouble} containing the average element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble average();
+
+    /**
+     * Returns a {@code DoubleSummaryStatistics} describing various summary data
+     * about the elements of this stream.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return a {@code DoubleSummaryStatistics} describing various summary data
+     * about the elements of this stream
+     */
+    DoubleSummaryStatistics summaryStatistics();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(DoublePredicate predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(DoublePredicate predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(DoublePredicate predicate);
+
+    /**
+     * Returns an {@link OptionalDouble} describing the first element of this
+     * stream, or an empty {@code OptionalDouble} if the stream is empty.  If
+     * the stream has no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code OptionalDouble} describing the first element of this
+     * stream, or an empty {@code OptionalDouble} if the stream is empty
+     */
+    OptionalDouble findFirst();
+
+    /**
+     * Returns an {@link OptionalDouble} describing some element of the stream,
+     * or an empty {@code OptionalDouble} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code OptionalDouble} describing some element of this stream,
+     * or an empty {@code OptionalDouble} if the stream is empty
+     * @see #findFirst()
+     */
+    OptionalDouble findAny();
+
+    /**
+     * Returns a {@code Stream} consisting of the elements of this stream,
+     * boxed to {@code Double}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code Stream} consistent of the elements of this stream,
+     * each boxed to a {@code Double}
+     */
+    Stream<Double> boxed();
+
+    @Override
+    DoubleStream sequential();
+
+    @Override
+    DoubleStream parallel();
+
+    @Override
+    PrimitiveIterator.OfDouble iterator();
+
+    @Override
+    Spliterator.OfDouble spliterator();
+
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code DoubleStream}.
+     *
+     * @return a stream builder
+     */
+    public static Builder builder() {
+        return new Streams.DoubleStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code DoubleStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static DoubleStream empty() {
+        return StreamSupport.doubleStream(Spliterators.emptyDoubleSpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code DoubleStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static DoubleStream of(double t) {
+        return StreamSupport.doubleStream(new Streams.DoubleStreamBuilderImpl(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static DoubleStream of(double... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code DoubleStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code DoubleStream}
+     * will be the provided {@code seed}.  For {@code n > 0}, the element at
+     * position {@code n}, will be the result of applying the function {@code f}
+     *  to the element at position {@code n - 1}.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code DoubleStream}
+     */
+    public static DoubleStream iterate(final double seed, final DoubleUnaryOperator f) {
+        Objects.requireNonNull(f);
+        final PrimitiveIterator.OfDouble iterator = new PrimitiveIterator.OfDouble() {
+            double t = seed;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public double nextDouble() {
+                double v = t;
+                t = f.applyAsDouble(t);
+                return v;
+            }
+        };
+        return StreamSupport.doubleStream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code DoubleSupplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param s the {@code DoubleSupplier} for generated elements
+     * @return a new infinite sequential unordered {@code DoubleStream}
+     */
+    public static DoubleStream generate(DoubleSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.doubleStream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfDouble(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowException}.
+     *
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static DoubleStream concat(DoubleStream a, DoubleStream b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        Spliterator.OfDouble split = new Streams.ConcatSpliterator.OfDouble(
+                a.spliterator(), b.spliterator());
+        DoubleStream stream = StreamSupport.doubleStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for a {@code DoubleStream}.
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase
+     * begins when the {@link #build()} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
+     * @see DoubleStream#builder()
+     * @since 1.8
+     */
+    public interface Builder extends DoubleConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(double t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default Builder add(double t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        DoubleStream build();
+    }
+}
diff --git a/java/util/stream/DoubleStreamTestDataProvider.java b/java/util/stream/DoubleStreamTestDataProvider.java
new file mode 100644
index 0000000..0eb7c87
--- /dev/null
+++ b/java/util/stream/DoubleStreamTestDataProvider.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for double-valued streams */
+public class DoubleStreamTestDataProvider {
+    private static final double[] to0 = new double[0];
+    private static final double[] to1 = new double[1];
+    private static final double[] to10 = new double[10];
+    private static final double[] to100 = new double[100];
+    private static final double[] to1000 = new double[1000];
+    private static final double[] reversed = new double[100];
+    private static final double[] ones = new double[100];
+    private static final double[] twice = new double[200];
+    private static final double[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        double[][] arrays = {to0, to1, to10, to100, to1000};
+        for (double[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new double[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (double) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final double[] doubles = (double[]) data[1];
+
+                list.add(new Object[]{"array:" + name,
+                        TestData.Factory.ofArray("array:" + name, doubles)});
+
+                SpinedBuffer.OfDouble isl = new SpinedBuffer.OfDouble();
+                for (double i : doubles) {
+                    isl.accept(i);
+                }
+                list.add(new Object[]{"SpinedList:" + name,
+                        TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final double[] doubles = (double[]) data[1];
+
+                SpinedBuffer.OfDouble isl = new SpinedBuffer.OfDouble();
+                for (double i : doubles) {
+                    isl.accept(i);
+                }
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(doubles)));
+                spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(doubles, 0, doubles.length / 2)));
+
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> isl.spliterator()));
+
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(isl.iterator(), doubles.length, 0)));
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+                // Need more!
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfDouble> s) {
+        return new Object[] { description, s };
+    }
+
+    // Return an array of ( String name, DoubleStreamTestData )
+    @DataProvider(name = "DoubleStreamTestData")
+    public static Object[][] makeDoubleStreamTestData() {
+        return testData;
+    }
+
+    // returns an array of (String name, Supplier<PrimitiveSpliterator<Double>>)
+    @DataProvider(name = "DoubleSpliterator")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
diff --git a/java/util/stream/DoubleStreamTestScenario.java b/java/util/stream/DoubleStreamTestScenario.java
new file mode 100644
index 0000000..1811a4b
--- /dev/null
+++ b/java/util/stream/DoubleStreamTestScenario.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.PrimitiveIterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+
+/**
+ * Test scenarios for double streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum DoubleStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            DoubleStream s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+            s.close();
+        }
+    },
+
+    STREAM_TO_ARRAY(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (double t : m.apply(data.stream()).toArray()) {
+                b.accept(t);
+            }
+        }
+    },
+
+    STREAM_ITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (PrimitiveIterator.OfDouble seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.nextDouble());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (Spliterator.OfDouble spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (Spliterator.OfDouble spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (double t : m.apply(data.parallelStream()).toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            DoubleStream s = m.apply(data.parallelStream());
+            Spliterator.OfDouble sp = s.spliterator();
+            DoubleStream ss = StreamSupport.doubleStream(() -> sp,
+                                                         StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                         | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
+            for (double t : ss.toArray())
+                b.accept(t);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            DoubleStream pipe2 = m.apply(pipe1);
+
+            for (double t : pipe2.toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing
+    PAR_STREAM_FOR_EACH(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            m.apply(data.parallelStream()).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+    PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            m.apply(pipe1).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+    ;
+
+    // The set of scenarios that clean the SIZED flag
+    public static final Set<DoubleStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+            EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+    private boolean isParallel;
+
+    private final boolean isOrdered;
+
+    DoubleStreamTestScenario(boolean isParallel) {
+        this(isParallel, true);
+    }
+
+    DoubleStreamTestScenario(boolean isParallel, boolean isOrdered) {
+        this.isParallel = isParallel;
+        this.isOrdered = isOrdered;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.DOUBLE_VALUE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public boolean isOrdered() {
+        return isOrdered;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, (DoubleConsumer) b, (Function<S_IN, DoubleStream>) m);
+    }
+
+    abstract <T, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m);
+
+}
diff --git a/java/util/stream/FindOps.java b/java/util/stream/FindOps.java
new file mode 100644
index 0000000..197d99c
--- /dev/null
+++ b/java/util/stream/FindOps.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * Factory for instances of a short-circuiting {@code TerminalOp} that searches
+ * for an element in a stream pipeline, and terminates when it finds one.
+ * Supported variants include find-first (find the first element in the
+ * encounter order) and find-any (find any element, may not be the first in
+ * encounter order.)
+ *
+ * @since 1.8
+ */
+final class FindOps {
+
+    private FindOps() { }
+
+    /**
+     * Constructs a {@code TerminalOp} for streams of objects.
+     *
+     * @param <T> the type of elements of the stream
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    public static <T> TerminalOp<T, Optional<T>> makeRef(boolean mustFindFirst) {
+        return new FindOp<>(mustFindFirst, StreamShape.REFERENCE, Optional.empty(),
+                            Optional::isPresent, FindSink.OfRef::new);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} for streams of ints.
+     *
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    public static TerminalOp<Integer, OptionalInt> makeInt(boolean mustFindFirst) {
+        return new FindOp<>(mustFindFirst, StreamShape.INT_VALUE, OptionalInt.empty(),
+                            OptionalInt::isPresent, FindSink.OfInt::new);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} for streams of longs.
+     *
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    public static TerminalOp<Long, OptionalLong> makeLong(boolean mustFindFirst) {
+        return new FindOp<>(mustFindFirst, StreamShape.LONG_VALUE, OptionalLong.empty(),
+                            OptionalLong::isPresent, FindSink.OfLong::new);
+    }
+
+    /**
+     * Constructs a {@code FindOp} for streams of doubles.
+     *
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    public static TerminalOp<Double, OptionalDouble> makeDouble(boolean mustFindFirst) {
+        return new FindOp<>(mustFindFirst, StreamShape.DOUBLE_VALUE, OptionalDouble.empty(),
+                            OptionalDouble::isPresent, FindSink.OfDouble::new);
+    }
+
+    /**
+     * A short-circuiting {@code TerminalOp} that searches for an element in a
+     * stream pipeline, and terminates when it finds one.  Implements both
+     * find-first (find the first element in the encounter order) and find-any
+     * (find any element, may not be the first in encounter order.)
+     *
+     * @param <T> the output type of the stream pipeline
+     * @param <O> the result type of the find operation, typically an optional
+     *        type
+     */
+    private static final class FindOp<T, O> implements TerminalOp<T, O> {
+        private final StreamShape shape;
+        final boolean mustFindFirst;
+        final O emptyValue;
+        final Predicate<O> presentPredicate;
+        final Supplier<TerminalSink<T, O>> sinkSupplier;
+
+        /**
+         * Constructs a {@code FindOp}.
+         *
+         * @param mustFindFirst if true, must find the first element in
+         *        encounter order, otherwise can find any element
+         * @param shape stream shape of elements to search
+         * @param emptyValue result value corresponding to "found nothing"
+         * @param presentPredicate {@code Predicate} on result value
+         *        corresponding to "found something"
+         * @param sinkSupplier supplier for a {@code TerminalSink} implementing
+         *        the matching functionality
+         */
+        FindOp(boolean mustFindFirst,
+                       StreamShape shape,
+                       O emptyValue,
+                       Predicate<O> presentPredicate,
+                       Supplier<TerminalSink<T, O>> sinkSupplier) {
+            this.mustFindFirst = mustFindFirst;
+            this.shape = shape;
+            this.emptyValue = emptyValue;
+            this.presentPredicate = presentPredicate;
+            this.sinkSupplier = sinkSupplier;
+        }
+
+        @Override
+        public int getOpFlags() {
+            return StreamOpFlag.IS_SHORT_CIRCUIT | (mustFindFirst ? 0 : StreamOpFlag.NOT_ORDERED);
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return shape;
+        }
+
+        @Override
+        public <S> O evaluateSequential(PipelineHelper<T> helper,
+                                        Spliterator<S> spliterator) {
+            O result = helper.wrapAndCopyInto(sinkSupplier.get(), spliterator).get();
+            return result != null ? result : emptyValue;
+        }
+
+        @Override
+        public <P_IN> O evaluateParallel(PipelineHelper<T> helper,
+                                         Spliterator<P_IN> spliterator) {
+            return new FindTask<>(this, helper, spliterator).invoke();
+        }
+    }
+
+    /**
+     * Implementation of @{code TerminalSink} that implements the find
+     * functionality, requesting cancellation when something has been found
+     *
+     * @param <T> The type of input element
+     * @param <O> The result type, typically an optional type
+     */
+    private static abstract class FindSink<T, O> implements TerminalSink<T, O> {
+        boolean hasValue;
+        T value;
+
+        FindSink() {} // Avoid creation of special accessor
+
+        @Override
+        public void accept(T value) {
+            if (!hasValue) {
+                hasValue = true;
+                this.value = value;
+            }
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return hasValue;
+        }
+
+        /** Specialization of {@code FindSink} for reference streams */
+        static final class OfRef<T> extends FindSink<T, Optional<T>> {
+            @Override
+            public Optional<T> get() {
+                return hasValue ? Optional.of(value) : null;
+            }
+        }
+
+        /** Specialization of {@code FindSink} for int streams */
+        static final class OfInt extends FindSink<Integer, OptionalInt>
+                implements Sink.OfInt {
+            @Override
+            public void accept(int value) {
+                // Boxing is OK here, since few values will actually flow into the sink
+                accept((Integer) value);
+            }
+
+            @Override
+            public OptionalInt get() {
+                return hasValue ? OptionalInt.of(value) : null;
+            }
+        }
+
+        /** Specialization of {@code FindSink} for long streams */
+        static final class OfLong extends FindSink<Long, OptionalLong>
+                implements Sink.OfLong {
+            @Override
+            public void accept(long value) {
+                // Boxing is OK here, since few values will actually flow into the sink
+                accept((Long) value);
+            }
+
+            @Override
+            public OptionalLong get() {
+                return hasValue ? OptionalLong.of(value) : null;
+            }
+        }
+
+        /** Specialization of {@code FindSink} for double streams */
+        static final class OfDouble extends FindSink<Double, OptionalDouble>
+                implements Sink.OfDouble {
+            @Override
+            public void accept(double value) {
+                // Boxing is OK here, since few values will actually flow into the sink
+                accept((Double) value);
+            }
+
+            @Override
+            public OptionalDouble get() {
+                return hasValue ? OptionalDouble.of(value) : null;
+            }
+        }
+    }
+
+    /**
+     * {@code ForkJoinTask} implementing parallel short-circuiting search
+     * @param <P_IN> Input element type to the stream pipeline
+     * @param <P_OUT> Output element type from the stream pipeline
+     * @param <O> Result type from the find operation
+     */
+    @SuppressWarnings("serial")
+    private static final class FindTask<P_IN, P_OUT, O>
+            extends AbstractShortCircuitTask<P_IN, P_OUT, O, FindTask<P_IN, P_OUT, O>> {
+        private final FindOp<P_OUT, O> op;
+
+        FindTask(FindOp<P_OUT, O> op,
+                 PipelineHelper<P_OUT> helper,
+                 Spliterator<P_IN> spliterator) {
+            super(helper, spliterator);
+            this.op = op;
+        }
+
+        FindTask(FindTask<P_IN, P_OUT, O> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+        }
+
+        @Override
+        protected FindTask<P_IN, P_OUT, O> makeChild(Spliterator<P_IN> spliterator) {
+            return new FindTask<>(this, spliterator);
+        }
+
+        @Override
+        protected O getEmptyResult() {
+            return op.emptyValue;
+        }
+
+        private void foundResult(O answer) {
+            if (isLeftmostNode())
+                shortCircuit(answer);
+            else
+                cancelLaterNodes();
+        }
+
+        @Override
+        protected O doLeaf() {
+            O result = helper.wrapAndCopyInto(op.sinkSupplier.get(), spliterator).get();
+            if (!op.mustFindFirst) {
+                if (result != null)
+                    shortCircuit(result);
+                return null;
+            }
+            else {
+                if (result != null) {
+                    foundResult(result);
+                    return result;
+                }
+                else
+                    return null;
+            }
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (op.mustFindFirst) {
+                    for (FindTask<P_IN, P_OUT, O> child = leftChild, p = null; child != p;
+                         p = child, child = rightChild) {
+                    O result = child.getLocalResult();
+                    if (result != null && op.presentPredicate.test(result)) {
+                        setLocalResult(result);
+                        foundResult(result);
+                        break;
+                    }
+                }
+            }
+            super.onCompletion(caller);
+        }
+    }
+}
+
diff --git a/java/util/stream/FlagDeclaringOp.java b/java/util/stream/FlagDeclaringOp.java
new file mode 100644
index 0000000..a9882c8
--- /dev/null
+++ b/java/util/stream/FlagDeclaringOp.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * An operation that injects or clears flags but otherwise performs no operation on elements.
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class FlagDeclaringOp<T> implements StatelessTestOp<T, T> {
+    private final int flags;
+    private final StreamShape shape;
+
+    public FlagDeclaringOp(int flags) {
+        this(flags, StreamShape.REFERENCE);
+    }
+
+    public FlagDeclaringOp(int flags, StreamShape shape) {
+        this.flags = flags;
+        this.shape = shape;
+    }
+
+    @Override
+    public StreamShape outputShape() {
+        return shape;
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return shape;
+    }
+
+    @Override
+    public int opGetFlags() {
+        return flags;
+    }
+
+    @Override
+    public Sink<T> opWrapSink(int flags, boolean parallel, Sink sink) {
+        return sink;
+    }
+}
diff --git a/java/util/stream/FlagOpTest.java b/java/util/stream/FlagOpTest.java
new file mode 100644
index 0000000..1543108
--- /dev/null
+++ b/java/util/stream/FlagOpTest.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.function.Supplier;
+
+import static java.util.stream.LambdaTestHelpers.countTo;
+
+@Test
+public class FlagOpTest extends OpTestCase {
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testFlagsPassThrough(String name, TestData<Integer, Stream<Integer>> data) {
+
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        TestFlagPassThroughOp<Integer>[] ops = new TestFlagPassThroughOp[3];
+        ops[0] = new TestFlagPassThroughOp<>();
+        ops[1] = new TestFlagPassThroughOp<>();
+        ops[2] = new TestFlagPassThroughOp<>();
+
+        ops[0].set(null, ops[1]);
+        ops[1].set(ops[0], ops[2]);
+        ops[2].set(ops[1], null);
+
+        withData(data).ops(ops).exercise();
+    }
+
+    static class TestFlagPassThroughOp<T> extends FlagDeclaringOp<T> {
+        TestFlagPassThroughOp<T> upstream;
+        TestFlagPassThroughOp<T> downstream;
+
+        TestFlagPassThroughOp() {
+            super(0);
+        }
+
+        void set(TestFlagPassThroughOp<T> upstream, TestFlagPassThroughOp<T> downstream)  {
+            this.upstream = upstream;
+            this.downstream = downstream;
+        }
+
+        int wrapFlags;
+
+        @Override
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        public Sink<T> opWrapSink(int flags, boolean parallel, Sink sink) {
+            this.wrapFlags = flags;
+
+            if (downstream != null) {
+                assertTrue(flags == downstream.wrapFlags);
+            }
+
+            return sink;
+        }
+    }
+
+    public void testFlagsClearAllSet() {
+        int clearAllFlags = 0;
+        for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class)) {
+            if (f.isStreamFlag()) {
+                clearAllFlags |= f.clear();
+            }
+        }
+
+        EnumSet<StreamOpFlag> known = EnumSet.noneOf(StreamOpFlag.class);
+        EnumSet<StreamOpFlag> notKnown = StreamOpFlagTestHelper.allStreamFlags();
+
+        List<FlagDeclaringOp<Integer>> ops = new ArrayList<>();
+        ops.add(new FlagDeclaringOp<>(clearAllFlags));
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            if (f.canSet(StreamOpFlag.Type.OP)) {
+                ops.add(new TestFlagExpectedOp<>(f.set(),
+                                             known.clone(),
+                                             EnumSet.noneOf(StreamOpFlag.class),
+                                             notKnown.clone()));
+                known.add(f);
+                notKnown.remove(f);
+            }
+        }
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         EnumSet.noneOf(StreamOpFlag.class),
+                                         notKnown.clone()));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        FlagDeclaringOp[] opsArray = ops.toArray(new FlagDeclaringOp[ops.size()]);
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+                exercise();
+    }
+
+    public void testFlagsSetAllClear() {
+        EnumSet<StreamOpFlag> known = StreamOpFlagTestHelper.allStreamFlags();
+        int setAllFlags = 0;
+        for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class)) {
+            if (f.isStreamFlag()) {
+                if (f.canSet(StreamOpFlag.Type.OP)) {
+                    setAllFlags |= f.set();
+                } else {
+                    known.remove(f);
+                }
+            }
+        }
+
+        EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+        List<FlagDeclaringOp<Integer>> ops = new ArrayList<>();
+        ops.add(new FlagDeclaringOp<>(setAllFlags));
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            ops.add(new TestFlagExpectedOp<>(f.clear(),
+                                             known.clone(),
+                                             EnumSet.noneOf(StreamOpFlag.class),
+                                             notKnown.clone()));
+            known.remove(f);
+            notKnown.add(f);
+        }
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         EnumSet.noneOf(StreamOpFlag.class),
+                                         notKnown.clone()));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        FlagDeclaringOp[] opsArray = ops.toArray(new FlagDeclaringOp[ops.size()]);
+
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+                exercise();
+    }
+
+    public void testFlagsParallelCollect() {
+        testFlagsSetSequence(CollectorOps::collector);
+    }
+
+    private void testFlagsSetSequence(Supplier<StatefulTestOp<Integer>> cf) {
+        EnumSet<StreamOpFlag> known = EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.SIZED);
+        EnumSet<StreamOpFlag> preserve = EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED);
+
+        List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+        for (StreamOpFlag f : EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED)) {
+            ops.add(cf.get());
+            ops.add(new TestFlagExpectedOp<>(f.set(),
+                                             known.clone(),
+                                             preserve.clone(),
+                                             EnumSet.noneOf(StreamOpFlag.class)));
+            known.add(f);
+            preserve.remove(f);
+        }
+        ops.add(cf.get());
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         preserve.clone(),
+                                         EnumSet.noneOf(StreamOpFlag.class)));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+                exercise();
+    }
+
+
+    public void testFlagsClearParallelCollect() {
+        testFlagsClearSequence(CollectorOps::collector);
+    }
+
+    protected void testFlagsClearSequence(Supplier<StatefulTestOp<Integer>> cf) {
+        EnumSet<StreamOpFlag> known = EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.SIZED);
+        EnumSet<StreamOpFlag> preserve = EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED);
+        EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+        List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+        for (StreamOpFlag f : EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.DISTINCT, StreamOpFlag.SORTED)) {
+            ops.add(cf.get());
+            ops.add(new TestFlagExpectedOp<>(f.clear(),
+                                             known.clone(),
+                                             preserve.clone(),
+                                             notKnown.clone()));
+            known.remove(f);
+            preserve.remove(f);
+            notKnown.add(f);
+        }
+        ops.add(cf.get());
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         preserve.clone(),
+                                         notKnown.clone()));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+                exercise();
+    }
+
+    public void testFlagsSizedOrderedParallelCollect() {
+        EnumSet<StreamOpFlag> parKnown = EnumSet.of(StreamOpFlag.SIZED);
+        EnumSet<StreamOpFlag> serKnown = parKnown.clone();
+
+        List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+        for (StreamOpFlag f : parKnown) {
+            ops.add(CollectorOps.collector());
+            ops.add(new ParSerTestFlagExpectedOp<>(f.clear(),
+                                             parKnown,
+                                             serKnown));
+            serKnown.remove(f);
+        }
+        ops.add(CollectorOps.collector());
+        ops.add(new ParSerTestFlagExpectedOp<>(0,
+                                         parKnown,
+                                         EnumSet.noneOf(StreamOpFlag.class)));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+        withData(data).ops(opsArray).exercise();
+    }
+
+    static class ParSerTestFlagExpectedOp<T> extends FlagDeclaringOp<T> {
+        final EnumSet<StreamOpFlag> parKnown;
+        final EnumSet<StreamOpFlag> serKnown;
+
+        ParSerTestFlagExpectedOp(int flags, EnumSet<StreamOpFlag> known, EnumSet<StreamOpFlag> serKnown) {
+            super(flags);
+            this.parKnown = known;
+            this.serKnown = serKnown;
+        }
+
+        @Override
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        public Sink<T> opWrapSink(int flags, boolean parallel, Sink upstream) {
+            assertFlags(flags, parallel);
+            return upstream;
+        }
+
+        protected void assertFlags(int flags, boolean parallel) {
+            if (parallel) {
+                for (StreamOpFlag f : parKnown) {
+                    Assert.assertTrue(f.isKnown(flags), String.format("Flag %s is not known, but should be known.", f.toString()));
+                }
+
+            } else {
+                for (StreamOpFlag f : serKnown) {
+                    Assert.assertTrue(f.isKnown(flags), String.format("Flag %s is not known, but should be known.", f.toString()));
+                }
+
+            }
+        }
+    }
+}
diff --git a/java/util/stream/ForEachOps.java b/java/util/stream/ForEachOps.java
new file mode 100644
index 0000000..b527f05
--- /dev/null
+++ b/java/util/stream/ForEachOps.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinTask;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+
+/**
+ * Factory for creating instances of {@code TerminalOp} that perform an
+ * action for every element of a stream.  Supported variants include unordered
+ * traversal (elements are provided to the {@code Consumer} as soon as they are
+ * available), and ordered traversal (elements are provided to the
+ * {@code Consumer} in encounter order.)
+ *
+ * <p>Elements are provided to the {@code Consumer} on whatever thread and
+ * whatever order they become available.  For ordered traversals, it is
+ * guaranteed that processing an element <em>happens-before</em> processing
+ * subsequent elements in the encounter order.
+ *
+ * <p>Exceptions occurring as a result of sending an element to the
+ * {@code Consumer} will be relayed to the caller and traversal will be
+ * prematurely terminated.
+ *
+ * @since 1.8
+ */
+final class ForEachOps {
+
+    private ForEachOps() { }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of a stream.
+     *
+     * @param action the {@code Consumer} that receives all elements of a
+     *        stream
+     * @param ordered whether an ordered traversal is requested
+     * @param <T> the type of the stream elements
+     * @return the {@code TerminalOp} instance
+     */
+    public static <T> TerminalOp<T, Void> makeRef(Consumer<? super T> action,
+                                                  boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfRef<>(action, ordered);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of an {@code IntStream}.
+     *
+     * @param action the {@code IntConsumer} that receives all elements of a
+     *        stream
+     * @param ordered whether an ordered traversal is requested
+     * @return the {@code TerminalOp} instance
+     */
+    public static TerminalOp<Integer, Void> makeInt(IntConsumer action,
+                                                    boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfInt(action, ordered);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of a {@code LongStream}.
+     *
+     * @param action the {@code LongConsumer} that receives all elements of a
+     *        stream
+     * @param ordered whether an ordered traversal is requested
+     * @return the {@code TerminalOp} instance
+     */
+    public static TerminalOp<Long, Void> makeLong(LongConsumer action,
+                                                  boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfLong(action, ordered);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of a {@code DoubleStream}.
+     *
+     * @param action the {@code DoubleConsumer} that receives all elements of
+     *        a stream
+     * @param ordered whether an ordered traversal is requested
+     * @return the {@code TerminalOp} instance
+     */
+    public static TerminalOp<Double, Void> makeDouble(DoubleConsumer action,
+                                                      boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfDouble(action, ordered);
+    }
+
+    /**
+     * A {@code TerminalOp} that evaluates a stream pipeline and sends the
+     * output to itself as a {@code TerminalSink}.  Elements will be sent in
+     * whatever thread they become available.  If the traversal is unordered,
+     * they will be sent independent of the stream's encounter order.
+     *
+     * <p>This terminal operation is stateless.  For parallel evaluation, each
+     * leaf instance of a {@code ForEachTask} will send elements to the same
+     * {@code TerminalSink} reference that is an instance of this class.
+     *
+     * @param <T> the output type of the stream pipeline
+     */
+    static abstract class ForEachOp<T>
+            implements TerminalOp<T, Void>, TerminalSink<T, Void> {
+        private final boolean ordered;
+
+        protected ForEachOp(boolean ordered) {
+            this.ordered = ordered;
+        }
+
+        // TerminalOp
+
+        @Override
+        public int getOpFlags() {
+            return ordered ? 0 : StreamOpFlag.NOT_ORDERED;
+        }
+
+        @Override
+        public <S> Void evaluateSequential(PipelineHelper<T> helper,
+                                           Spliterator<S> spliterator) {
+            return helper.wrapAndCopyInto(this, spliterator).get();
+        }
+
+        @Override
+        public <S> Void evaluateParallel(PipelineHelper<T> helper,
+                                         Spliterator<S> spliterator) {
+            if (ordered)
+                new ForEachOrderedTask<>(helper, spliterator, this).invoke();
+            else
+                new ForEachTask<>(helper, spliterator, helper.wrapSink(this)).invoke();
+            return null;
+        }
+
+        // TerminalSink
+
+        @Override
+        public Void get() {
+            return null;
+        }
+
+        // Implementations
+
+        /** Implementation class for reference streams */
+        static final class OfRef<T> extends ForEachOp<T> {
+            final Consumer<? super T> consumer;
+
+            OfRef(Consumer<? super T> consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public void accept(T t) {
+                consumer.accept(t);
+            }
+        }
+
+        /** Implementation class for {@code IntStream} */
+        static final class OfInt extends ForEachOp<Integer>
+                implements Sink.OfInt {
+            final IntConsumer consumer;
+
+            OfInt(IntConsumer consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public StreamShape inputShape() {
+                return StreamShape.INT_VALUE;
+            }
+
+            @Override
+            public void accept(int t) {
+                consumer.accept(t);
+            }
+        }
+
+        /** Implementation class for {@code LongStream} */
+        static final class OfLong extends ForEachOp<Long>
+                implements Sink.OfLong {
+            final LongConsumer consumer;
+
+            OfLong(LongConsumer consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public StreamShape inputShape() {
+                return StreamShape.LONG_VALUE;
+            }
+
+            @Override
+            public void accept(long t) {
+                consumer.accept(t);
+            }
+        }
+
+        /** Implementation class for {@code DoubleStream} */
+        static final class OfDouble extends ForEachOp<Double>
+                implements Sink.OfDouble {
+            final DoubleConsumer consumer;
+
+            OfDouble(DoubleConsumer consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public StreamShape inputShape() {
+                return StreamShape.DOUBLE_VALUE;
+            }
+
+            @Override
+            public void accept(double t) {
+                consumer.accept(t);
+            }
+        }
+    }
+
+    /** A {@code ForkJoinTask} for performing a parallel for-each operation */
+    @SuppressWarnings("serial")
+    static final class ForEachTask<S, T> extends CountedCompleter<Void> {
+        private Spliterator<S> spliterator;
+        private final Sink<S> sink;
+        private final PipelineHelper<T> helper;
+        private long targetSize;
+
+        ForEachTask(PipelineHelper<T> helper,
+                    Spliterator<S> spliterator,
+                    Sink<S> sink) {
+            super(null);
+            this.sink = sink;
+            this.helper = helper;
+            this.spliterator = spliterator;
+            this.targetSize = 0L;
+        }
+
+        ForEachTask(ForEachTask<S, T> parent, Spliterator<S> spliterator) {
+            super(parent);
+            this.spliterator = spliterator;
+            this.sink = parent.sink;
+            this.targetSize = parent.targetSize;
+            this.helper = parent.helper;
+        }
+
+        // Similar to AbstractTask but doesn't need to track child tasks
+        public void compute() {
+            Spliterator<S> rightSplit = spliterator, leftSplit;
+            long sizeEstimate = rightSplit.estimateSize(), sizeThreshold;
+            if ((sizeThreshold = targetSize) == 0L)
+                targetSize = sizeThreshold = AbstractTask.suggestTargetSize(sizeEstimate);
+            boolean isShortCircuit = StreamOpFlag.SHORT_CIRCUIT.isKnown(helper.getStreamAndOpFlags());
+            boolean forkRight = false;
+            Sink<S> taskSink = sink;
+            ForEachTask<S, T> task = this;
+            while (!isShortCircuit || !taskSink.cancellationRequested()) {
+                if (sizeEstimate <= sizeThreshold ||
+                    (leftSplit = rightSplit.trySplit()) == null) {
+                    task.helper.copyInto(taskSink, rightSplit);
+                    break;
+                }
+                ForEachTask<S, T> leftTask = new ForEachTask<>(task, leftSplit);
+                task.addToPendingCount(1);
+                ForEachTask<S, T> taskToFork;
+                if (forkRight) {
+                    forkRight = false;
+                    rightSplit = leftSplit;
+                    taskToFork = task;
+                    task = leftTask;
+                }
+                else {
+                    forkRight = true;
+                    taskToFork = leftTask;
+                }
+                taskToFork.fork();
+                sizeEstimate = rightSplit.estimateSize();
+            }
+            task.spliterator = null;
+            task.propagateCompletion();
+        }
+    }
+
+    /**
+     * A {@code ForkJoinTask} for performing a parallel for-each operation
+     * which visits the elements in encounter order
+     */
+    @SuppressWarnings("serial")
+    static final class ForEachOrderedTask<S, T> extends CountedCompleter<Void> {
+        /*
+         * Our goal is to ensure that the elements associated with a task are
+         * processed according to an in-order traversal of the computation tree.
+         * We use completion counts for representing these dependencies, so that
+         * a task does not complete until all the tasks preceding it in this
+         * order complete.  We use the "completion map" to associate the next
+         * task in this order for any left child.  We increase the pending count
+         * of any node on the right side of such a mapping by one to indicate
+         * its dependency, and when a node on the left side of such a mapping
+         * completes, it decrements the pending count of its corresponding right
+         * side.  As the computation tree is expanded by splitting, we must
+         * atomically update the mappings to maintain the invariant that the
+         * completion map maps left children to the next node in the in-order
+         * traversal.
+         *
+         * Take, for example, the following computation tree of tasks:
+         *
+         *       a
+         *      / \
+         *     b   c
+         *    / \ / \
+         *   d  e f  g
+         *
+         * The complete map will contain (not necessarily all at the same time)
+         * the following associations:
+         *
+         *   d -> e
+         *   b -> f
+         *   f -> g
+         *
+         * Tasks e, f, g will have their pending counts increased by 1.
+         *
+         * The following relationships hold:
+         *
+         *   - completion of d "happens-before" e;
+         *   - completion of d and e "happens-before b;
+         *   - completion of b "happens-before" f; and
+         *   - completion of f "happens-before" g
+         *
+         * Thus overall the "happens-before" relationship holds for the
+         * reporting of elements, covered by tasks d, e, f and g, as specified
+         * by the forEachOrdered operation.
+         */
+
+        private final PipelineHelper<T> helper;
+        private Spliterator<S> spliterator;
+        private final long targetSize;
+        private final ConcurrentHashMap<ForEachOrderedTask<S, T>, ForEachOrderedTask<S, T>> completionMap;
+        private final Sink<T> action;
+        private final ForEachOrderedTask<S, T> leftPredecessor;
+        private Node<T> node;
+
+        protected ForEachOrderedTask(PipelineHelper<T> helper,
+                                     Spliterator<S> spliterator,
+                                     Sink<T> action) {
+            super(null);
+            this.helper = helper;
+            this.spliterator = spliterator;
+            this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize());
+            // Size map to avoid concurrent re-sizes
+            this.completionMap = new ConcurrentHashMap<>(Math.max(16, AbstractTask.LEAF_TARGET << 1));
+            this.action = action;
+            this.leftPredecessor = null;
+        }
+
+        ForEachOrderedTask(ForEachOrderedTask<S, T> parent,
+                           Spliterator<S> spliterator,
+                           ForEachOrderedTask<S, T> leftPredecessor) {
+            super(parent);
+            this.helper = parent.helper;
+            this.spliterator = spliterator;
+            this.targetSize = parent.targetSize;
+            this.completionMap = parent.completionMap;
+            this.action = parent.action;
+            this.leftPredecessor = leftPredecessor;
+        }
+
+        @Override
+        public final void compute() {
+            doCompute(this);
+        }
+
+        private static <S, T> void doCompute(ForEachOrderedTask<S, T> task) {
+            Spliterator<S> rightSplit = task.spliterator, leftSplit;
+            long sizeThreshold = task.targetSize;
+            boolean forkRight = false;
+            while (rightSplit.estimateSize() > sizeThreshold &&
+                   (leftSplit = rightSplit.trySplit()) != null) {
+                ForEachOrderedTask<S, T> leftChild =
+                    new ForEachOrderedTask<>(task, leftSplit, task.leftPredecessor);
+                ForEachOrderedTask<S, T> rightChild =
+                    new ForEachOrderedTask<>(task, rightSplit, leftChild);
+
+                // Fork the parent task
+                // Completion of the left and right children "happens-before"
+                // completion of the parent
+                task.addToPendingCount(1);
+                // Completion of the left child "happens-before" completion of
+                // the right child
+                rightChild.addToPendingCount(1);
+                task.completionMap.put(leftChild, rightChild);
+
+                // If task is not on the left spine
+                if (task.leftPredecessor != null) {
+                    /*
+                     * Completion of left-predecessor, or left subtree,
+                     * "happens-before" completion of left-most leaf node of
+                     * right subtree.
+                     * The left child's pending count needs to be updated before
+                     * it is associated in the completion map, otherwise the
+                     * left child can complete prematurely and violate the
+                     * "happens-before" constraint.
+                     */
+                    leftChild.addToPendingCount(1);
+                    // Update association of left-predecessor to left-most
+                    // leaf node of right subtree
+                    if (task.completionMap.replace(task.leftPredecessor, task, leftChild)) {
+                        // If replaced, adjust the pending count of the parent
+                        // to complete when its children complete
+                        task.addToPendingCount(-1);
+                    } else {
+                        // Left-predecessor has already completed, parent's
+                        // pending count is adjusted by left-predecessor;
+                        // left child is ready to complete
+                        leftChild.addToPendingCount(-1);
+                    }
+                }
+
+                ForEachOrderedTask<S, T> taskToFork;
+                if (forkRight) {
+                    forkRight = false;
+                    rightSplit = leftSplit;
+                    task = leftChild;
+                    taskToFork = rightChild;
+                }
+                else {
+                    forkRight = true;
+                    task = rightChild;
+                    taskToFork = leftChild;
+                }
+                taskToFork.fork();
+            }
+
+            /*
+             * Task's pending count is either 0 or 1.  If 1 then the completion
+             * map will contain a value that is task, and two calls to
+             * tryComplete are required for completion, one below and one
+             * triggered by the completion of task's left-predecessor in
+             * onCompletion.  Therefore there is no data race within the if
+             * block.
+             */
+            if (task.getPendingCount() > 0) {
+                // Cannot complete just yet so buffer elements into a Node
+                // for use when completion occurs
+                @SuppressWarnings("unchecked")
+                IntFunction<T[]> generator = size -> (T[]) new Object[size];
+                Node.Builder<T> nb = task.helper.makeNodeBuilder(
+                        task.helper.exactOutputSizeIfKnown(rightSplit),
+                        generator);
+                task.node = task.helper.wrapAndCopyInto(nb, rightSplit).build();
+                task.spliterator = null;
+            }
+            task.tryComplete();
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (node != null) {
+                // Dump buffered elements from this leaf into the sink
+                node.forEach(action);
+                node = null;
+            }
+            else if (spliterator != null) {
+                // Dump elements output from this leaf's pipeline into the sink
+                helper.wrapAndCopyInto(action, spliterator);
+                spliterator = null;
+            }
+
+            // The completion of this task *and* the dumping of elements
+            // "happens-before" completion of the associated left-most leaf task
+            // of right subtree (if any, which can be this task's right sibling)
+            //
+            ForEachOrderedTask<S, T> leftDescendant = completionMap.remove(this);
+            if (leftDescendant != null)
+                leftDescendant.tryComplete();
+        }
+    }
+}
diff --git a/java/util/stream/IntNodeTest.java b/java/util/stream/IntNodeTest.java
new file mode 100644
index 0000000..e050e63
--- /dev/null
+++ b/java/util/stream/IntNodeTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class IntNodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            int[] array = new int[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Integer>> nodes = new ArrayList<>();
+
+            nodes.add(Nodes.node(array));
+            nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
+            nodes.add(tree(toList(array), l -> Nodes.node(toIntArray(l))));
+            nodes.add(fill(array, Nodes.intBuilder(array.length)));
+            nodes.add(fill(array, Nodes.intBuilder()));
+
+            for (Node<Integer> node : nodes) {
+                params.add(new Object[]{array, node});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    private static void assertEqualsListIntArray(List<Integer> list, int[] array) {
+        assertEquals(list.size(), array.length);
+        for (int i = 0; i < array.length; i++)
+            assertEquals(array[i], (int) list.get(i));
+    }
+
+    private List<Integer> toList(int[] a) {
+        List<Integer> l = new ArrayList<>();
+        for (int i : a) {
+            l.add(i);
+        }
+
+        return l;
+    }
+
+    private int[] toIntArray(List<Integer> l) {
+        int[] a = new int[l.size()];
+
+        int i = 0;
+        for (Integer e : l) {
+            a[i++] = e;
+        }
+        return a;
+    }
+
+    private Node.OfInt fill(int[] array, Node.Builder.OfInt nb) {
+        nb.begin(array.length);
+        for (int i : array)
+            nb.accept(i);
+        nb.end();
+        return nb.build();
+    }
+
+    private Node.OfInt degenerateTree(PrimitiveIterator.OfInt it) {
+        if (!it.hasNext()) {
+            return Nodes.node(new int[0]);
+        }
+
+        int i = it.nextInt();
+        if (it.hasNext()) {
+            return new Nodes.ConcNode.OfInt(Nodes.node(new int[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new int[] {i});
+        }
+    }
+
+    private Node.OfInt tree(List<Integer> l, Function<List<Integer>, Node.OfInt> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.ConcNode.OfInt(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(int[] array, Node.OfInt n) {
+        assertEquals(n.asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(int[] array, Node.OfInt n) {
+        assertEquals(Nodes.flattenInt(n).asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(int[] array, Node.OfInt n) {
+        int[] copy = new int[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(int[] array, Node.OfInt n) {
+        List<Integer> l = new ArrayList<>((int) n.count());
+        n.forEach((int e) -> {
+            l.add(e);
+        });
+
+        assertEqualsListIntArray(l, array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(int[] array, Node.OfInt n) {
+        TestData.OfInt data = TestData.Factory.ofNode("Node", n);
+
+        exerciseOps(data, s -> s);
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testSpliterator(int[] array, Node.OfInt n) {
+        SpliteratorTestHelper.testIntSpliterator(n::spliterator);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testTruncate(int[] array, Node.OfInt n) {
+        int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+        for (int start : nums)
+            for (int end : nums) {
+                if (start < 0 || end < 0 || end < start || end > array.length)
+                    continue;
+                Node.OfInt slice = n.truncate(start, end, Integer[]::new);
+                int[] asArray = slice.asPrimitiveArray();
+                for (int k = start; k < end; k++)
+                    assertEquals(array[k], asArray[k - start]);
+            }
+    }
+}
diff --git a/java/util/stream/IntPipeline.java b/java/util/stream/IntPipeline.java
new file mode 100644
index 0000000..11f0bb7
--- /dev/null
+++ b/java/util/stream/IntPipeline.java
@@ -0,0 +1,665 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.IntSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.ObjIntConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code int}.
+ *
+ * @param <E_IN> type of elements in the upstream source
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class IntPipeline<E_IN>
+        extends AbstractPipeline<E_IN, Integer, IntStream>
+        implements IntStream {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    IntPipeline(Supplier<? extends Spliterator<Integer>> source,
+                int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    IntPipeline(Spliterator<Integer> source,
+                int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing
+     * pipeline.
+     *
+     * @param upstream the upstream element source
+     * @param opFlags the operation flags for the new operation
+     */
+    IntPipeline(AbstractPipeline<?, E_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    /**
+     * Adapt a {@code Sink<Integer> to an {@code IntConsumer}, ideally simply
+     * by casting.
+     */
+    private static IntConsumer adapt(Sink<Integer> sink) {
+        if (sink instanceof IntConsumer) {
+            return (IntConsumer) sink;
+        }
+        else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using IntStream.adapt(Sink<Integer> s)");
+            return sink::accept;
+        }
+    }
+
+    /**
+     * Adapt a {@code Spliterator<Integer>} to a {@code Spliterator.OfInt}.
+     *
+     * @implNote
+     * The implementation attempts to cast to a Spliterator.OfInt, and throws an
+     * exception if this cast is not possible.
+     */
+    private static Spliterator.OfInt adapt(Spliterator<Integer> s) {
+        if (s instanceof Spliterator.OfInt) {
+            return (Spliterator.OfInt) s;
+        }
+        else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using IntStream.adapt(Spliterator<Integer> s)");
+            throw new UnsupportedOperationException("IntStream.adapt(Spliterator<Integer> s)");
+        }
+    }
+
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.INT_VALUE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<Integer> evaluateToNode(PipelineHelper<Integer> helper,
+                                                     Spliterator<P_IN> spliterator,
+                                                     boolean flattenTree,
+                                                     IntFunction<Integer[]> generator) {
+        return Nodes.collectInt(helper, spliterator, flattenTree);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<Integer> wrap(PipelineHelper<Integer> ph,
+                                                  Supplier<Spliterator<P_IN>> supplier,
+                                                  boolean isParallel) {
+        return new StreamSpliterators.IntWrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator.OfInt lazySpliterator(Supplier<? extends Spliterator<Integer>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator.OfInt((Supplier<Spliterator.OfInt>) supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final void forEachWithCancel(Spliterator<Integer> spliterator, Sink<Integer> sink) {
+        Spliterator.OfInt spl = adapt(spliterator);
+        IntConsumer adaptedSink = adapt(sink);
+        do { } while (!sink.cancellationRequested() && spl.tryAdvance(adaptedSink));
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<Integer> makeNodeBuilder(long exactSizeIfKnown,
+                                                       IntFunction<Integer[]> generator) {
+        return Nodes.intBuilder(exactSizeIfKnown);
+    }
+
+
+    // IntStream
+
+    @Override
+    public final PrimitiveIterator.OfInt iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public final Spliterator.OfInt spliterator() {
+        return adapt(super.spliterator());
+    }
+
+    // Stateless intermediate ops from IntStream
+
+    @Override
+    public final LongStream asLongStream() {
+        return new LongPipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            public Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedInt<Long>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept((long) t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream asDoubleStream() {
+        return new DoublePipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                                       StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedInt<Double>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept((double) t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final Stream<Integer> boxed() {
+        return mapToObj(Integer::valueOf);
+    }
+
+    @Override
+    public final IntStream map(IntUnaryOperator mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.applyAsInt(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <U> Stream<U> mapToObj(IntFunction<? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        return new ReferencePipeline.StatelessOp<Integer, U>(this, StreamShape.INT_VALUE,
+                                                             StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedInt<U>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream mapToLong(IntToLongFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new LongPipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedInt<Long>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.applyAsLong(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream mapToDouble(IntToDoubleFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new DoublePipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                                       StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedInt<Double>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.applyAsDouble(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream flatMap(IntFunction<? extends IntStream> mapper) {
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(int t) {
+                        try (IntStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public IntStream unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final IntStream filter(IntPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(int t) {
+                        if (predicate.test(t))
+                            downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream peek(IntConsumer action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        action.accept(t);
+                        downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate ops from IntStream
+
+    @Override
+    public final IntStream limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeInt(this, 0, maxSize);
+    }
+
+    @Override
+    public final IntStream skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else
+            return SliceOps.makeInt(this, n, -1);
+    }
+
+    @Override
+    public final IntStream sorted() {
+        return SortedOps.makeInt(this);
+    }
+
+    @Override
+    public final IntStream distinct() {
+        // While functional and quick to implement, this approach is not very efficient.
+        // An efficient version requires an int-specific map/set implementation.
+        return boxed().distinct().mapToInt(i -> i);
+    }
+
+    // Terminal ops from IntStream
+
+    @Override
+    public void forEach(IntConsumer action) {
+        evaluate(ForEachOps.makeInt(action, false));
+    }
+
+    @Override
+    public void forEachOrdered(IntConsumer action) {
+        evaluate(ForEachOps.makeInt(action, true));
+    }
+
+    @Override
+    public final int sum() {
+        return reduce(0, Integer::sum);
+    }
+
+    @Override
+    public final OptionalInt min() {
+        return reduce(Math::min);
+    }
+
+    @Override
+    public final OptionalInt max() {
+        return reduce(Math::max);
+    }
+
+    @Override
+    public final long count() {
+        return mapToLong(e -> 1L).sum();
+    }
+
+    @Override
+    public final OptionalDouble average() {
+        long[] avg = collect(() -> new long[2],
+                             (ll, i) -> {
+                                 ll[0]++;
+                                 ll[1] += i;
+                             },
+                             (ll, rr) -> {
+                                 ll[0] += rr[0];
+                                 ll[1] += rr[1];
+                             });
+        return avg[0] > 0
+               ? OptionalDouble.of((double) avg[1] / avg[0])
+               : OptionalDouble.empty();
+    }
+
+    @Override
+    public final IntSummaryStatistics summaryStatistics() {
+        return collect(IntSummaryStatistics::new, IntSummaryStatistics::accept,
+                       IntSummaryStatistics::combine);
+    }
+
+    @Override
+    public final int reduce(int identity, IntBinaryOperator op) {
+        return evaluate(ReduceOps.makeInt(identity, op));
+    }
+
+    @Override
+    public final OptionalInt reduce(IntBinaryOperator op) {
+        return evaluate(ReduceOps.makeInt(op));
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               ObjIntConsumer<R> accumulator,
+                               BiConsumer<R, R> combiner) {
+        BinaryOperator<R> operator = (left, right) -> {
+            combiner.accept(left, right);
+            return left;
+        };
+        return evaluate(ReduceOps.makeInt(supplier, accumulator, operator));
+    }
+
+    @Override
+    public final boolean anyMatch(IntPredicate predicate) {
+        return evaluate(MatchOps.makeInt(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(IntPredicate predicate) {
+        return evaluate(MatchOps.makeInt(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(IntPredicate predicate) {
+        return evaluate(MatchOps.makeInt(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final OptionalInt findFirst() {
+        return evaluate(FindOps.makeInt(true));
+    }
+
+    @Override
+    public final OptionalInt findAny() {
+        return evaluate(FindOps.makeInt(false));
+    }
+
+    @Override
+    public final int[] toArray() {
+        return Nodes.flattenInt((Node.OfInt) evaluateToArrayNode(Integer[]::new))
+                        .asPrimitiveArray();
+    }
+
+    //
+
+    /**
+     * Source stage of an IntStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN> extends IntPipeline<E_IN> {
+        /**
+         * Constructor for the source stage of an IntStream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<Integer>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of an IntStream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<Integer> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<Integer> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(IntConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            }
+            else {
+                super.forEach(action);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(IntConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            }
+            else {
+                super.forEachOrdered(action);
+            }
+        }
+    }
+
+    /**
+     * Base class for a stateless intermediate stage of an IntStream
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN> extends IntPipeline<E_IN> {
+        /**
+         * Construct a new IntStream by appending a stateless intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of an IntStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN> extends IntPipeline<E_IN> {
+        /**
+         * Construct a new IntStream by appending a stateful intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                         Spliterator<P_IN> spliterator,
+                                                         IntFunction<Integer[]> generator);
+    }
+}
diff --git a/java/util/stream/IntStream.java b/java/util/stream/IntStream.java
new file mode 100644
index 0000000..94c2924
--- /dev/null
+++ b/java/util/stream/IntStream.java
@@ -0,0 +1,912 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Arrays;
+import java.util.IntSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntSupplier;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.ObjIntConsumer;
+import java.util.function.Supplier;
+
+/**
+ * A sequence of primitive int-valued elements supporting sequential and parallel
+ * aggregate operations.  This is the {@code int} primitive specialization of
+ * {@link Stream}.
+ *
+ * <p>The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}, computing the sum of the weights of the
+ * red widgets:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism.
+ *
+ * @since 1.8
+ * @see Stream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface IntStream extends BaseStream<Integer, IntStream> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    IntStream filter(IntPredicate predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream map(IntUnaryOperator mapper);
+
+    /**
+     * Returns an object-valued {@code Stream} consisting of the results of
+     * applying the given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param <U> the element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <U> Stream<U> mapToObj(IntFunction<? extends U> mapper);
+
+    /**
+     * Returns a {@code LongStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream mapToLong(IntToLongFunction mapper);
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream mapToDouble(IntToDoubleFunction mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces an
+     *               {@code IntStream} of new values
+     * @return the new stream
+     * @see Stream#flatMap(Function)
+     */
+    IntStream flatMap(IntFunction<? extends IntStream> mapper);
+
+    /**
+     * Returns a stream consisting of the distinct elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    IntStream distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream in sorted
+     * order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    IntStream sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     IntStream.of(1, 2, 3, 4)
+     *         .filter(e -> e > 2)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(e -> e * e)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .sum();
+     * }</pre>
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements as
+     *               they are consumed from the stream
+     * @return the new stream
+     */
+    IntStream peek(IntConsumer action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(IntSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    IntStream limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(IntSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    IntStream skip(long n);
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(IntConsumer action);
+
+    /**
+     * Performs an action for each element of this stream, guaranteeing that
+     * each element is processed in encounter order for streams that have a
+     * defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(IntConsumer)
+     */
+    void forEachOrdered(IntConsumer action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array containing the elements of this stream
+     */
+    int[] toArray();
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     int result = identity;
+     *     for (int element : this stream)
+     *         result = accumulator.applyAsInt(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code x},
+     * {@code accumulator.apply(identity, x)} is equal to {@code x}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min, max, and average are all special cases of reduction.
+     * Summing a stream of numbers can be expressed as:
+     *
+     * <pre>{@code
+     *     int sum = integers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or more compactly:
+     *
+     * <pre>{@code
+     *     int sum = integers.reduce(0, Integer::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #sum()
+     * @see #min()
+     * @see #max()
+     * @see #average()
+     */
+    int reduce(int identity, IntBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code OptionalInt} describing the reduced value,
+     * if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     int result = null;
+     *     for (int element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.applyAsInt(result, element);
+     *     }
+     *     return foundAny ? OptionalInt.of(result) : OptionalInt.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #reduce(int, IntBinaryOperator)
+     */
+    OptionalInt reduce(IntBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (int element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(int, IntBinaryOperator)}, {@code collect} operations
+     * can be parallelized without requiring additional synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param <R> type of the result
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for incorporating an additional element into a result
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values, which must be
+     *                    compatible with the accumulator function
+     * @return the result of the reduction
+     * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
+     */
+    <R> R collect(Supplier<R> supplier,
+                  ObjIntConsumer<R> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Returns the sum of elements in this stream.  This is a special case
+     * of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(0, Integer::sum);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return the sum of elements in this stream
+     */
+    int sum();
+
+    /**
+     * Returns an {@code OptionalInt} describing the minimum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Integer::min);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return an {@code OptionalInt} containing the minimum element of this
+     * stream, or an empty {@code OptionalInt} if the stream is empty
+     */
+    OptionalInt min();
+
+    /**
+     * Returns an {@code OptionalInt} describing the maximum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Integer::max);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalInt} containing the maximum element of this
+     * stream, or an empty {@code OptionalInt} if the stream is empty
+     */
+    OptionalInt max();
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return mapToLong(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
+     * this stream, or an empty optional if this stream is empty.  This is a
+     * special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the average element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble average();
+
+    /**
+     * Returns an {@code IntSummaryStatistics} describing various
+     * summary data about the elements of this stream.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code IntSummaryStatistics} describing various summary data
+     * about the elements of this stream
+     */
+    IntSummaryStatistics summaryStatistics();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(IntPredicate predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(IntPredicate predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(IntPredicate predicate);
+
+    /**
+     * Returns an {@link OptionalInt} describing the first element of this
+     * stream, or an empty {@code OptionalInt} if the stream is empty.  If the
+     * stream has no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code OptionalInt} describing the first element of this stream,
+     * or an empty {@code OptionalInt} if the stream is empty
+     */
+    OptionalInt findFirst();
+
+    /**
+     * Returns an {@link OptionalInt} describing some element of the stream, or
+     * an empty {@code OptionalInt} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code OptionalInt} describing some element of this stream, or
+     * an empty {@code OptionalInt} if the stream is empty
+     * @see #findFirst()
+     */
+    OptionalInt findAny();
+
+    /**
+     * Returns a {@code LongStream} consisting of the elements of this stream,
+     * converted to {@code long}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code LongStream} consisting of the elements of this stream,
+     * converted to {@code long}
+     */
+    LongStream asLongStream();
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}
+     */
+    DoubleStream asDoubleStream();
+
+    /**
+     * Returns a {@code Stream} consisting of the elements of this stream,
+     * each boxed to an {@code Integer}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code Stream} consistent of the elements of this stream,
+     * each boxed to an {@code Integer}
+     */
+    Stream<Integer> boxed();
+
+    @Override
+    IntStream sequential();
+
+    @Override
+    IntStream parallel();
+
+    @Override
+    PrimitiveIterator.OfInt iterator();
+
+    @Override
+    Spliterator.OfInt spliterator();
+
+    // Static factories
+
+    /**
+     * Returns a builder for an {@code IntStream}.
+     *
+     * @return a stream builder
+     */
+    public static Builder builder() {
+        return new Streams.IntStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code IntStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static IntStream empty() {
+        return StreamSupport.intStream(Spliterators.emptyIntSpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code IntStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static IntStream of(int t) {
+        return StreamSupport.intStream(new Streams.IntStreamBuilderImpl(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static IntStream of(int... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code IntStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code IntStream} will be
+     * the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return A new sequential {@code IntStream}
+     */
+    public static IntStream iterate(final int seed, final IntUnaryOperator f) {
+        Objects.requireNonNull(f);
+        final PrimitiveIterator.OfInt iterator = new PrimitiveIterator.OfInt() {
+            int t = seed;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public int nextInt() {
+                int v = t;
+                t = f.applyAsInt(t);
+                return v;
+            }
+        };
+        return StreamSupport.intStream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code IntSupplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param s the {@code IntSupplier} for generated elements
+     * @return a new infinite sequential unordered {@code IntStream}
+     */
+    public static IntStream generate(IntSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.intStream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfInt(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
+     * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (int i = startInclusive; i < endExclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @return a sequential {@code IntStream} for the range of {@code int}
+     *         elements
+     */
+    public static IntStream range(int startInclusive, int endExclusive) {
+        if (startInclusive >= endExclusive) {
+            return empty();
+        } else {
+            return StreamSupport.intStream(
+                    new Streams.RangeIntSpliterator(startInclusive, endExclusive, false), false);
+        }
+    }
+
+    /**
+     * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
+     * (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (int i = startInclusive; i <= endInclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endInclusive the inclusive upper bound
+     * @return a sequential {@code IntStream} for the range of {@code int}
+     *         elements
+     */
+    public static IntStream rangeClosed(int startInclusive, int endInclusive) {
+        if (startInclusive > endInclusive) {
+            return empty();
+        } else {
+            return StreamSupport.intStream(
+                    new Streams.RangeIntSpliterator(startInclusive, endInclusive, true), false);
+        }
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowException}.
+     *
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static IntStream concat(IntStream a, IntStream b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        Spliterator.OfInt split = new Streams.ConcatSpliterator.OfInt(
+                a.spliterator(), b.spliterator());
+        IntStream stream = StreamSupport.intStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for an {@code IntStream}.
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase
+     * begins when the {@link #build()} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
+     * @see IntStream#builder()
+     * @since 1.8
+     */
+    public interface Builder extends IntConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(int t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default Builder add(int t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        IntStream build();
+    }
+}
diff --git a/java/util/stream/IntStreamTestDataProvider.java b/java/util/stream/IntStreamTestDataProvider.java
new file mode 100644
index 0000000..dded670
--- /dev/null
+++ b/java/util/stream/IntStreamTestDataProvider.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for int-valued streams */
+public class IntStreamTestDataProvider {
+    private static final int[] to0 = new int[0];
+    private static final int[] to1 = new int[1];
+    private static final int[] to10 = new int[10];
+    private static final int[] to100 = new int[100];
+    private static final int[] to1000 = new int[1000];
+    private static final int[] reversed = new int[100];
+    private static final int[] ones = new int[100];
+    private static final int[] twice = new int[200];
+    private static final int[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        int[][] arrays = {to0, to1, to10, to100, to1000};
+        for (int[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new int[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (int) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final int[] ints = (int[]) data[1];
+
+                list.add(new Object[]{"array:" +
+                                      name, TestData.Factory.ofArray("array:" + name, ints)});
+
+                SpinedBuffer.OfInt isl = new SpinedBuffer.OfInt();
+                for (int i : ints) {
+                    isl.accept(i);
+                }
+                list.add(new Object[]{"SpinedList:" + name,
+                         TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+
+                list.add(streamDataDescr("IntStream.intRange(0,l): " + ints.length,
+                                         () -> IntStream.range(0, ints.length)));
+                list.add(streamDataDescr("IntStream.rangeClosed(0,l): " + ints.length,
+                                         () -> IntStream.rangeClosed(0, ints.length)));
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final int[] ints = (int[]) data[1];
+
+                SpinedBuffer.OfInt isl = new SpinedBuffer.OfInt();
+                for (int i : ints) {
+                    isl.accept(i);
+                }
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(ints)));
+                spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(ints, 0, ints.length / 2)));
+
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> isl.spliterator()));
+
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(isl.iterator(), ints.length, 0)));
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+
+                spliterators.add(splitDescr("IntStream.intRange(0,l):" + name,
+                                            () -> IntStream.range(0, ints.length).spliterator()));
+                spliterators.add(splitDescr("IntStream.intRangeClosed(0,l):" + name,
+                                            () -> IntStream.rangeClosed(0, ints.length).spliterator()));
+                // Need more!
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+
+    }
+
+    static <T> Object[] streamDataDescr(String description, Supplier<IntStream> s) {
+        return new Object[] { description, TestData.Factory.ofIntSupplier(description, s) };
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfInt> s) {
+        return new Object[] { description, s };
+    }
+
+    // Return an array of ( String name, IntStreamTestData )
+    @DataProvider(name = "IntStreamTestData")
+    public static Object[][] makeIntStreamTestData() {
+        return testData;
+    }
+
+    // returns an array of (String name, Supplier<PrimitiveSpliterator<Integer>>)
+    @DataProvider(name = "IntSpliterator")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
diff --git a/java/util/stream/IntStreamTestScenario.java b/java/util/stream/IntStreamTestScenario.java
new file mode 100644
index 0000000..9a3cc44
--- /dev/null
+++ b/java/util/stream/IntStreamTestScenario.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.PrimitiveIterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+
+/**
+ * Test scenarios for int streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum IntStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            IntStream s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+            s.close();
+        }
+    },
+
+    STREAM_TO_ARRAY(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (int t : m.apply(data.stream()).toArray()) {
+                b.accept(t);
+            }
+        }
+    },
+
+    STREAM_ITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (PrimitiveIterator.OfInt seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.nextInt());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (Spliterator.OfInt spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (Spliterator.OfInt spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (int t : m.apply(data.parallelStream()).toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            IntStream s = m.apply(data.parallelStream());
+            Spliterator.OfInt sp = s.spliterator();
+            IntStream ss = StreamSupport.intStream(() -> sp,
+                                                   StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                   | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED),
+                                                   true);
+            for (int t : ss.toArray())
+                b.accept(t);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            IntStream pipe2 = m.apply(pipe1);
+
+            for (int t : pipe2.toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing
+    PAR_STREAM_FOR_EACH(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            m.apply(data.parallelStream()).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+    PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            m.apply(pipe1).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+    ;
+
+    // The set of scenarios that clean the SIZED flag
+    public static final Set<IntStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+            EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+    private final boolean isParallel;
+
+    private final boolean isOrdered;
+
+    IntStreamTestScenario(boolean isParallel) {
+        this(isParallel, true);
+    }
+
+    IntStreamTestScenario(boolean isParallel, boolean isOrdered) {
+        this.isParallel = isParallel;
+        this.isOrdered = isOrdered;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.INT_VALUE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public boolean isOrdered() {
+        return isOrdered;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, (IntConsumer) b, (Function<S_IN, IntStream>) m);
+    }
+
+    abstract <T, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m);
+
+}
diff --git a/java/util/stream/IntermediateTestOp.java b/java/util/stream/IntermediateTestOp.java
new file mode 100644
index 0000000..1ed04c7
--- /dev/null
+++ b/java/util/stream/IntermediateTestOp.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * A base type for test operations
+ */
+interface IntermediateTestOp<E_IN, E_OUT> {
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+                                            IntermediateTestOp<?, T> op) {
+        if (op instanceof StatelessTestOp)
+            return StatelessTestOp.chain(upstream, (StatelessTestOp) op);
+
+        if (op instanceof StatefulTestOp)
+            return StatefulTestOp.chain(upstream, (StatefulTestOp) op);
+
+        throw new IllegalStateException("Unknown test op type: " + op.getClass().getName());
+    }
+}
diff --git a/java/util/stream/LambdaTestHelpers.java b/java/util/stream/LambdaTestHelpers.java
new file mode 100644
index 0000000..76a4d72
--- /dev/null
+++ b/java/util/stream/LambdaTestHelpers.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoublePredicate;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongPredicate;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * LambdaTestHelpers -- assertion methods and useful objects for lambda test cases
+ */
+public class LambdaTestHelpers {
+    public static final String LONG_STRING = "When in the Course of human events it becomes necessary for one people to dissolve the political bands which have connected them with another and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.";
+
+    @SuppressWarnings("rawtypes")
+    public static final Consumer bEmpty = x -> {  };
+    @SuppressWarnings("rawtypes")
+    public static final IntConsumer bIntEmpty = x -> {  };
+    @SuppressWarnings("rawtypes")
+    public static final BiConsumer bBiEmpty = (x,y) -> { };
+    @SuppressWarnings("rawtypes")
+    public static final Consumer bHashCode = x -> { Objects.hashCode(x); };
+    @SuppressWarnings("rawtypes")
+    public static final BiConsumer bBiHashCode = (x,y) -> { Objects.hash(x, y); };
+    public static final Function<Integer, Integer> mZero = x -> 0;
+    public static final Function<Integer, Integer> mId = x -> x;
+    public static final Function<Integer, Integer> mDoubler = x -> x * 2;
+    public static final Function<Integer, Stream<Integer>> mfId = e -> Collections.singletonList(e).stream();
+    public static final Function<Integer, Stream<Integer>> mfNull = e -> Collections.<Integer>emptyList().stream();
+    public static final Function<Integer, Stream<Integer>> mfLt = e -> {
+        List<Integer> l = new ArrayList<>();
+        for (int i=0; i<e; i++)
+            l.add(i);
+        return l.stream();
+    };
+    public static final ToIntFunction<Integer> imDoubler = x -> x * 2;
+    public static final ToLongFunction<Long> lmDoubler = x -> x * 2;
+    public static final ToDoubleFunction<Double> dmDoubler = x -> x * 2;
+    public static final Predicate<Integer> pFalse = x -> false;
+    public static final Predicate<Integer> pTrue = x -> true;
+    public static final Predicate<Integer> pEven = x -> 0 == x % 2;
+    public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
+    public static final IntPredicate ipFalse = x -> false;
+    public static final IntPredicate ipTrue = x -> true;
+    public static final IntPredicate ipEven = x -> 0 == x % 2;
+    public static final IntPredicate ipOdd = x -> 1 == x % 2;
+    public static final LongPredicate lpFalse = x -> false;
+    public static final LongPredicate lpTrue = x -> true;
+    public static final LongPredicate lpEven = x -> 0 == x % 2;
+    public static final LongPredicate lpOdd = x -> 1 == x % 2;
+    public static final DoublePredicate dpFalse = x -> false;
+    public static final DoublePredicate dpTrue = x -> true;
+    public static final DoublePredicate dpEven = x -> 0 == ((long) x) % 2;
+    public static final DoublePredicate dpOdd = x -> 1 == ((long) x) % 2;
+    public static final BinaryOperator<Integer> rPlus = (x, y) -> x+y;
+    public static final BinaryOperator<Integer> rMax = (x, y) -> Math.max(x, y);
+    public static final BinaryOperator<Integer> rMin = (x, y) -> Math.min(x,y);
+    public static final IntBinaryOperator irPlus = (x, y) -> x+y;
+    public static final IntBinaryOperator irMax = (x, y) -> Math.max(x, y);
+    public static final IntBinaryOperator irMin = (x, y) -> Math.min(x,y);
+    public static final IntUnaryOperator irDoubler = x -> x * 2;
+    public static final LongBinaryOperator lrPlus = (x, y) -> x+y;
+    public static final DoubleBinaryOperator drPlus = (x, y) -> x+y;
+    public static final Comparator<Integer> cInteger = (a, b) -> Integer.compare(a, b);
+    public static final BiPredicate<?, ?> bipFalse = (x, y) -> false;
+    public static final BiPredicate<?, ?> bipTrue = (x, y) -> true;
+    public static final BiPredicate<Integer, Integer> bipBothEven = (x, y) -> 0 == (x % 2 + y % 2);
+    public static final BiPredicate<Integer, Integer> bipBothOdd = (x, y) -> 2 == (x % 2 + y % 2);
+    public static final BiPredicate<?, ?> bipSameString = (x, y) -> String.valueOf(x).equals(String.valueOf(y));
+
+    public static final IntFunction<Integer[]> integerArrayGenerator = s -> new Integer[s];
+
+    public static final IntFunction<Object[]> objectArrayGenerator = s -> new Object[s];
+
+    public static final Function<String, Stream<Character>> flattenChars = string -> {
+        List<Character> l = new ArrayList<>();
+        for (int i=0; i<string.length(); i++)
+            l.add(string.charAt(i));
+        return l.stream();
+    };
+
+    public static final Function<String, IntStream> flattenInt
+            = string -> IntStream.range(0, string.length()).map(string::charAt);
+
+    public static <T, R> Function<T, R> forPredicate(Predicate<? super T> predicate, R forTrue, R forFalse) {
+        Objects.requireNonNull(predicate);
+
+        return t -> predicate.test(t) ? forTrue : forFalse;
+    }
+
+    public static <T> Function<T, T> identity() {
+        return t -> t;
+    }
+
+    public static<V, T, R> Function<V, R> compose(Function<? super T, ? extends R> after, Function<? super V, ? extends T> before) {
+        Objects.requireNonNull(before);
+        return (V v) -> after.apply(before.apply(v));
+    }
+
+    public static List<Integer> empty() {
+        ArrayList<Integer> list = new ArrayList<>();
+        list.add(null);
+        return list;
+    }
+
+    public static List<Integer> countTo(int n) {
+        return range(1, n);
+    }
+
+    public static List<Integer> range(int l, int u) {
+        ArrayList<Integer> list = new ArrayList<>(u - l + 1);
+        for (int i=l; i<=u; i++) {
+            list.add(i);
+        }
+        return list;
+    }
+
+    public static List<Integer> repeat(int value, int n) {
+        ArrayList<Integer> list = new ArrayList<>(n);
+        for (int i=1; i<=n; i++) {
+            list.add(value);
+        }
+        return list;
+    }
+
+    public static List<Double> asDoubles(List<Integer> integers) {
+        ArrayList<Double> list = new ArrayList<>();
+        for (Integer i : integers) {
+            list.add((double) i);
+        }
+        return list;
+    }
+
+    public static List<Long> asLongs(List<Integer> integers) {
+        ArrayList<Long> list = new ArrayList<>();
+        for (Integer i : integers) {
+            list.add((long) i);
+        }
+        return list;
+    }
+
+    public static void assertCountSum(Stream<? super Integer> it, int count, int sum) {
+        assertCountSum(it.iterator(), count, sum);
+    }
+
+    public static void assertCountSum(Iterable<? super Integer> it, int count, int sum) {
+        assertCountSum(it.iterator(), count, sum);
+    }
+
+    public static void assertCountSum(Iterator<? super Integer> it, int count, int sum) {
+        int c = 0;
+        int s = 0;
+        while (it.hasNext()) {
+            int i = (Integer) it.next();
+            c++;
+            s += i;
+        }
+
+        assertEquals(c, count);
+        assertEquals(s, sum);
+    }
+
+    public static void assertConcat(Iterator<Character> it, String result) {
+        StringBuilder sb = new StringBuilder();
+        while (it.hasNext()) {
+            sb.append(it.next());
+        }
+
+        assertEquals(result, sb.toString());
+    }
+
+    public static<T extends Comparable<? super T>> void assertSorted(Iterator<T> i) {
+        i = toBoxedList(i).iterator();
+
+        if (!i.hasNext())
+            return;
+        T last = i.next();
+        while (i.hasNext()) {
+            T t = i.next();
+            assertTrue(last.compareTo(t) <= 0);
+            assertTrue(t.compareTo(last) >= 0);
+            last = t;
+        }
+    }
+
+    public static<T> void assertSorted(Iterator<T> i, Comparator<? super T> comp) {
+        if (i instanceof PrimitiveIterator.OfInt
+                || i instanceof PrimitiveIterator.OfDouble
+                || i instanceof PrimitiveIterator.OfLong) {
+            i = toBoxedList(i).iterator();
+        }
+
+        if (!i.hasNext())
+            return;
+        T last = i.next();
+        while (i.hasNext()) {
+            T t = i.next();
+            assertTrue(comp.compare(last, t) <= 0);
+            assertTrue(comp.compare(t, last) >= 0);
+            last = t;
+        }
+    }
+
+    public static<T extends Comparable<? super T>> void assertSorted(Iterable<T> iter) {
+        assertSorted(iter.iterator());
+    }
+
+    public static<T> void assertSorted(Iterable<T> iter, Comparator<? super T> comp) {
+        assertSorted(iter.iterator(), comp);
+    }
+
+    public static <T> void assertUnique(Iterable<T> iter) {
+        assertUnique(iter.iterator());
+    }
+
+    public static<T> void assertUnique(Iterator<T> iter) {
+        if (!iter.hasNext()) {
+            return;
+        }
+
+        if (iter instanceof PrimitiveIterator.OfInt
+            || iter instanceof PrimitiveIterator.OfDouble
+            || iter instanceof PrimitiveIterator.OfLong) {
+            iter = toBoxedList(iter).iterator();
+        }
+
+        Set<T> uniq = new HashSet<>();
+        while(iter.hasNext()) {
+            T each = iter.next();
+            assertTrue(!uniq.contains(each), "Not unique");
+            uniq.add(each);
+        }
+    }
+
+    public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected) {
+        if (actual instanceof Collection && expected instanceof Collection) {
+            assertEquals(actual, expected);
+        } else {
+            assertContents(actual.iterator(), expected.iterator());
+        }
+    }
+
+    public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected) {
+        assertEquals(toBoxedList(actual), toBoxedList(expected));
+    }
+
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    public static<T> void assertContents(Iterator<T> actual, T... expected) {
+        assertContents(actual, Arrays.asList(expected).iterator());
+    }
+
+    /**
+     * The all consuming consumer (rampant capitalist) that can accepting a reference or any primitive value.
+     */
+    private static interface OmnivorousConsumer<T>
+            extends Consumer<T>, IntConsumer, LongConsumer, DoubleConsumer { }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> Consumer<T> toBoxingConsumer(Consumer<? super T> c) {
+        return (Consumer<T>) new OmnivorousConsumer() {
+            @Override
+            public void accept(Object t) {
+                c.accept((T) t);
+            }
+
+            @Override
+            public void accept(int t) {
+                accept((Object) t);
+            }
+
+            @Override
+            public void accept(long t) {
+                accept((Object) t);
+            }
+
+            @Override
+            public void accept(double t) {
+                accept((Object) t);
+            }
+        };
+    }
+
+    /**
+     * Convert an iterator to a list using forEach with an implementation of
+     * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+     *
+     * This ensures equality comparisons for test results do not trip
+     * the boxing trip-wires.
+     */
+    private static<T> List<T> toBoxedList(Iterator<T> it) {
+        List<T> l = new ArrayList<>();
+        it.forEachRemaining(toBoxingConsumer(l::add));
+        return l;
+    }
+
+    /**
+     * Convert a spliterator to a list using forEach with an implementation of
+     * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+     *
+     * This ensures equality comparisons for test results do not trip
+     * the boxing trip-wires.
+     */
+    public static<T> List<T> toBoxedList(Spliterator<T> sp) {
+        List<T> l = new ArrayList<>();
+        sp.forEachRemaining(toBoxingConsumer(l::add));
+        return l;
+    }
+
+    /**
+     * Convert an iterator to a multi-set, represented as a Map, using forEach with an implementation of
+     * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+     *
+     * This ensures equality comparisons for test results do not trip
+     * the boxing trip-wires.
+     */
+    @SuppressWarnings("unchecked")
+    private static<T> Map<T, Integer> toBoxedMultiset(Iterator<T> it) {
+        Map<Object, Integer> result = new HashMap<>();
+
+        it.forEachRemaining(toBoxingConsumer(o -> {
+                if (result.containsKey(o))
+                    result.put(o, result.get(o) + 1);
+                else
+                    result.put(o, 1);
+            }));
+
+        return (Map<T, Integer>) result;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static<T> Map<T, Integer> toBoxedMultiset(Spliterator<T> it) {
+        Map<Object, Integer> result = new HashMap<>();
+
+        it.forEachRemaining(toBoxingConsumer(o -> {
+                if (result.containsKey(o))
+                    result.put(o, result.get(o) + 1);
+                else
+                    result.put(o, 1);
+            }));
+
+        return (Map<T, Integer>) result;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static void assertContentsEqual(Object a, Object b) {
+        if (a instanceof Iterable && b instanceof Iterable)
+            assertContents((Iterable) a, (Iterable) b);
+        else
+            assertEquals(a, b);
+    }
+
+    public static<T> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
+        assertContentsUnordered(actual.iterator(), expected.iterator());
+    }
+
+    public static<T> void assertContentsUnordered(Iterator<T> actual, Iterator<T> expected) {
+        assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected));
+    }
+
+    public static void launderAssertion(Runnable r, Supplier<String> additionalInfo) {
+        try {
+            r.run();
+        }
+        catch (AssertionError ae) {
+            AssertionError cloned = new AssertionError(ae.getMessage() + String.format("%n%s", additionalInfo.get()));
+            cloned.setStackTrace(ae.getStackTrace());
+            if (ae.getCause() != null)
+                cloned.initCause(ae.getCause());
+            throw cloned;
+        }
+    }
+
+    public static <T, S extends BaseStream<T, S>>
+    List<Function<S, S>> permuteStreamFunctions(List<Function<S, S>> opFunctions) {
+        List<List<Function<S, S>>> opFunctionPermutations = perm(opFunctions);
+
+        List<Function<S, S>> appliedFunctions = new ArrayList<>();
+        for (List<Function<S, S>> fs : opFunctionPermutations) {
+            Function<S, S> applied = s -> {
+                for (Function<S, S> f : fs) {
+                    s = f.apply(s);
+                }
+                return s;
+            };
+            appliedFunctions.add(applied);
+        }
+
+        return appliedFunctions;
+    }
+
+    private static <T> List<T> sub(List<T> l, int index) {
+        List<T> subL = new ArrayList<>(l);
+        subL.remove(index);
+        return subL;
+    }
+
+    public static <T> List<List<T>> perm(List<T> l) {
+        List<List<T>> result = new ArrayList<>();
+        for (int i = 0; i < l.size(); i++) {
+            for (List<T> perm : perm(sub(l, i))) {
+                perm.add(0, l.get(i));
+                result.add(perm);
+            }
+        }
+        result.add(new ArrayList<T>());
+
+        return result;
+    }
+
+    public static String flagsToString(int flags) {
+        StringJoiner sj = new StringJoiner(", ", "StreamOpFlag[", "]");
+        if (StreamOpFlag.DISTINCT.isKnown(flags)) sj.add("IS_DISTINCT");
+        if (StreamOpFlag.ORDERED.isKnown(flags)) sj.add("IS_ORDERED");
+        if (StreamOpFlag.SIZED.isKnown(flags)) sj.add("IS_SIZED");
+        if (StreamOpFlag.SORTED.isKnown(flags)) sj.add("IS_SORTED");
+        if (StreamOpFlag.SHORT_CIRCUIT.isKnown(flags)) sj.add("IS_SHORT_CIRCUIT");
+        return sj.toString();
+    }
+}
diff --git a/java/util/stream/LambdaTestMode.java b/java/util/stream/LambdaTestMode.java
new file mode 100644
index 0000000..b598964
--- /dev/null
+++ b/java/util/stream/LambdaTestMode.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * Runtime modes of test execution.
+ */
+public enum LambdaTestMode {
+    /**
+     * Execution mode with no particular runtime constraints.
+     */
+    NORMAL,
+
+    /**
+     * Execution mode where tests are executed for testing lambda serialization
+     * and deserialization.
+     *
+     * <p>This mode may be queried by tests or data supplied by data
+     * providers, which cannot otherwise be assigned to the test group
+     * <em>serialization-hostile</em>, to not execute or declare
+     * serialization-hostile code or data.
+     *
+     * <p>This mode is enabled if the boolean system property
+     * {@code org.openjdk.java.util.stream.sand.mode} is declared with a
+     * {@code true} value.
+     */
+    SERIALIZATION;
+
+    /**
+     * {@code true} if tests are executed in the mode for testing lambda
+     * Serialization ANd Deserialization (SAND).
+     */
+    private static final boolean IS_LAMBDA_SERIALIZATION_MODE =
+            Boolean.getBoolean("org.openjdk.java.util.stream.sand.mode");
+
+    /**
+     *
+     * @return the mode of test execution.
+     */
+    public static LambdaTestMode getMode() {
+        return IS_LAMBDA_SERIALIZATION_MODE ? SERIALIZATION : NORMAL;
+    }
+
+    /**
+     *
+     * @return {@code true} if normal test mode.
+     */
+    public static boolean isNormalMode() {
+        return getMode() == NORMAL;
+    }
+}
diff --git a/java/util/stream/LoggingTestCase.java b/java/util/stream/LoggingTestCase.java
new file mode 100644
index 0000000..a0f2219
--- /dev/null
+++ b/java/util/stream/LoggingTestCase.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.Assert;
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * LoggingTestCase
+ *
+ */
+@Test
+public class LoggingTestCase extends Assert {
+    private Map<String, Object> context = new HashMap<>();
+
+    @BeforeMethod
+    public void before() {
+        context.clear();
+    }
+
+    @AfterMethod
+    public void after(ITestResult result) {
+        if (!result.isSuccess()) {
+            List<Object> list = new ArrayList<>();
+            Collections.addAll(list, result.getParameters());
+            list.add(context.toString());
+            result.setParameters(list.toArray(new Object[list.size()]));
+        }
+    }
+
+    protected void setContext(String key, Object value) {
+        context.put(key, value);
+    }
+
+    protected void clearContext(String key) {
+        context.remove(key);
+    }
+}
diff --git a/java/util/stream/LongNodeTest.java b/java/util/stream/LongNodeTest.java
new file mode 100644
index 0000000..d266fd7
--- /dev/null
+++ b/java/util/stream/LongNodeTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class LongNodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            long[] array = new long[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Long>> nodes = new ArrayList<>();
+
+            nodes.add(Nodes.node(array));
+            nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
+            nodes.add(tree(toList(array), l -> Nodes.node(toLongArray(l))));
+            nodes.add(fill(array, Nodes.longBuilder(array.length)));
+            nodes.add(fill(array, Nodes.longBuilder()));
+
+            for (Node<Long> node : nodes) {
+                params.add(new Object[]{array, node});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    private static void assertEqualsListLongArray(List<Long> list, long[] array) {
+        assertEquals(list.size(), array.length);
+        for (int i = 0; i < array.length; i++)
+            assertEquals(array[i], (long) list.get(i));
+    }
+
+    private List<Long> toList(long[] a) {
+        List<Long> l = new ArrayList<>();
+        for (long i : a) {
+            l.add(i);
+        }
+
+        return l;
+    }
+
+    private long[] toLongArray(List<Long> l) {
+        long[] a = new long[l.size()];
+
+        int i = 0;
+        for (Long e : l) {
+            a[i++] = e;
+        }
+        return a;
+    }
+
+    private Node.OfLong fill(long[] array, Node.Builder.OfLong nb) {
+        nb.begin(array.length);
+        for (long i : array)
+            nb.accept(i);
+        nb.end();
+        return nb.build();
+    }
+
+    private Node.OfLong degenerateTree(PrimitiveIterator.OfLong it) {
+        if (!it.hasNext()) {
+            return Nodes.node(new long[0]);
+        }
+
+        long i = it.nextLong();
+        if (it.hasNext()) {
+            return new Nodes.ConcNode.OfLong(Nodes.node(new long[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new long[] {i});
+        }
+    }
+
+    private Node.OfLong tree(List<Long> l, Function<List<Long>, Node.OfLong> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.ConcNode.OfLong(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(long[] array, Node.OfLong n) {
+        assertEquals(n.asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(long[] array, Node.OfLong n) {
+        assertEquals(Nodes.flattenLong(n).asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(long[] array, Node.OfLong n) {
+        long[] copy = new long[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(long[] array, Node.OfLong n) {
+        List<Long> l = new ArrayList<>((int) n.count());
+        n.forEach((long e) -> {
+            l.add(e);
+        });
+
+        assertEqualsListLongArray(l, array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(long[] array, Node.OfLong n) {
+        TestData.OfLong data = TestData.Factory.ofNode("Node", n);
+
+        exerciseOps(data, s -> s);
+
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testSpliterator(long[] array, Node.OfLong n) {
+        SpliteratorTestHelper.testLongSpliterator(n::spliterator);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testTruncate(long[] array, Node.OfLong n) {
+        int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+        for (int start : nums)
+            for (int end : nums) {
+                if (start < 0 || end < 0 || end < start || end > array.length)
+                    continue;
+                Node.OfLong slice = n.truncate(start, end, Long[]::new);
+                long[] asArray = slice.asPrimitiveArray();
+                for (int k = start; k < end; k++)
+                    assertEquals(array[k], asArray[k - start]);
+            }
+    }
+}
diff --git a/java/util/stream/LongPipeline.java b/java/util/stream/LongPipeline.java
new file mode 100644
index 0000000..768a378
--- /dev/null
+++ b/java/util/stream/LongPipeline.java
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.LongSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalLong;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.IntFunction;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongFunction;
+import java.util.function.LongPredicate;
+import java.util.function.LongToDoubleFunction;
+import java.util.function.LongToIntFunction;
+import java.util.function.LongUnaryOperator;
+import java.util.function.ObjLongConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code long}.
+ *
+ * @param <E_IN> type of elements in the upstream source
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class LongPipeline<E_IN>
+        extends AbstractPipeline<E_IN, Long, LongStream>
+        implements LongStream {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    LongPipeline(Supplier<? extends Spliterator<Long>> source,
+                 int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    LongPipeline(Spliterator<Long> source,
+                 int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing pipeline.
+     *
+     * @param upstream the upstream element source.
+     * @param opFlags the operation flags
+     */
+    LongPipeline(AbstractPipeline<?, E_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    /**
+     * Adapt a {@code Sink<Long> to an {@code LongConsumer}, ideally simply
+     * by casting.
+     */
+    private static LongConsumer adapt(Sink<Long> sink) {
+        if (sink instanceof LongConsumer) {
+            return (LongConsumer) sink;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using LongStream.adapt(Sink<Long> s)");
+            return sink::accept;
+        }
+    }
+
+    /**
+     * Adapt a {@code Spliterator<Long>} to a {@code Spliterator.OfLong}.
+     *
+     * @implNote
+     * The implementation attempts to cast to a Spliterator.OfLong, and throws
+     * an exception if this cast is not possible.
+     */
+    private static Spliterator.OfLong adapt(Spliterator<Long> s) {
+        if (s instanceof Spliterator.OfLong) {
+            return (Spliterator.OfLong) s;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using LongStream.adapt(Spliterator<Long> s)");
+            throw new UnsupportedOperationException("LongStream.adapt(Spliterator<Long> s)");
+        }
+    }
+
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.LONG_VALUE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<Long> evaluateToNode(PipelineHelper<Long> helper,
+                                           Spliterator<P_IN> spliterator,
+                                           boolean flattenTree,
+                                           IntFunction<Long[]> generator) {
+        return Nodes.collectLong(helper, spliterator, flattenTree);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<Long> wrap(PipelineHelper<Long> ph,
+                                        Supplier<Spliterator<P_IN>> supplier,
+                                        boolean isParallel) {
+        return new StreamSpliterators.LongWrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator.OfLong lazySpliterator(Supplier<? extends Spliterator<Long>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator.OfLong((Supplier<Spliterator.OfLong>) supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final void forEachWithCancel(Spliterator<Long> spliterator, Sink<Long> sink) {
+        Spliterator.OfLong spl = adapt(spliterator);
+        LongConsumer adaptedSink =  adapt(sink);
+        do { } while (!sink.cancellationRequested() && spl.tryAdvance(adaptedSink));
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<Long> makeNodeBuilder(long exactSizeIfKnown, IntFunction<Long[]> generator) {
+        return Nodes.longBuilder(exactSizeIfKnown);
+    }
+
+
+    // LongStream
+
+    @Override
+    public final PrimitiveIterator.OfLong iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public final Spliterator.OfLong spliterator() {
+        return adapt(super.spliterator());
+    }
+
+    // Stateless intermediate ops from LongStream
+
+    @Override
+    public final DoubleStream asDoubleStream() {
+        return new DoublePipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                                    StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedLong<Double>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept((double) t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final Stream<Long> boxed() {
+        return mapToObj(Long::valueOf);
+    }
+
+    @Override
+    public final LongStream map(LongUnaryOperator mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.applyAsLong(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <U> Stream<U> mapToObj(LongFunction<? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        return new ReferencePipeline.StatelessOp<Long, U>(this, StreamShape.LONG_VALUE,
+                                                          StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedLong<U>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream mapToInt(LongToIntFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new IntPipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                                 StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedLong<Integer>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.applyAsInt(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream mapToDouble(LongToDoubleFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new DoublePipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                                    StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedLong<Double>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.applyAsDouble(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream flatMap(LongFunction<? extends LongStream> mapper) {
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(long t) {
+                        try (LongStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public LongStream unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final LongStream filter(LongPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(long t) {
+                        if (predicate.test(t))
+                            downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream peek(LongConsumer action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        action.accept(t);
+                        downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate ops from LongStream
+
+    @Override
+    public final LongStream limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeLong(this, 0, maxSize);
+    }
+
+    @Override
+    public final LongStream skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else
+            return SliceOps.makeLong(this, n, -1);
+    }
+
+    @Override
+    public final LongStream sorted() {
+        return SortedOps.makeLong(this);
+    }
+
+    @Override
+    public final LongStream distinct() {
+        // While functional and quick to implement, this approach is not very efficient.
+        // An efficient version requires a long-specific map/set implementation.
+        return boxed().distinct().mapToLong(i -> (long) i);
+    }
+
+    // Terminal ops from LongStream
+
+    @Override
+    public void forEach(LongConsumer action) {
+        evaluate(ForEachOps.makeLong(action, false));
+    }
+
+    @Override
+    public void forEachOrdered(LongConsumer action) {
+        evaluate(ForEachOps.makeLong(action, true));
+    }
+
+    @Override
+    public final long sum() {
+        // use better algorithm to compensate for intermediate overflow?
+        return reduce(0, Long::sum);
+    }
+
+    @Override
+    public final OptionalLong min() {
+        return reduce(Math::min);
+    }
+
+    @Override
+    public final OptionalLong max() {
+        return reduce(Math::max);
+    }
+
+    @Override
+    public final OptionalDouble average() {
+        long[] avg = collect(() -> new long[2],
+                             (ll, i) -> {
+                                 ll[0]++;
+                                 ll[1] += i;
+                             },
+                             (ll, rr) -> {
+                                 ll[0] += rr[0];
+                                 ll[1] += rr[1];
+                             });
+        return avg[0] > 0
+               ? OptionalDouble.of((double) avg[1] / avg[0])
+               : OptionalDouble.empty();
+    }
+
+    @Override
+    public final long count() {
+        return map(e -> 1L).sum();
+    }
+
+    @Override
+    public final LongSummaryStatistics summaryStatistics() {
+        return collect(LongSummaryStatistics::new, LongSummaryStatistics::accept,
+                       LongSummaryStatistics::combine);
+    }
+
+    @Override
+    public final long reduce(long identity, LongBinaryOperator op) {
+        return evaluate(ReduceOps.makeLong(identity, op));
+    }
+
+    @Override
+    public final OptionalLong reduce(LongBinaryOperator op) {
+        return evaluate(ReduceOps.makeLong(op));
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               ObjLongConsumer<R> accumulator,
+                               BiConsumer<R, R> combiner) {
+        BinaryOperator<R> operator = (left, right) -> {
+            combiner.accept(left, right);
+            return left;
+        };
+        return evaluate(ReduceOps.makeLong(supplier, accumulator, operator));
+    }
+
+    @Override
+    public final boolean anyMatch(LongPredicate predicate) {
+        return evaluate(MatchOps.makeLong(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(LongPredicate predicate) {
+        return evaluate(MatchOps.makeLong(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(LongPredicate predicate) {
+        return evaluate(MatchOps.makeLong(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final OptionalLong findFirst() {
+        return evaluate(FindOps.makeLong(true));
+    }
+
+    @Override
+    public final OptionalLong findAny() {
+        return evaluate(FindOps.makeLong(false));
+    }
+
+    @Override
+    public final long[] toArray() {
+        return Nodes.flattenLong((Node.OfLong) evaluateToArrayNode(Long[]::new))
+                .asPrimitiveArray();
+    }
+
+
+    //
+
+    /**
+     * Source stage of a LongPipeline.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Made public for CTS tests only (OpenJDK 8 streams tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN> extends LongPipeline<E_IN> {
+        /**
+         * Constructor for the source stage of a LongStream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<Long>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of a LongStream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<Long> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<Long> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(LongConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            } else {
+                super.forEach(action);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(LongConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            } else {
+                super.forEachOrdered(action);
+            }
+        }
+    }
+
+    /** Base class for a stateless intermediate stage of a LongStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN> extends LongPipeline<E_IN> {
+        /**
+         * Construct a new LongStream by appending a stateless intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of a LongStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN> extends LongPipeline<E_IN> {
+        /**
+         * Construct a new LongStream by appending a stateful intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         * @hide Visible for CTS testing only (OpenJDK8 tests).
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      IntFunction<Long[]> generator);
+    }
+}
diff --git a/java/util/stream/LongStream.java b/java/util/stream/LongStream.java
new file mode 100644
index 0000000..a2d429e
--- /dev/null
+++ b/java/util/stream/LongStream.java
@@ -0,0 +1,920 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LongSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalLong;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongFunction;
+import java.util.function.LongPredicate;
+import java.util.function.LongSupplier;
+import java.util.function.LongToDoubleFunction;
+import java.util.function.LongToIntFunction;
+import java.util.function.LongUnaryOperator;
+import java.util.function.ObjLongConsumer;
+import java.util.function.Supplier;
+
+/**
+ * A sequence of primitive long-valued elements supporting sequential and parallel
+ * aggregate operations.  This is the {@code long} primitive specialization of
+ * {@link Stream}.
+ *
+ * <p>The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link LongStream}, computing the sum of the weights of the
+ * red widgets:
+ *
+ * <pre>{@code
+ *     long sum = widgets.stream()
+ *                       .filter(w -> w.getColor() == RED)
+ *                       .mapToLong(w -> w.getWeight())
+ *                       .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism.
+ *
+ * @since 1.8
+ * @see Stream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface LongStream extends BaseStream<Long, LongStream> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    LongStream filter(LongPredicate predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream map(LongUnaryOperator mapper);
+
+    /**
+     * Returns an object-valued {@code Stream} consisting of the results of
+     * applying the given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param <U> the element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <U> Stream<U> mapToObj(LongFunction<? extends U> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream mapToInt(LongToIntFunction mapper);
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream mapToDouble(LongToDoubleFunction mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a
+     *               {@code LongStream} of new values
+     * @return the new stream
+     * @see Stream#flatMap(Function)
+     */
+    LongStream flatMap(LongFunction<? extends LongStream> mapper);
+
+    /**
+     * Returns a stream consisting of the distinct elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    LongStream distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream in sorted
+     * order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    LongStream sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     LongStream.of(1, 2, 3, 4)
+     *         .filter(e -> e > 2)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(e -> e * e)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .sum();
+     * }</pre>
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements as
+     *               they are consumed from the stream
+     * @return the new stream
+     */
+    LongStream peek(LongConsumer action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(LongSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    LongStream limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(LongSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    LongStream skip(long n);
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(LongConsumer action);
+
+    /**
+     * Performs an action for each element of this stream, guaranteeing that
+     * each element is processed in encounter order for streams that have a
+     * defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(LongConsumer)
+     */
+    void forEachOrdered(LongConsumer action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array containing the elements of this stream
+     */
+    long[] toArray();
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     long result = identity;
+     *     for (long element : this stream)
+     *         result = accumulator.applyAsLong(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code x},
+     * {@code accumulator.apply(identity, x)} is equal to {@code x}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min, max, and average are all special cases of reduction.
+     * Summing a stream of numbers can be expressed as:
+     *
+     * <pre>{@code
+     *     long sum = integers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or more compactly:
+     *
+     * <pre>{@code
+     *     long sum = integers.reduce(0, Long::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #sum()
+     * @see #min()
+     * @see #max()
+     * @see #average()
+     */
+    long reduce(long identity, LongBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code OptionalLong} describing the reduced value,
+     * if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     long result = null;
+     *     for (long element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.applyAsLong(result, element);
+     *     }
+     *     return foundAny ? OptionalLong.of(result) : OptionalLong.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #reduce(long, LongBinaryOperator)
+     */
+    OptionalLong reduce(LongBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (long element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(long, LongBinaryOperator)}, {@code collect} operations
+     * can be parallelized without requiring additional synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param <R> type of the result
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for incorporating an additional element into a result
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values, which must be
+     *                    compatible with the accumulator function
+     * @return the result of the reduction
+     * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
+     */
+    <R> R collect(Supplier<R> supplier,
+                  ObjLongConsumer<R> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Returns the sum of elements in this stream.  This is a special case
+     * of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(0, Long::sum);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return the sum of elements in this stream
+     */
+    long sum();
+
+    /**
+     * Returns an {@code OptionalLong} describing the minimum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Long::min);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return an {@code OptionalLong} containing the minimum element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty
+     */
+    OptionalLong min();
+
+    /**
+     * Returns an {@code OptionalLong} describing the maximum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Long::max);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalLong} containing the maximum element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty
+     */
+    OptionalLong max();
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return map(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
+     * this stream, or an empty optional if this stream is empty.  This is a
+     * special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the average element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble average();
+
+    /**
+     * Returns a {@code LongSummaryStatistics} describing various summary data
+     * about the elements of this stream.  This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return a {@code LongSummaryStatistics} describing various summary data
+     * about the elements of this stream
+     */
+    LongSummaryStatistics summaryStatistics();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(LongPredicate predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(LongPredicate predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(LongPredicate predicate);
+
+    /**
+     * Returns an {@link OptionalLong} describing the first element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty.  If the
+     * stream has no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code OptionalLong} describing the first element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty
+     */
+    OptionalLong findFirst();
+
+    /**
+     * Returns an {@link OptionalLong} describing some element of the stream, or
+     * an empty {@code OptionalLong} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code OptionalLong} describing some element of this stream,
+     * or an empty {@code OptionalLong} if the stream is empty
+     * @see #findFirst()
+     */
+    OptionalLong findAny();
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}
+     */
+    DoubleStream asDoubleStream();
+
+    /**
+     * Returns a {@code Stream} consisting of the elements of this stream,
+     * each boxed to a {@code Long}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code Stream} consistent of the elements of this stream,
+     * each boxed to {@code Long}
+     */
+    Stream<Long> boxed();
+
+    @Override
+    LongStream sequential();
+
+    @Override
+    LongStream parallel();
+
+    @Override
+    PrimitiveIterator.OfLong iterator();
+
+    @Override
+    Spliterator.OfLong spliterator();
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code LongStream}.
+     *
+     * @return a stream builder
+     */
+    public static Builder builder() {
+        return new Streams.LongStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code LongStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static LongStream empty() {
+        return StreamSupport.longStream(Spliterators.emptyLongSpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code LongStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static LongStream of(long t) {
+        return StreamSupport.longStream(new Streams.LongStreamBuilderImpl(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static LongStream of(long... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code LongStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code LongStream} will
+     * be the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code LongStream}
+     */
+    public static LongStream iterate(final long seed, final LongUnaryOperator f) {
+        Objects.requireNonNull(f);
+        final PrimitiveIterator.OfLong iterator = new PrimitiveIterator.OfLong() {
+            long t = seed;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public long nextLong() {
+                long v = t;
+                t = f.applyAsLong(t);
+                return v;
+            }
+        };
+        return StreamSupport.longStream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code LongSupplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param s the {@code LongSupplier} for generated elements
+     * @return a new infinite sequential unordered {@code LongStream}
+     */
+    public static LongStream generate(LongSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.longStream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfLong(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
+     * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (long i = startInclusive; i < endExclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @return a sequential {@code LongStream} for the range of {@code long}
+     *         elements
+     */
+    public static LongStream range(long startInclusive, final long endExclusive) {
+        if (startInclusive >= endExclusive) {
+            return empty();
+        } else if (endExclusive - startInclusive < 0) {
+            // Size of range > Long.MAX_VALUE
+            // Split the range in two and concatenate
+            // Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE) then
+            // the lower range, [Long.MIN_VALUE, 0) will be further split in two
+            long m = startInclusive + Long.divideUnsigned(endExclusive - startInclusive, 2) + 1;
+            return concat(range(startInclusive, m), range(m, endExclusive));
+        } else {
+            return StreamSupport.longStream(
+                    new Streams.RangeLongSpliterator(startInclusive, endExclusive, false), false);
+        }
+    }
+
+    /**
+     * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
+     * (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (long i = startInclusive; i <= endInclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endInclusive the inclusive upper bound
+     * @return a sequential {@code LongStream} for the range of {@code long}
+     *         elements
+     */
+    public static LongStream rangeClosed(long startInclusive, final long endInclusive) {
+        if (startInclusive > endInclusive) {
+            return empty();
+        } else if (endInclusive - startInclusive + 1 <= 0) {
+            // Size of range > Long.MAX_VALUE
+            // Split the range in two and concatenate
+            // Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE] then
+            // the lower range, [Long.MIN_VALUE, 0), and upper range,
+            // [0, Long.MAX_VALUE], will both be further split in two
+            long m = startInclusive + Long.divideUnsigned(endInclusive - startInclusive, 2) + 1;
+            return concat(range(startInclusive, m), rangeClosed(m, endInclusive));
+        } else {
+            return StreamSupport.longStream(
+                    new Streams.RangeLongSpliterator(startInclusive, endInclusive, true), false);
+        }
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowException}.
+     *
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static LongStream concat(LongStream a, LongStream b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        Spliterator.OfLong split = new Streams.ConcatSpliterator.OfLong(
+                a.spliterator(), b.spliterator());
+        LongStream stream = StreamSupport.longStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for a {@code LongStream}.
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase begins
+     * begins when the {@link #build()} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
+     * @see LongStream#builder()
+     * @since 1.8
+     */
+    public interface Builder extends LongConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(long t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default Builder add(long t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        LongStream build();
+    }
+}
diff --git a/java/util/stream/LongStreamTestDataProvider.java b/java/util/stream/LongStreamTestDataProvider.java
new file mode 100644
index 0000000..4ce7ae6
--- /dev/null
+++ b/java/util/stream/LongStreamTestDataProvider.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for long-valued streams */
+public class LongStreamTestDataProvider {
+    private static final long[] to0 = new long[0];
+    private static final long[] to1 = new long[1];
+    private static final long[] to10 = new long[10];
+    private static final long[] to100 = new long[100];
+    private static final long[] to1000 = new long[1000];
+    private static final long[] reversed = new long[100];
+    private static final long[] ones = new long[100];
+    private static final long[] twice = new long[200];
+    private static final long[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        long[][] arrays = {to0, to1, to10, to100, to1000};
+        for (long[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new long[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (long) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final long[] longs = (long[]) data[1];
+
+                list.add(new Object[]{"array:" + name,
+                        TestData.Factory.ofArray("array:" + name, longs)});
+
+                SpinedBuffer.OfLong isl = new SpinedBuffer.OfLong();
+                for (long i : longs) {
+                    isl.accept(i);
+                }
+                list.add(new Object[]{"SpinedList:" + name,
+                        TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+
+                list.add(streamDataDescr("LongStream.longRange(0,l): " + longs.length,
+                                         () -> LongStream.range(0, longs.length)));
+                list.add(streamDataDescr("LongStream.longRangeClosed(0,l): " + longs.length,
+                                         () -> LongStream.rangeClosed(0, longs.length)));
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final long[] longs = (long[]) data[1];
+
+                SpinedBuffer.OfLong isl = new SpinedBuffer.OfLong();
+                for (long i : longs) {
+                    isl.accept(i);
+                }
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(longs)));
+                spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(longs, 0, longs.length / 2)));
+
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> isl.spliterator()));
+
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(isl.iterator(), longs.length, 0)));
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+
+                spliterators.add(splitDescr("LongStream.longRange(0,l):" + name,
+                                            () -> LongStream.range(0, longs.length).spliterator()));
+                spliterators.add(splitDescr("LongStream.longRangeClosed(0,l):" + name,
+                                            () -> LongStream.rangeClosed(0, longs.length).spliterator()));
+                // Need more!
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+
+    }
+
+    static <T> Object[] streamDataDescr(String description, Supplier<LongStream> s) {
+        return new Object[] { description, TestData.Factory.ofLongSupplier(description, s) };
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfLong> s) {
+        return new Object[] { description, s };
+    }
+
+    // Return an array of ( String name, LongStreamTestData )
+    @DataProvider(name = "LongStreamTestData")
+    public static Object[][] makeLongStreamTestData() {
+        return testData;
+    }
+
+    // returns an array of (String name, Supplier<PrimitiveSpliterator<Long>>)
+    @DataProvider(name = "LongSpliterator")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
diff --git a/java/util/stream/LongStreamTestScenario.java b/java/util/stream/LongStreamTestScenario.java
new file mode 100644
index 0000000..6d3e104
--- /dev/null
+++ b/java/util/stream/LongStreamTestScenario.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.PrimitiveIterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.LongConsumer;
+
+/**
+ * Test scenarios for long streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum LongStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            LongStream s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+            s.close();
+        }
+    },
+
+    STREAM_TO_ARRAY(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (long t : m.apply(data.stream()).toArray()) {
+                b.accept(t);
+            }
+        }
+    },
+
+    STREAM_ITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (PrimitiveIterator.OfLong seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.nextLong());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (Spliterator.OfLong spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (Spliterator.OfLong spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (long t : m.apply(data.parallelStream()).toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            LongStream s = m.apply(data.parallelStream());
+            Spliterator.OfLong sp = s.spliterator();
+            LongStream ss = StreamSupport.longStream(() -> sp,
+                                                     StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                     | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
+            for (long t : ss.toArray())
+                b.accept(t);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            LongStream pipe2 = m.apply(pipe1);
+
+            for (long t : pipe2.toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing
+    PAR_STREAM_FOR_EACH(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            m.apply(data.parallelStream()).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+    PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            m.apply(pipe1).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+    ;
+
+    // The set of scenarios that clean the SIZED flag
+    public static final Set<LongStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+            EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+    private boolean isParallel;
+
+    private final boolean isOrdered;
+
+    LongStreamTestScenario(boolean isParallel) {
+        this(isParallel, true);
+    }
+
+    LongStreamTestScenario(boolean isParallel, boolean isOrdered) {
+        this.isParallel = isParallel;
+        this.isOrdered = isOrdered;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.LONG_VALUE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public boolean isOrdered() {
+        return isOrdered;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, (LongConsumer) b, (Function<S_IN, LongStream>) m);
+    }
+
+    abstract <T, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m);
+
+}
diff --git a/java/util/stream/MatchOps.java b/java/util/stream/MatchOps.java
new file mode 100644
index 0000000..cc809e4
--- /dev/null
+++ b/java/util/stream/MatchOps.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.DoublePredicate;
+import java.util.function.IntPredicate;
+import java.util.function.LongPredicate;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * Factory for instances of a short-circuiting {@code TerminalOp} that implement
+ * quantified predicate matching on the elements of a stream. Supported variants
+ * include match-all, match-any, and match-none.
+ *
+ * @since 1.8
+ */
+final class MatchOps {
+
+    private MatchOps() { }
+
+    /**
+     * Enum describing quantified match options -- all match, any match, none
+     * match.
+     */
+    enum MatchKind {
+        /** Do all elements match the predicate? */
+        ANY(true, true),
+
+        /** Do any elements match the predicate? */
+        ALL(false, false),
+
+        /** Do no elements match the predicate? */
+        NONE(true, false);
+
+        private final boolean stopOnPredicateMatches;
+        private final boolean shortCircuitResult;
+
+        private MatchKind(boolean stopOnPredicateMatches,
+                          boolean shortCircuitResult) {
+            this.stopOnPredicateMatches = stopOnPredicateMatches;
+            this.shortCircuitResult = shortCircuitResult;
+        }
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for a Stream.
+     *
+     * @param <T> the type of stream elements
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static <T> TerminalOp<T, Boolean> makeRef(Predicate<? super T> predicate,
+            MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<T> {
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(T t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.REFERENCE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for an {@code IntStream}.
+     *
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static TerminalOp<Integer, Boolean> makeInt(IntPredicate predicate,
+                                                       MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<Integer> implements Sink.OfInt {
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(int t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.INT_VALUE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for a {@code LongStream}.
+     *
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static TerminalOp<Long, Boolean> makeLong(LongPredicate predicate,
+                                                     MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<Long> implements Sink.OfLong {
+
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(long t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.LONG_VALUE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for a {@code DoubleStream}.
+     *
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static TerminalOp<Double, Boolean> makeDouble(DoublePredicate predicate,
+                                                         MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<Double> implements Sink.OfDouble {
+
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(double t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.DOUBLE_VALUE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * A short-circuiting {@code TerminalOp} that evaluates a predicate on the
+     * elements of a stream and determines whether all, any or none of those
+     * elements match the predicate.
+     *
+     * @param <T> the output type of the stream pipeline
+     */
+    private static final class MatchOp<T> implements TerminalOp<T, Boolean> {
+        private final StreamShape inputShape;
+        final MatchKind matchKind;
+        final Supplier<BooleanTerminalSink<T>> sinkSupplier;
+
+        /**
+         * Constructs a {@code MatchOp}.
+         *
+         * @param shape the output shape of the stream pipeline
+         * @param matchKind the kind of quantified match (all, any, none)
+         * @param sinkSupplier {@code Supplier} for a {@code Sink} of the
+         *        appropriate shape which implements the matching operation
+         */
+        MatchOp(StreamShape shape,
+                MatchKind matchKind,
+                Supplier<BooleanTerminalSink<T>> sinkSupplier) {
+            this.inputShape = shape;
+            this.matchKind = matchKind;
+            this.sinkSupplier = sinkSupplier;
+        }
+
+        @Override
+        public int getOpFlags() {
+            return StreamOpFlag.IS_SHORT_CIRCUIT | StreamOpFlag.NOT_ORDERED;
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public <S> Boolean evaluateSequential(PipelineHelper<T> helper,
+                                              Spliterator<S> spliterator) {
+            return helper.wrapAndCopyInto(sinkSupplier.get(), spliterator).getAndClearState();
+        }
+
+        @Override
+        public <S> Boolean evaluateParallel(PipelineHelper<T> helper,
+                                            Spliterator<S> spliterator) {
+            // Approach for parallel implementation:
+            // - Decompose as per usual
+            // - run match on leaf chunks, call result "b"
+            // - if b == matchKind.shortCircuitOn, complete early and return b
+            // - else if we complete normally, return !shortCircuitOn
+
+            return new MatchTask<>(this, helper, spliterator).invoke();
+        }
+    }
+
+    /**
+     * Boolean specific terminal sink to avoid the boxing costs when returning
+     * results.  Subclasses implement the shape-specific functionality.
+     *
+     * @param <T> The output type of the stream pipeline
+     */
+    private static abstract class BooleanTerminalSink<T> implements Sink<T> {
+        boolean stop;
+        boolean value;
+
+        BooleanTerminalSink(MatchKind matchKind) {
+            value = !matchKind.shortCircuitResult;
+        }
+
+        public boolean getAndClearState() {
+            return value;
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return stop;
+        }
+    }
+
+    /**
+     * ForkJoinTask implementation to implement a parallel short-circuiting
+     * quantified match
+     *
+     * @param <P_IN> the type of source elements for the pipeline
+     * @param <P_OUT> the type of output elements for the pipeline
+     */
+    @SuppressWarnings("serial")
+    private static final class MatchTask<P_IN, P_OUT>
+            extends AbstractShortCircuitTask<P_IN, P_OUT, Boolean, MatchTask<P_IN, P_OUT>> {
+        private final MatchOp<P_OUT> op;
+
+        /**
+         * Constructor for root node
+         */
+        MatchTask(MatchOp<P_OUT> op, PipelineHelper<P_OUT> helper,
+                  Spliterator<P_IN> spliterator) {
+            super(helper, spliterator);
+            this.op = op;
+        }
+
+        /**
+         * Constructor for non-root node
+         */
+        MatchTask(MatchTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+        }
+
+        @Override
+        protected MatchTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) {
+            return new MatchTask<>(this, spliterator);
+        }
+
+        @Override
+        protected Boolean doLeaf() {
+            boolean b = helper.wrapAndCopyInto(op.sinkSupplier.get(), spliterator).getAndClearState();
+            if (b == op.matchKind.shortCircuitResult)
+                shortCircuit(b);
+            return null;
+        }
+
+        @Override
+        protected Boolean getEmptyResult() {
+            return !op.matchKind.shortCircuitResult;
+        }
+    }
+}
+
diff --git a/java/util/stream/Node.java b/java/util/stream/Node.java
new file mode 100644
index 0000000..e20de78
--- /dev/null
+++ b/java/util/stream/Node.java
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+
+/**
+ * An immutable container for describing an ordered sequence of elements of some
+ * type {@code T}.
+ *
+ * <p>A {@code Node} contains a fixed number of elements, which can be accessed
+ * via the {@link #count}, {@link #spliterator}, {@link #forEach},
+ * {@link #asArray}, or {@link #copyInto} methods.  A {@code Node} may have zero
+ * or more child {@code Node}s; if it has no children (accessed via
+ * {@link #getChildCount} and {@link #getChild(int)}, it is considered <em>flat
+ * </em> or a <em>leaf</em>; if it has children, it is considered an
+ * <em>internal</em> node.  The size of an internal node is the sum of sizes of
+ * its children.
+ *
+ * @apiNote
+ * <p>A {@code Node} typically does not store the elements directly, but instead
+ * mediates access to one or more existing (effectively immutable) data
+ * structures such as a {@code Collection}, array, or a set of other
+ * {@code Node}s.  Commonly {@code Node}s are formed into a tree whose shape
+ * corresponds to the computation tree that produced the elements that are
+ * contained in the leaf nodes.  The use of {@code Node} within the stream
+ * framework is largely to avoid copying data unnecessarily during parallel
+ * operations.
+ *
+ * @param <T> the type of elements.
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public interface Node<T> {
+
+    /**
+     * Returns a {@link Spliterator} describing the elements contained in this
+     * {@code Node}.
+     *
+     * @return a {@code Spliterator} describing the elements contained in this
+     *         {@code Node}
+     */
+    Spliterator<T> spliterator();
+
+    /**
+     * Traverses the elements of this node, and invoke the provided
+     * {@code Consumer} with each element.  Elements are provided in encounter
+     * order if the source for the {@code Node} has a defined encounter order.
+     *
+     * @param consumer a {@code Consumer} that is to be invoked with each
+     *        element in this {@code Node}
+     */
+    void forEach(Consumer<? super T> consumer);
+
+    /**
+     * Returns the number of child nodes of this node.
+     *
+     * @implSpec The default implementation returns zero.
+     *
+     * @return the number of child nodes
+     */
+    default int getChildCount() {
+        return 0;
+    }
+
+    /**
+     * Retrieves the child {@code Node} at a given index.
+     *
+     * @implSpec The default implementation always throws
+     * {@code IndexOutOfBoundsException}.
+     *
+     * @param i the index to the child node
+     * @return the child node
+     * @throws IndexOutOfBoundsException if the index is less than 0 or greater
+     *         than or equal to the number of child nodes
+     */
+    default Node<T> getChild(int i) {
+        throw new IndexOutOfBoundsException();
+    }
+
+    /**
+     * Return a node describing a subsequence of the elements of this node,
+     * starting at the given inclusive start offset and ending at the given
+     * exclusive end offset.
+     *
+     * @param from The (inclusive) starting offset of elements to include, must
+     *             be in range 0..count().
+     * @param to The (exclusive) end offset of elements to include, must be
+     *           in range 0..count().
+     * @param generator A function to be used to create a new array, if needed,
+     *                  for reference nodes.
+     * @return the truncated node
+     */
+    default Node<T> truncate(long from, long to, IntFunction<T[]> generator) {
+        if (from == 0 && to == count())
+            return this;
+        Spliterator<T> spliterator = spliterator();
+        long size = to - from;
+        Node.Builder<T> nodeBuilder = Nodes.builder(size, generator);
+        nodeBuilder.begin(size);
+        for (int i = 0; i < from && spliterator.tryAdvance(e -> { }); i++) { }
+        for (int i = 0; (i < size) && spliterator.tryAdvance(nodeBuilder); i++) { }
+        nodeBuilder.end();
+        return nodeBuilder.build();
+    }
+
+    /**
+     * Provides an array view of the contents of this node.
+     *
+     * <p>Depending on the underlying implementation, this may return a
+     * reference to an internal array rather than a copy.  Since the returned
+     * array may be shared, the returned array should not be modified.  The
+     * {@code generator} function may be consulted to create the array if a new
+     * array needs to be created.
+     *
+     * @param generator a factory function which takes an integer parameter and
+     *        returns a new, empty array of that size and of the appropriate
+     *        array type
+     * @return an array containing the contents of this {@code Node}
+     */
+    T[] asArray(IntFunction<T[]> generator);
+
+    /**
+     * Copies the content of this {@code Node} into an array, starting at a
+     * given offset into the array.  It is the caller's responsibility to ensure
+     * there is sufficient room in the array, otherwise unspecified behaviour
+     * will occur if the array length is less than the number of elements
+     * contained in this node.
+     *
+     * @param array the array into which to copy the contents of this
+     *       {@code Node}
+     * @param offset the starting offset within the array
+     * @throws IndexOutOfBoundsException if copying would cause access of data
+     *         outside array bounds
+     * @throws NullPointerException if {@code array} is {@code null}
+     */
+    void copyInto(T[] array, int offset);
+
+    /**
+     * Gets the {@code StreamShape} associated with this {@code Node}.
+     *
+     * @implSpec The default in {@code Node} returns
+     * {@code StreamShape.REFERENCE}
+     *
+     * @return the stream shape associated with this node
+     */
+    default StreamShape getShape() {
+        return StreamShape.REFERENCE;
+    }
+
+    /**
+     * Returns the number of elements contained in this node.
+     *
+     * @return the number of elements contained in this node
+     */
+    long count();
+
+    /**
+     * A mutable builder for a {@code Node} that implements {@link Sink}, which
+     * builds a flat node containing the elements that have been pushed to it.
+     */
+    interface Builder<T> extends Sink<T> {
+
+        /**
+         * Builds the node.  Should be called after all elements have been
+         * pushed and signalled with an invocation of {@link Sink#end()}.
+         *
+         * @return the resulting {@code Node}
+         */
+        Node<T> build();
+
+        /**
+         * Specialized @{code Node.Builder} for int elements
+         */
+        interface OfInt extends Node.Builder<Integer>, Sink.OfInt {
+            @Override
+            Node.OfInt build();
+        }
+
+        /**
+         * Specialized @{code Node.Builder} for long elements
+         */
+        interface OfLong extends Node.Builder<Long>, Sink.OfLong {
+            @Override
+            Node.OfLong build();
+        }
+
+        /**
+         * Specialized @{code Node.Builder} for double elements
+         */
+        interface OfDouble extends Node.Builder<Double>, Sink.OfDouble {
+            @Override
+            Node.OfDouble build();
+        }
+    }
+
+    public interface OfPrimitive<T, T_CONS, T_ARR,
+                                 T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                                 T_NODE extends OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>>
+            extends Node<T> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @return a {@link Spliterator.OfPrimitive} describing the elements of
+         *         this node
+         */
+        @Override
+        T_SPLITR spliterator();
+
+        /**
+         * Traverses the elements of this node, and invoke the provided
+         * {@code action} with each element.
+         *
+         * @param action a consumer that is to be invoked with each
+         *        element in this {@code Node.OfPrimitive}
+         */
+        @SuppressWarnings("overloads")
+        void forEach(T_CONS action);
+
+        @Override
+        default T_NODE getChild(int i) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        T_NODE truncate(long from, long to, IntFunction<T[]> generator);
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes the generator to create
+         * an instance of a boxed primitive array with a length of
+         * {@link #count()} and then invokes {@link #copyInto(T[], int)} with
+         * that array at an offset of 0.
+         */
+        @Override
+        default T[] asArray(IntFunction<T[]> generator) {
+            if (java.util.stream.Tripwire.ENABLED)
+                java.util.stream.Tripwire.trip(getClass(), "{0} calling Node.OfPrimitive.asArray");
+
+            long size = count();
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            T[] boxed = generator.apply((int) count());
+            copyInto(boxed, 0);
+            return boxed;
+        }
+
+        /**
+         * Views this node as a primitive array.
+         *
+         * <p>Depending on the underlying implementation this may return a
+         * reference to an internal array rather than a copy.  It is the callers
+         * responsibility to decide if either this node or the array is utilized
+         * as the primary reference for the data.</p>
+         *
+         * @return an array containing the contents of this {@code Node}
+         */
+        T_ARR asPrimitiveArray();
+
+        /**
+         * Creates a new primitive array.
+         *
+         * @param count the length of the primitive array.
+         * @return the new primitive array.
+         */
+        T_ARR newArray(int count);
+
+        /**
+         * Copies the content of this {@code Node} into a primitive array,
+         * starting at a given offset into the array.  It is the caller's
+         * responsibility to ensure there is sufficient room in the array.
+         *
+         * @param array the array into which to copy the contents of this
+         *              {@code Node}
+         * @param offset the starting offset within the array
+         * @throws IndexOutOfBoundsException if copying would cause access of
+         *         data outside array bounds
+         * @throws NullPointerException if {@code array} is {@code null}
+         */
+        void copyInto(T_ARR array, int offset);
+    }
+
+    /**
+     * Specialized {@code Node} for int elements
+     */
+    interface OfInt extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, OfInt> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @param consumer a {@code Consumer} that is to be invoked with each
+         *        element in this {@code Node}.  If this is an
+         *        {@code IntConsumer}, it is cast to {@code IntConsumer} so the
+         *        elements may be processed without boxing.
+         */
+        @Override
+        default void forEach(Consumer<? super Integer> consumer) {
+            if (consumer instanceof IntConsumer) {
+                forEach((IntConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling Node.OfInt.forEachRemaining(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes {@link #asPrimitiveArray()} to
+         * obtain an int[] array then and copies the elements from that int[]
+         * array into the boxed Integer[] array.  This is not efficient and it
+         * is recommended to invoke {@link #copyInto(Object, int)}.
+         */
+        @Override
+        default void copyInto(Integer[] boxed, int offset) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Node.OfInt.copyInto(Integer[], int)");
+
+            int[] array = asPrimitiveArray();
+            for (int i = 0; i < array.length; i++) {
+                boxed[offset + i] = array[i];
+            }
+        }
+
+        @Override
+        default Node.OfInt truncate(long from, long to, IntFunction<Integer[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long size = to - from;
+            Spliterator.OfInt spliterator = spliterator();
+            Node.Builder.OfInt nodeBuilder = Nodes.intBuilder(size);
+            nodeBuilder.begin(size);
+            for (int i = 0; i < from && spliterator.tryAdvance((IntConsumer) e -> { }); i++) { }
+            for (int i = 0; (i < size) && spliterator.tryAdvance((IntConsumer) nodeBuilder); i++) { }
+            nodeBuilder.end();
+            return nodeBuilder.build();
+        }
+
+        @Override
+        default int[] newArray(int count) {
+            return new int[count];
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec The default in {@code Node.OfInt} returns
+         * {@code StreamShape.INT_VALUE}
+         */
+        default StreamShape getShape() {
+            return StreamShape.INT_VALUE;
+        }
+    }
+
+    /**
+     * Specialized {@code Node} for long elements
+     */
+    interface OfLong extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, OfLong> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @param consumer A {@code Consumer} that is to be invoked with each
+         *        element in this {@code Node}.  If this is an
+         *        {@code LongConsumer}, it is cast to {@code LongConsumer} so
+         *        the elements may be processed without boxing.
+         */
+        @Override
+        default void forEach(Consumer<? super Long> consumer) {
+            if (consumer instanceof LongConsumer) {
+                forEach((LongConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling Node.OfLong.forEachRemaining(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes {@link #asPrimitiveArray()}
+         * to obtain a long[] array then and copies the elements from that
+         * long[] array into the boxed Long[] array.  This is not efficient and
+         * it is recommended to invoke {@link #copyInto(Object, int)}.
+         */
+        @Override
+        default void copyInto(Long[] boxed, int offset) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Node.OfInt.copyInto(Long[], int)");
+
+            long[] array = asPrimitiveArray();
+            for (int i = 0; i < array.length; i++) {
+                boxed[offset + i] = array[i];
+            }
+        }
+
+        @Override
+        default Node.OfLong truncate(long from, long to, IntFunction<Long[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long size = to - from;
+            Spliterator.OfLong spliterator = spliterator();
+            Node.Builder.OfLong nodeBuilder = Nodes.longBuilder(size);
+            nodeBuilder.begin(size);
+            for (int i = 0; i < from && spliterator.tryAdvance((LongConsumer) e -> { }); i++) { }
+            for (int i = 0; (i < size) && spliterator.tryAdvance((LongConsumer) nodeBuilder); i++) { }
+            nodeBuilder.end();
+            return nodeBuilder.build();
+        }
+
+        @Override
+        default long[] newArray(int count) {
+            return new long[count];
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec The default in {@code Node.OfLong} returns
+         * {@code StreamShape.LONG_VALUE}
+         */
+        default StreamShape getShape() {
+            return StreamShape.LONG_VALUE;
+        }
+    }
+
+    /**
+     * Specialized {@code Node} for double elements
+     */
+    interface OfDouble extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, OfDouble> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @param consumer A {@code Consumer} that is to be invoked with each
+         *        element in this {@code Node}.  If this is an
+         *        {@code DoubleConsumer}, it is cast to {@code DoubleConsumer}
+         *        so the elements may be processed without boxing.
+         */
+        @Override
+        default void forEach(Consumer<? super Double> consumer) {
+            if (consumer instanceof DoubleConsumer) {
+                forEach((DoubleConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling Node.OfLong.forEachRemaining(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        //
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes {@link #asPrimitiveArray()}
+         * to obtain a double[] array then and copies the elements from that
+         * double[] array into the boxed Double[] array.  This is not efficient
+         * and it is recommended to invoke {@link #copyInto(Object, int)}.
+         */
+        @Override
+        default void copyInto(Double[] boxed, int offset) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Node.OfDouble.copyInto(Double[], int)");
+
+            double[] array = asPrimitiveArray();
+            for (int i = 0; i < array.length; i++) {
+                boxed[offset + i] = array[i];
+            }
+        }
+
+        @Override
+        default Node.OfDouble truncate(long from, long to, IntFunction<Double[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long size = to - from;
+            Spliterator.OfDouble spliterator = spliterator();
+            Node.Builder.OfDouble nodeBuilder = Nodes.doubleBuilder(size);
+            nodeBuilder.begin(size);
+            for (int i = 0; i < from && spliterator.tryAdvance((DoubleConsumer) e -> { }); i++) { }
+            for (int i = 0; (i < size) && spliterator.tryAdvance((DoubleConsumer) nodeBuilder); i++) { }
+            nodeBuilder.end();
+            return nodeBuilder.build();
+        }
+
+        @Override
+        default double[] newArray(int count) {
+            return new double[count];
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec The default in {@code Node.OfDouble} returns
+         * {@code StreamShape.DOUBLE_VALUE}
+         */
+        default StreamShape getShape() {
+            return StreamShape.DOUBLE_VALUE;
+        }
+    }
+}
diff --git a/java/util/stream/NodeBuilderTest.java b/java/util/stream/NodeBuilderTest.java
new file mode 100644
index 0000000..11fe86f
--- /dev/null
+++ b/java/util/stream/NodeBuilderTest.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static java.util.stream.LambdaTestHelpers.assertContents;
+import static java.util.stream.LambdaTestHelpers.countTo;
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class NodeBuilderTest {
+
+    List<Integer> sizes = Arrays.asList(0, 1, 4, 16, 256,
+                                        1023, 1024, 1025,
+                                        2047, 2048, 2049,
+                                        1024 * 32 - 1, 1024 * 32, 1024 * 32 + 1);
+
+    @DataProvider(name = "Node.Builder")
+    public Object[][] createNodeBuilders() {
+        List<List<Integer>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            ls.add(countTo(size));
+        }
+
+        List<Function<Integer, Node.Builder<Integer>>> ms = Arrays.asList(
+                s -> Nodes.builder(),
+                s -> Nodes.builder(s, LambdaTestHelpers.integerArrayGenerator)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Integer> l : ls) {
+            for (Function<Integer, Node.Builder<Integer>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder", groups = { "serialization-hostile" })
+    public void testIteration(List<Integer> l, Function<Integer, Node.Builder<Integer>> m) {
+        Node.Builder<Integer> nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Integer i : l) {
+            nb.accept(i);
+        }
+        nb.end();
+
+        Node<Integer> n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Integer> _l = new ArrayList<>();
+            n.forEach(_l::add);
+
+            assertContents(_l, l);
+        }
+    }
+
+    // Node.Builder.OfInt
+
+    @DataProvider(name = "Node.Builder<Integer>")
+    public Object[][] createIntNodeBuilders() {
+        List<List<Integer>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            ls.add(countTo(size));
+        }
+
+        List<Function<Integer, Node.Builder<Integer>>> ms = Arrays.asList(
+                s -> Nodes.intBuilder(),
+                s -> Nodes.intBuilder(s)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Integer> l : ls) {
+            for (Function<Integer, Node.Builder<Integer>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder<Integer>", groups = { "serialization-hostile" })
+    public void testIntIteration(List<Integer> l, Function<Integer, Node.Builder.OfInt> m) {
+        Node.Builder.OfInt nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Integer i : l) {
+            nb.accept((int) i);
+        }
+        nb.end();
+
+        Node.OfInt n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Integer> _l = new ArrayList<>();
+            n.forEach((IntConsumer) _l::add);
+
+            assertContents(_l, l);
+        }
+
+    }
+
+    // Node.Builder.OfLong
+
+    @DataProvider(name = "Node.Builder<Long>")
+    public Object[][] createLongNodeBuilders() {
+        List<List<Long>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            List<Long> l = new ArrayList<>();
+            for (long i = 0; i < size; i++) {
+                l.add(i);
+            }
+            ls.add(l);
+        }
+
+        List<Function<Integer, Node.Builder<Long>>> ms = Arrays.asList(
+                s -> Nodes.longBuilder(),
+                s -> Nodes.longBuilder(s)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Long> l : ls) {
+            for (Function<Integer, Node.Builder<Long>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder<Long>")
+    public void testLongIteration(List<Long> l, Function<Integer, Node.Builder.OfLong> m) {
+        Node.Builder.OfLong nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Long i : l) {
+            nb.accept((long) i);
+        }
+        nb.end();
+
+        Node.OfLong n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Long> _l = new ArrayList<>();
+            n.forEach((LongConsumer) _l::add);
+
+            assertContents(_l, l);
+        }
+
+    }
+
+    // Node.Builder.OfDouble
+
+    @DataProvider(name = "Node.Builder<Double>")
+    public Object[][] createDoubleNodeBuilders() {
+        List<List<Double>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            List<Double> l = new ArrayList<>();
+            for (long i = 0; i < size; i++) {
+                l.add((double) i);
+            }
+            ls.add(l);
+        }
+
+        List<Function<Integer, Node.Builder<Double>>> ms = Arrays.asList(
+                s -> Nodes.doubleBuilder(),
+                s -> Nodes.doubleBuilder(s)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Double> l : ls) {
+            for (Function<Integer, Node.Builder<Double>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder<Double>")
+    public void testDoubleIteration(List<Double> l, Function<Integer, Node.Builder.OfDouble> m) {
+        Node.Builder.OfDouble nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Double i : l) {
+            nb.accept((double) i);
+        }
+        nb.end();
+
+        Node.OfDouble n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Double> _l = new ArrayList<>();
+            n.forEach((DoubleConsumer) _l::add);
+
+            assertContents(_l, l);
+        }
+
+    }
+}
diff --git a/java/util/stream/NodeTest.java b/java/util/stream/NodeTest.java
new file mode 100644
index 0000000..da71003
--- /dev/null
+++ b/java/util/stream/NodeTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class NodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            Integer[] array = new Integer[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Integer>> nodes = new ArrayList<>();
+            nodes.add(Nodes.node(array));
+            nodes.add(Nodes.node(Arrays.asList(array)));
+            nodes.add(degenerateTree(Arrays.asList(array).iterator()));
+            nodes.add(tree(Arrays.asList(array), l -> Nodes.node(l.toArray(new Integer[l.size()]))));
+            nodes.add(tree(Arrays.asList(array), l -> Nodes.node(l)));
+            nodes.add(fill(array, Nodes.builder(array.length, LambdaTestHelpers.integerArrayGenerator)));
+            nodes.add(fill(array, Nodes.builder()));
+
+            for (int i = 0; i < nodes.size(); i++) {
+                params.add(new Object[]{array, nodes.get(i)});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    Node<Integer> fill(Integer[] array, Node.Builder<Integer> nb) {
+        nb.begin(array.length);
+        for (Integer i : array) {
+            nb.accept(i);
+        }
+        nb.end();
+        return nb.build();
+    }
+
+    Node<Integer> degenerateTree(Iterator<Integer> it) {
+        if (!it.hasNext()) {
+            return Nodes.node(Collections.emptyList());
+        }
+
+        Integer i = it.next();
+        if (it.hasNext()) {
+            return new Nodes.ConcNode<Integer>(Nodes.node(new Integer[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new Integer[]{i});
+        }
+    }
+
+    Node<Integer> tree(List<Integer> l, Function<List<Integer>, Node<Integer>> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.ConcNode<>(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m ));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(Integer[] array, Node<Integer> n) {
+        assertEquals(n.asArray(LambdaTestHelpers.integerArrayGenerator), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(Integer[] array, Node<Integer> n) {
+        assertEquals(Nodes.flatten(n, LambdaTestHelpers.integerArrayGenerator)
+                          .asArray(LambdaTestHelpers.integerArrayGenerator), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(Integer[] array, Node<Integer> n) {
+        Integer[] copy = new Integer[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(Integer[] array, Node<Integer> n) {
+        List<Integer> l = new ArrayList<>((int) n.count());
+        n.forEach(e -> l.add(e));
+
+        assertEquals(l.toArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(Integer[] array, Node<Integer> n) {
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofRefNode("Node", n);
+
+        exerciseOps(data, s -> s);
+
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testSpliterator(Integer[] array, Node<Integer> n) {
+        SpliteratorTestHelper.testSpliterator(n::spliterator);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testTruncate(Integer[] array, Node<Integer> n) {
+        int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+        for (int start : nums)
+            for (int end : nums) {
+                if (start < 0 || end < 0 || end < start || end > array.length)
+                    continue;
+                Node<Integer> slice = n.truncate(start, end, Integer[]::new);
+                Integer[] asArray = slice.asArray(Integer[]::new);
+                for (int k = start; k < end; k++)
+                    assertEquals(array[k], asArray[k - start]);
+            }
+    }
+}
diff --git a/java/util/stream/Nodes.java b/java/util/stream/Nodes.java
new file mode 100644
index 0000000..c18540c
--- /dev/null
+++ b/java/util/stream/Nodes.java
@@ -0,0 +1,2227 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.List;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+import java.util.function.LongFunction;
+
+/**
+ * Factory methods for constructing implementations of {@link Node} and
+ * {@link Node.Builder} and their primitive specializations.  Fork/Join tasks
+ * for collecting output from a {@link PipelineHelper} to a {@link Node} and
+ * flattening {@link Node}s.
+ *
+ * @since 1.8
+ */
+final class Nodes {
+
+    private Nodes() {
+        throw new Error("no instances");
+    }
+
+    /**
+     * The maximum size of an array that can be allocated.
+     */
+    static final long MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    // IllegalArgumentException messages
+    static final String BAD_SIZE = "Stream size exceeds max array size";
+
+    @SuppressWarnings("rawtypes")
+    private static final Node EMPTY_NODE = new EmptyNode.OfRef();
+    private static final Node.OfInt EMPTY_INT_NODE = new EmptyNode.OfInt();
+    private static final Node.OfLong EMPTY_LONG_NODE = new EmptyNode.OfLong();
+    private static final Node.OfDouble EMPTY_DOUBLE_NODE = new EmptyNode.OfDouble();
+
+    // General shape-based node creation methods
+
+    /**
+     * Produces an empty node whose count is zero, has no children and no content.
+     *
+     * @param <T> the type of elements of the created node
+     * @param shape the shape of the node to be created
+     * @return an empty node.
+     */
+    @SuppressWarnings("unchecked")
+    static <T> Node<T> emptyNode(StreamShape shape) {
+        switch (shape) {
+            case REFERENCE:    return (Node<T>) EMPTY_NODE;
+            case INT_VALUE:    return (Node<T>) EMPTY_INT_NODE;
+            case LONG_VALUE:   return (Node<T>) EMPTY_LONG_NODE;
+            case DOUBLE_VALUE: return (Node<T>) EMPTY_DOUBLE_NODE;
+            default:
+                throw new IllegalStateException("Unknown shape " + shape);
+        }
+    }
+
+    /**
+     * Produces a concatenated {@link Node} that has two or more children.
+     * <p>The count of the concatenated node is equal to the sum of the count
+     * of each child. Traversal of the concatenated node traverses the content
+     * of each child in encounter order of the list of children. Splitting a
+     * spliterator obtained from the concatenated node preserves the encounter
+     * order of the list of children.
+     *
+     * <p>The result may be a concatenated node, the input sole node if the size
+     * of the list is 1, or an empty node.
+     *
+     * @param <T> the type of elements of the concatenated node
+     * @param shape the shape of the concatenated node to be created
+     * @param left the left input node
+     * @param right the right input node
+     * @return a {@code Node} covering the elements of the input nodes
+     * @throws IllegalStateException if all {@link Node} elements of the list
+     * are an not instance of type supported by this factory.
+     */
+    @SuppressWarnings("unchecked")
+    static <T> Node<T> conc(StreamShape shape, Node<T> left, Node<T> right) {
+        switch (shape) {
+            case REFERENCE:
+                return new ConcNode<>(left, right);
+            case INT_VALUE:
+                return (Node<T>) new ConcNode.OfInt((Node.OfInt) left, (Node.OfInt) right);
+            case LONG_VALUE:
+                return (Node<T>) new ConcNode.OfLong((Node.OfLong) left, (Node.OfLong) right);
+            case DOUBLE_VALUE:
+                return (Node<T>) new ConcNode.OfDouble((Node.OfDouble) left, (Node.OfDouble) right);
+            default:
+                throw new IllegalStateException("Unknown shape " + shape);
+        }
+    }
+
+    // Reference-based node methods
+
+    /**
+     * Produces a {@link Node} describing an array.
+     *
+     * <p>The node will hold a reference to the array and will not make a copy.
+     *
+     * @param <T> the type of elements held by the node
+     * @param array the array
+     * @return a node holding an array
+     */
+    static <T> Node<T> node(T[] array) {
+        return new ArrayNode<>(array);
+    }
+
+    /**
+     * Produces a {@link Node} describing a {@link Collection}.
+     * <p>
+     * The node will hold a reference to the collection and will not make a copy.
+     *
+     * @param <T> the type of elements held by the node
+     * @param c the collection
+     * @return a node holding a collection
+     */
+    static <T> Node<T> node(Collection<T> c) {
+        return new CollectionNode<>(c);
+    }
+
+    /**
+     * Produces a {@link Node.Builder}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @param generator the array factory
+     * @param <T> the type of elements of the node builder
+     * @return a {@code Node.Builder}
+     */
+    static <T> Node.Builder<T> builder(long exactSizeIfKnown, IntFunction<T[]> generator) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new FixedNodeBuilder<>(exactSizeIfKnown, generator)
+               : builder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder}.
+     *
+     * @param <T> the type of elements of the node builder
+     * @return a {@code Node.Builder}
+     */
+    static <T> Node.Builder<T> builder() {
+        return new SpinedNodeBuilder<>();
+    }
+
+    // Int nodes
+
+    /**
+     * Produces a {@link Node.OfInt} describing an int[] array.
+     *
+     * <p>The node will hold a reference to the array and will not make a copy.
+     *
+     * @param array the array
+     * @return a node holding an array
+     */
+    static Node.OfInt node(int[] array) {
+        return new IntArrayNode(array);
+    }
+
+    /**
+     * Produces a {@link Node.Builder.OfInt}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @return a {@code Node.Builder.OfInt}
+     */
+    static Node.Builder.OfInt intBuilder(long exactSizeIfKnown) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new IntFixedNodeBuilder(exactSizeIfKnown)
+               : intBuilder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder.OfInt}.
+     *
+     * @return a {@code Node.Builder.OfInt}
+     */
+    static Node.Builder.OfInt intBuilder() {
+        return new IntSpinedNodeBuilder();
+    }
+
+    // Long nodes
+
+    /**
+     * Produces a {@link Node.OfLong} describing a long[] array.
+     * <p>
+     * The node will hold a reference to the array and will not make a copy.
+     *
+     * @param array the array
+     * @return a node holding an array
+     */
+    static Node.OfLong node(final long[] array) {
+        return new LongArrayNode(array);
+    }
+
+    /**
+     * Produces a {@link Node.Builder.OfLong}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @return a {@code Node.Builder.OfLong}
+     */
+    static Node.Builder.OfLong longBuilder(long exactSizeIfKnown) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new LongFixedNodeBuilder(exactSizeIfKnown)
+               : longBuilder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder.OfLong}.
+     *
+     * @return a {@code Node.Builder.OfLong}
+     */
+    static Node.Builder.OfLong longBuilder() {
+        return new LongSpinedNodeBuilder();
+    }
+
+    // Double nodes
+
+    /**
+     * Produces a {@link Node.OfDouble} describing a double[] array.
+     *
+     * <p>The node will hold a reference to the array and will not make a copy.
+     *
+     * @param array the array
+     * @return a node holding an array
+     */
+    static Node.OfDouble node(final double[] array) {
+        return new DoubleArrayNode(array);
+    }
+
+    /**
+     * Produces a {@link Node.Builder.OfDouble}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @return a {@code Node.Builder.OfDouble}
+     */
+    static Node.Builder.OfDouble doubleBuilder(long exactSizeIfKnown) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new DoubleFixedNodeBuilder(exactSizeIfKnown)
+               : doubleBuilder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder.OfDouble}.
+     *
+     * @return a {@code Node.Builder.OfDouble}
+     */
+    static Node.Builder.OfDouble doubleBuilder() {
+        return new DoubleSpinedNodeBuilder();
+    }
+
+    // Parallel evaluation of pipelines to nodes
+
+    /**
+     * Collect, in parallel, elements output from a pipeline and describe those
+     * elements with a {@link Node}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node} if desired.
+     *
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @param generator the array generator
+     * @return a {@link Node} describing the output elements
+     */
+    public static <P_IN, P_OUT> Node<P_OUT> collect(PipelineHelper<P_OUT> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    boolean flattenTree,
+                                                    IntFunction<P_OUT[]> generator) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            P_OUT[] array = generator.apply((int) size);
+            new SizedCollectorTask.OfRef<>(spliterator, helper, array).invoke();
+            return node(array);
+        } else {
+            Node<P_OUT> node = new CollectorTask.OfRef<>(helper, generator, spliterator).invoke();
+            return flattenTree ? flatten(node, generator) : node;
+        }
+    }
+
+    /**
+     * Collect, in parallel, elements output from an int-valued pipeline and
+     * describe those elements with a {@link Node.OfInt}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node.OfInt} if desired.
+     *
+     * @param <P_IN> the type of elements from the source Spliterator
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @return a {@link Node.OfInt} describing the output elements
+     */
+    public static <P_IN> Node.OfInt collectInt(PipelineHelper<Integer> helper,
+                                               Spliterator<P_IN> spliterator,
+                                               boolean flattenTree) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            int[] array = new int[(int) size];
+            new SizedCollectorTask.OfInt<>(spliterator, helper, array).invoke();
+            return node(array);
+        }
+        else {
+            Node.OfInt node = new CollectorTask.OfInt<>(helper, spliterator).invoke();
+            return flattenTree ? flattenInt(node) : node;
+        }
+    }
+
+    /**
+     * Collect, in parallel, elements output from a long-valued pipeline and
+     * describe those elements with a {@link Node.OfLong}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node.OfLong} if desired.
+     *
+     * @param <P_IN> the type of elements from the source Spliterator
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @return a {@link Node.OfLong} describing the output elements
+     */
+    public static <P_IN> Node.OfLong collectLong(PipelineHelper<Long> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 boolean flattenTree) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            long[] array = new long[(int) size];
+            new SizedCollectorTask.OfLong<>(spliterator, helper, array).invoke();
+            return node(array);
+        }
+        else {
+            Node.OfLong node = new CollectorTask.OfLong<>(helper, spliterator).invoke();
+            return flattenTree ? flattenLong(node) : node;
+        }
+    }
+
+    /**
+     * Collect, in parallel, elements output from n double-valued pipeline and
+     * describe those elements with a {@link Node.OfDouble}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node.OfDouble} if desired.
+     *
+     * @param <P_IN> the type of elements from the source Spliterator
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @return a {@link Node.OfDouble} describing the output elements
+     */
+    public static <P_IN> Node.OfDouble collectDouble(PipelineHelper<Double> helper,
+                                                     Spliterator<P_IN> spliterator,
+                                                     boolean flattenTree) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            double[] array = new double[(int) size];
+            new SizedCollectorTask.OfDouble<>(spliterator, helper, array).invoke();
+            return node(array);
+        }
+        else {
+            Node.OfDouble node = new CollectorTask.OfDouble<>(helper, spliterator).invoke();
+            return flattenTree ? flattenDouble(node) : node;
+        }
+    }
+
+    // Parallel flattening of nodes
+
+    /**
+     * Flatten, in parallel, a {@link Node}.  A flattened node is one that has
+     * no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, the generator is used to create an array
+     * whose length is {@link Node#count()}.  Then the node tree is traversed
+     * and leaf node elements are placed in the array concurrently by leaf tasks
+     * at the correct offsets.
+     *
+     * @param <T> type of elements contained by the node
+     * @param node the node to flatten
+     * @param generator the array factory used to create array instances
+     * @return a flat {@code Node}
+     */
+    public static <T> Node<T> flatten(Node<T> node, IntFunction<T[]> generator) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            T[] array = generator.apply((int) size);
+            new ToArrayTask.OfRef<>(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    /**
+     * Flatten, in parallel, a {@link Node.OfInt}.  A flattened node is one that
+     * has no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, a new int[] array is created whose length
+     * is {@link Node#count()}.  Then the node tree is traversed and leaf node
+     * elements are placed in the array concurrently by leaf tasks at the
+     * correct offsets.
+     *
+     * @param node the node to flatten
+     * @return a flat {@code Node.OfInt}
+     */
+    public static Node.OfInt flattenInt(Node.OfInt node) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            int[] array = new int[(int) size];
+            new ToArrayTask.OfInt(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    /**
+     * Flatten, in parallel, a {@link Node.OfLong}.  A flattened node is one that
+     * has no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, a new long[] array is created whose length
+     * is {@link Node#count()}.  Then the node tree is traversed and leaf node
+     * elements are placed in the array concurrently by leaf tasks at the
+     * correct offsets.
+     *
+     * @param node the node to flatten
+     * @return a flat {@code Node.OfLong}
+     */
+    public static Node.OfLong flattenLong(Node.OfLong node) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            long[] array = new long[(int) size];
+            new ToArrayTask.OfLong(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    /**
+     * Flatten, in parallel, a {@link Node.OfDouble}.  A flattened node is one that
+     * has no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, a new double[] array is created whose length
+     * is {@link Node#count()}.  Then the node tree is traversed and leaf node
+     * elements are placed in the array concurrently by leaf tasks at the
+     * correct offsets.
+     *
+     * @param node the node to flatten
+     * @return a flat {@code Node.OfDouble}
+     */
+    public static Node.OfDouble flattenDouble(Node.OfDouble node) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            double[] array = new double[(int) size];
+            new ToArrayTask.OfDouble(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    // Implementations
+
+    private static abstract class EmptyNode<T, T_ARR, T_CONS> implements Node<T> {
+        EmptyNode() { }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> generator) {
+            return generator.apply(0);
+        }
+
+        public void copyInto(T_ARR array, int offset) { }
+
+        @Override
+        public long count() {
+            return 0;
+        }
+
+        public void forEach(T_CONS consumer) { }
+
+        private static class OfRef<T> extends EmptyNode<T, T[], Consumer<? super T>> {
+            private OfRef() {
+                super();
+            }
+
+            @Override
+            public Spliterator<T> spliterator() {
+                return Spliterators.emptySpliterator();
+            }
+        }
+
+        private static final class OfInt
+                extends EmptyNode<Integer, int[], IntConsumer>
+                implements Node.OfInt {
+
+            OfInt() { } // Avoid creation of special accessor
+
+            @Override
+            public Spliterator.OfInt spliterator() {
+                return Spliterators.emptyIntSpliterator();
+            }
+
+            @Override
+            public int[] asPrimitiveArray() {
+                return EMPTY_INT_ARRAY;
+            }
+        }
+
+        private static final class OfLong
+                extends EmptyNode<Long, long[], LongConsumer>
+                implements Node.OfLong {
+
+            OfLong() { } // Avoid creation of special accessor
+
+            @Override
+            public Spliterator.OfLong spliterator() {
+                return Spliterators.emptyLongSpliterator();
+            }
+
+            @Override
+            public long[] asPrimitiveArray() {
+                return EMPTY_LONG_ARRAY;
+            }
+        }
+
+        private static final class OfDouble
+                extends EmptyNode<Double, double[], DoubleConsumer>
+                implements Node.OfDouble {
+
+            OfDouble() { } // Avoid creation of special accessor
+
+            @Override
+            public Spliterator.OfDouble spliterator() {
+                return Spliterators.emptyDoubleSpliterator();
+            }
+
+            @Override
+            public double[] asPrimitiveArray() {
+                return EMPTY_DOUBLE_ARRAY;
+            }
+        }
+    }
+
+    /** Node class for a reference array */
+    private static class ArrayNode<T> implements Node<T> {
+        final T[] array;
+        int curSize;
+
+        @SuppressWarnings("unchecked")
+        ArrayNode(long size, IntFunction<T[]> generator) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = generator.apply((int) size);
+            this.curSize = 0;
+        }
+
+        ArrayNode(T[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public void copyInto(T[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> generator) {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        //
+
+        @Override
+        public String toString() {
+            return String.format("ArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    /** Node class for a Collection */
+    private static final class CollectionNode<T> implements Node<T> {
+        private final Collection<T> c;
+
+        CollectionNode(Collection<T> c) {
+            this.c = c;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return c.stream().spliterator();
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            for (T t : c)
+                array[offset++] = t;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public T[] asArray(IntFunction<T[]> generator) {
+            return c.toArray(generator.apply(c.size()));
+        }
+
+        @Override
+        public long count() {
+            return c.size();
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            c.forEach(consumer);
+        }
+
+        //
+
+        @Override
+        public String toString() {
+            return String.format("CollectionNode[%d][%s]", c.size(), c);
+        }
+    }
+
+    /**
+     * Node class for an internal node with two or more children
+     */
+    private static abstract class AbstractConcNode<T, T_NODE extends Node<T>> implements Node<T> {
+        protected final T_NODE left;
+        protected final T_NODE right;
+        private final long size;
+
+        AbstractConcNode(T_NODE left, T_NODE right) {
+            this.left = left;
+            this.right = right;
+            // The Node count will be required when the Node spliterator is
+            // obtained and it is cheaper to aggressively calculate bottom up
+            // as the tree is built rather than later on from the top down
+            // traversing the tree
+            this.size = left.count() + right.count();
+        }
+
+        @Override
+        public int getChildCount() {
+            return 2;
+        }
+
+        @Override
+        public T_NODE getChild(int i) {
+            if (i == 0) return left;
+            if (i == 1) return right;
+            throw new IndexOutOfBoundsException();
+        }
+
+        @Override
+        public long count() {
+            return size;
+        }
+    }
+
+    static final class ConcNode<T>
+            extends AbstractConcNode<T, Node<T>>
+            implements Node<T> {
+
+        ConcNode(Node<T> left, Node<T> right) {
+            super(left, right);
+        }
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return new Nodes.InternalNodeSpliterator.OfRef<>(this);
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            Objects.requireNonNull(array);
+            left.copyInto(array, offset);
+            // Cast to int is safe since it is the callers responsibility to
+            // ensure that there is sufficient room in the array
+            right.copyInto(array, offset + (int) left.count());
+        }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> generator) {
+            long size = count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            T[] array = generator.apply((int) size);
+            copyInto(array, 0);
+            return array;
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            left.forEach(consumer);
+            right.forEach(consumer);
+        }
+
+        @Override
+        public Node<T> truncate(long from, long to, IntFunction<T[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long leftCount = left.count();
+            if (from >= leftCount)
+                return right.truncate(from - leftCount, to - leftCount, generator);
+            else if (to <= leftCount)
+                return left.truncate(from, to, generator);
+            else {
+                return Nodes.conc(getShape(), left.truncate(from, leftCount, generator),
+                                  right.truncate(0, to - leftCount, generator));
+            }
+        }
+
+        @Override
+        public String toString() {
+            if (count() < 32) {
+                return String.format("ConcNode[%s.%s]", left, right);
+            } else {
+                return String.format("ConcNode[size=%d]", count());
+            }
+        }
+
+        private abstract static class OfPrimitive<E, T_CONS, T_ARR,
+                                                  T_SPLITR extends Spliterator.OfPrimitive<E, T_CONS, T_SPLITR>,
+                                                  T_NODE extends Node.OfPrimitive<E, T_CONS, T_ARR, T_SPLITR, T_NODE>>
+                extends AbstractConcNode<E, T_NODE>
+                implements Node.OfPrimitive<E, T_CONS, T_ARR, T_SPLITR, T_NODE> {
+
+            OfPrimitive(T_NODE left, T_NODE right) {
+                super(left, right);
+            }
+
+            @Override
+            public void forEach(T_CONS consumer) {
+                left.forEach(consumer);
+                right.forEach(consumer);
+            }
+
+            @Override
+            public void copyInto(T_ARR array, int offset) {
+                left.copyInto(array, offset);
+                // Cast to int is safe since it is the callers responsibility to
+                // ensure that there is sufficient room in the array
+                right.copyInto(array, offset + (int) left.count());
+            }
+
+            @Override
+            public T_ARR asPrimitiveArray() {
+                long size = count();
+                if (size >= MAX_ARRAY_SIZE)
+                    throw new IllegalArgumentException(BAD_SIZE);
+                T_ARR array = newArray((int) size);
+                copyInto(array, 0);
+                return array;
+            }
+
+            @Override
+            public String toString() {
+                if (count() < 32)
+                    return String.format("%s[%s.%s]", this.getClass().getName(), left, right);
+                else
+                    return String.format("%s[size=%d]", this.getClass().getName(), count());
+            }
+        }
+
+        static final class OfInt
+                extends ConcNode.OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt>
+                implements Node.OfInt {
+
+            OfInt(Node.OfInt left, Node.OfInt right) {
+                super(left, right);
+            }
+
+            @Override
+            public Spliterator.OfInt spliterator() {
+                return new InternalNodeSpliterator.OfInt(this);
+            }
+        }
+
+        static final class OfLong
+                extends ConcNode.OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong>
+                implements Node.OfLong {
+
+            OfLong(Node.OfLong left, Node.OfLong right) {
+                super(left, right);
+            }
+
+            @Override
+            public Spliterator.OfLong spliterator() {
+                return new InternalNodeSpliterator.OfLong(this);
+            }
+        }
+
+        static final class OfDouble
+                extends ConcNode.OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble>
+                implements Node.OfDouble {
+
+            OfDouble(Node.OfDouble left, Node.OfDouble right) {
+                super(left, right);
+            }
+
+            @Override
+            public Spliterator.OfDouble spliterator() {
+                return new InternalNodeSpliterator.OfDouble(this);
+            }
+        }
+    }
+
+    /** Abstract class for spliterator for all internal node classes */
+    private static abstract class InternalNodeSpliterator<T,
+                                                          S extends Spliterator<T>,
+                                                          N extends Node<T>>
+            implements Spliterator<T> {
+        // Node we are pointing to
+        // null if full traversal has occurred
+        N curNode;
+
+        // next child of curNode to consume
+        int curChildIndex;
+
+        // The spliterator of the curNode if that node is last and has no children.
+        // This spliterator will be delegated to for splitting and traversing.
+        // null if curNode has children
+        S lastNodeSpliterator;
+
+        // spliterator used while traversing with tryAdvance
+        // null if no partial traversal has occurred
+        S tryAdvanceSpliterator;
+
+        // node stack used when traversing to search and find leaf nodes
+        // null if no partial traversal has occurred
+        Deque<N> tryAdvanceStack;
+
+        InternalNodeSpliterator(N curNode) {
+            this.curNode = curNode;
+        }
+
+        /**
+         * Initiate a stack containing, in left-to-right order, the child nodes
+         * covered by this spliterator
+         */
+        @SuppressWarnings("unchecked")
+        protected final Deque<N> initStack() {
+            // Bias size to the case where leaf nodes are close to this node
+            // 8 is the minimum initial capacity for the ArrayDeque implementation
+            Deque<N> stack = new ArrayDeque<>(8);
+            for (int i = curNode.getChildCount() - 1; i >= curChildIndex; i--)
+                stack.addFirst((N) curNode.getChild(i));
+            return stack;
+        }
+
+        /**
+         * Depth first search, in left-to-right order, of the node tree, using
+         * an explicit stack, to find the next non-empty leaf node.
+         */
+        @SuppressWarnings("unchecked")
+        protected final N findNextLeafNode(Deque<N> stack) {
+            N n = null;
+            while ((n = stack.pollFirst()) != null) {
+                if (n.getChildCount() == 0) {
+                    if (n.count() > 0)
+                        return n;
+                } else {
+                    for (int i = n.getChildCount() - 1; i >= 0; i--)
+                        stack.addFirst((N) n.getChild(i));
+                }
+            }
+
+            return null;
+        }
+
+        @SuppressWarnings("unchecked")
+        protected final boolean initTryAdvance() {
+            if (curNode == null)
+                return false;
+
+            if (tryAdvanceSpliterator == null) {
+                if (lastNodeSpliterator == null) {
+                    // Initiate the node stack
+                    tryAdvanceStack = initStack();
+                    N leaf = findNextLeafNode(tryAdvanceStack);
+                    if (leaf != null)
+                        tryAdvanceSpliterator = (S) leaf.spliterator();
+                    else {
+                        // A non-empty leaf node was not found
+                        // No elements to traverse
+                        curNode = null;
+                        return false;
+                    }
+                }
+                else
+                    tryAdvanceSpliterator = lastNodeSpliterator;
+            }
+            return true;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public final S trySplit() {
+            if (curNode == null || tryAdvanceSpliterator != null)
+                return null; // Cannot split if fully or partially traversed
+            else if (lastNodeSpliterator != null)
+                return (S) lastNodeSpliterator.trySplit();
+            else if (curChildIndex < curNode.getChildCount() - 1)
+                return (S) curNode.getChild(curChildIndex++).spliterator();
+            else {
+                curNode = (N) curNode.getChild(curChildIndex);
+                if (curNode.getChildCount() == 0) {
+                    lastNodeSpliterator = (S) curNode.spliterator();
+                    return (S) lastNodeSpliterator.trySplit();
+                }
+                else {
+                    curChildIndex = 0;
+                    return (S) curNode.getChild(curChildIndex++).spliterator();
+                }
+            }
+        }
+
+        @Override
+        public final long estimateSize() {
+            if (curNode == null)
+                return 0;
+
+            // Will not reflect the effects of partial traversal.
+            // This is compliant with the specification
+            if (lastNodeSpliterator != null)
+                return lastNodeSpliterator.estimateSize();
+            else {
+                long size = 0;
+                for (int i = curChildIndex; i < curNode.getChildCount(); i++)
+                    size += curNode.getChild(i).count();
+                return size;
+            }
+        }
+
+        @Override
+        public final int characteristics() {
+            return Spliterator.SIZED;
+        }
+
+        private static final class OfRef<T>
+                extends InternalNodeSpliterator<T, Spliterator<T>, Node<T>> {
+
+            OfRef(Node<T> curNode) {
+                super(curNode);
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> consumer) {
+                if (!initTryAdvance())
+                    return false;
+
+                boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer);
+                if (!hasNext) {
+                    if (lastNodeSpliterator == null) {
+                        // Advance to the spliterator of the next non-empty leaf node
+                        Node<T> leaf = findNextLeafNode(tryAdvanceStack);
+                        if (leaf != null) {
+                            tryAdvanceSpliterator = leaf.spliterator();
+                            // Since the node is not-empty the spliterator can be advanced
+                            return tryAdvanceSpliterator.tryAdvance(consumer);
+                        }
+                    }
+                    // No more elements to traverse
+                    curNode = null;
+                }
+                return hasNext;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> consumer) {
+                if (curNode == null)
+                    return;
+
+                if (tryAdvanceSpliterator == null) {
+                    if (lastNodeSpliterator == null) {
+                        Deque<Node<T>> stack = initStack();
+                        Node<T> leaf;
+                        while ((leaf = findNextLeafNode(stack)) != null) {
+                            leaf.forEach(consumer);
+                        }
+                        curNode = null;
+                    }
+                    else
+                        lastNodeSpliterator.forEachRemaining(consumer);
+                }
+                else
+                    while(tryAdvance(consumer)) { }
+            }
+        }
+
+        private static abstract class OfPrimitive<T, T_CONS, T_ARR,
+                                                  T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                                                  N extends Node.OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, N>>
+                extends InternalNodeSpliterator<T, T_SPLITR, N>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+
+            OfPrimitive(N cur) {
+                super(cur);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS consumer) {
+                if (!initTryAdvance())
+                    return false;
+
+                boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer);
+                if (!hasNext) {
+                    if (lastNodeSpliterator == null) {
+                        // Advance to the spliterator of the next non-empty leaf node
+                        N leaf = findNextLeafNode(tryAdvanceStack);
+                        if (leaf != null) {
+                            tryAdvanceSpliterator = leaf.spliterator();
+                            // Since the node is not-empty the spliterator can be advanced
+                            return tryAdvanceSpliterator.tryAdvance(consumer);
+                        }
+                    }
+                    // No more elements to traverse
+                    curNode = null;
+                }
+                return hasNext;
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS consumer) {
+                if (curNode == null)
+                    return;
+
+                if (tryAdvanceSpliterator == null) {
+                    if (lastNodeSpliterator == null) {
+                        Deque<N> stack = initStack();
+                        N leaf;
+                        while ((leaf = findNextLeafNode(stack)) != null) {
+                            leaf.forEach(consumer);
+                        }
+                        curNode = null;
+                    }
+                    else
+                        lastNodeSpliterator.forEachRemaining(consumer);
+                }
+                else
+                    while(tryAdvance(consumer)) { }
+            }
+        }
+
+        private static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt>
+                implements Spliterator.OfInt {
+
+            OfInt(Node.OfInt cur) {
+                super(cur);
+            }
+        }
+
+        private static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong>
+                implements Spliterator.OfLong {
+
+            OfLong(Node.OfLong cur) {
+                super(cur);
+            }
+        }
+
+        private static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble>
+                implements Spliterator.OfDouble {
+
+            OfDouble(Node.OfDouble cur) {
+                super(cur);
+            }
+        }
+    }
+
+    /**
+     * Fixed-sized builder class for reference nodes
+     */
+    private static final class FixedNodeBuilder<T>
+            extends ArrayNode<T>
+            implements Node.Builder<T> {
+
+        FixedNodeBuilder(long size, IntFunction<T[]> generator) {
+            super(size, generator);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node<T> build() {
+            if (curSize < array.length)
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length)
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(T t) {
+            if (curSize < array.length) {
+                array[curSize++] = t;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length)
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+        }
+
+        @Override
+        public String toString() {
+            return String.format("FixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    /**
+     * Variable-sized builder class for reference nodes
+     */
+    private static final class SpinedNodeBuilder<T>
+            extends SpinedBuffer<T>
+            implements Node<T>, Node.Builder<T> {
+        private boolean building = false;
+
+        SpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator<T> spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(T t) {
+            assert building : "not building";
+            super.accept(t);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> arrayFactory) {
+            assert !building : "during building";
+            return super.asArray(arrayFactory);
+        }
+
+        @Override
+        public Node<T> build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    //
+
+    private static final int[] EMPTY_INT_ARRAY = new int[0];
+    private static final long[] EMPTY_LONG_ARRAY = new long[0];
+    private static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
+
+    private static class IntArrayNode implements Node.OfInt {
+        final int[] array;
+        int curSize;
+
+        IntArrayNode(long size) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = new int[(int) size];
+            this.curSize = 0;
+        }
+
+        IntArrayNode(int[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator.OfInt spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public int[] asPrimitiveArray() {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                return Arrays.copyOf(array, curSize);
+            }
+        }
+
+        @Override
+        public void copyInto(int[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(IntConsumer consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("IntArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static class LongArrayNode implements Node.OfLong {
+        final long[] array;
+        int curSize;
+
+        LongArrayNode(long size) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = new long[(int) size];
+            this.curSize = 0;
+        }
+
+        LongArrayNode(long[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        @Override
+        public Spliterator.OfLong spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public long[] asPrimitiveArray() {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                return Arrays.copyOf(array, curSize);
+            }
+        }
+
+        @Override
+        public void copyInto(long[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(LongConsumer consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("LongArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static class DoubleArrayNode implements Node.OfDouble {
+        final double[] array;
+        int curSize;
+
+        DoubleArrayNode(long size) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = new double[(int) size];
+            this.curSize = 0;
+        }
+
+        DoubleArrayNode(double[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        @Override
+        public Spliterator.OfDouble spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public double[] asPrimitiveArray() {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                return Arrays.copyOf(array, curSize);
+            }
+        }
+
+        @Override
+        public void copyInto(double[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(DoubleConsumer consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("DoubleArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class IntFixedNodeBuilder
+            extends IntArrayNode
+            implements Node.Builder.OfInt {
+
+        IntFixedNodeBuilder(long size) {
+            super(size);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node.OfInt build() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length) {
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            }
+
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(int i) {
+            if (curSize < array.length) {
+                array[curSize++] = i;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("IntFixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class LongFixedNodeBuilder
+            extends LongArrayNode
+            implements Node.Builder.OfLong {
+
+        LongFixedNodeBuilder(long size) {
+            super(size);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node.OfLong build() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length) {
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            }
+
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(long i) {
+            if (curSize < array.length) {
+                array[curSize++] = i;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("LongFixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class DoubleFixedNodeBuilder
+            extends DoubleArrayNode
+            implements Node.Builder.OfDouble {
+
+        DoubleFixedNodeBuilder(long size) {
+            super(size);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node.OfDouble build() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length) {
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            }
+
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(double i) {
+            if (curSize < array.length) {
+                array[curSize++] = i;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("DoubleFixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class IntSpinedNodeBuilder
+            extends SpinedBuffer.OfInt
+            implements Node.OfInt, Node.Builder.OfInt {
+        private boolean building = false;
+
+        IntSpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator.OfInt spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(IntConsumer consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(int i) {
+            assert building : "not building";
+            super.accept(i);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public int[] asPrimitiveArray() {
+            assert !building : "during building";
+            return super.asPrimitiveArray();
+        }
+
+        @Override
+        public Node.OfInt build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    private static final class LongSpinedNodeBuilder
+            extends SpinedBuffer.OfLong
+            implements Node.OfLong, Node.Builder.OfLong {
+        private boolean building = false;
+
+        LongSpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator.OfLong spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(LongConsumer consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(long i) {
+            assert building : "not building";
+            super.accept(i);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(long[] array, int offset) {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public long[] asPrimitiveArray() {
+            assert !building : "during building";
+            return super.asPrimitiveArray();
+        }
+
+        @Override
+        public Node.OfLong build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    private static final class DoubleSpinedNodeBuilder
+            extends SpinedBuffer.OfDouble
+            implements Node.OfDouble, Node.Builder.OfDouble {
+        private boolean building = false;
+
+        DoubleSpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator.OfDouble spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(DoubleConsumer consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(double i) {
+            assert building : "not building";
+            super.accept(i);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(double[] array, int offset) {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public double[] asPrimitiveArray() {
+            assert !building : "during building";
+            return super.asPrimitiveArray();
+        }
+
+        @Override
+        public Node.OfDouble build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    /*
+     * This and subclasses are not intended to be serializable
+     */
+    @SuppressWarnings("serial")
+    private static abstract class SizedCollectorTask<P_IN, P_OUT, T_SINK extends Sink<P_OUT>,
+                                                     K extends SizedCollectorTask<P_IN, P_OUT, T_SINK, K>>
+            extends CountedCompleter<Void>
+            implements Sink<P_OUT> {
+        protected final Spliterator<P_IN> spliterator;
+        protected final PipelineHelper<P_OUT> helper;
+        protected final long targetSize;
+        protected long offset;
+        protected long length;
+        // For Sink implementation
+        protected int index, fence;
+
+        SizedCollectorTask(Spliterator<P_IN> spliterator,
+                           PipelineHelper<P_OUT> helper,
+                           int arrayLength) {
+            assert spliterator.hasCharacteristics(Spliterator.SUBSIZED);
+            this.spliterator = spliterator;
+            this.helper = helper;
+            this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize());
+            this.offset = 0;
+            this.length = arrayLength;
+        }
+
+        SizedCollectorTask(K parent, Spliterator<P_IN> spliterator,
+                           long offset, long length, int arrayLength) {
+            super(parent);
+            assert spliterator.hasCharacteristics(Spliterator.SUBSIZED);
+            this.spliterator = spliterator;
+            this.helper = parent.helper;
+            this.targetSize = parent.targetSize;
+            this.offset = offset;
+            this.length = length;
+
+            if (offset < 0 || length < 0 || (offset + length - 1 >= arrayLength)) {
+                throw new IllegalArgumentException(
+                        String.format("offset and length interval [%d, %d + %d) is not within array size interval [0, %d)",
+                                      offset, offset, length, arrayLength));
+            }
+        }
+
+        @Override
+        public void compute() {
+            SizedCollectorTask<P_IN, P_OUT, T_SINK, K> task = this;
+            Spliterator<P_IN> rightSplit = spliterator, leftSplit;
+            while (rightSplit.estimateSize() > task.targetSize &&
+                   (leftSplit = rightSplit.trySplit()) != null) {
+                task.setPendingCount(1);
+                long leftSplitSize = leftSplit.estimateSize();
+                task.makeChild(leftSplit, task.offset, leftSplitSize).fork();
+                task = task.makeChild(rightSplit, task.offset + leftSplitSize,
+                                      task.length - leftSplitSize);
+            }
+
+            assert task.offset + task.length < MAX_ARRAY_SIZE;
+            @SuppressWarnings("unchecked")
+            T_SINK sink = (T_SINK) task;
+            task.helper.wrapAndCopyInto(sink, rightSplit);
+            task.propagateCompletion();
+        }
+
+        abstract K makeChild(Spliterator<P_IN> spliterator, long offset, long size);
+
+        @Override
+        public void begin(long size) {
+            if (size > length)
+                throw new IllegalStateException("size passed to Sink.begin exceeds array length");
+            // Casts to int are safe since absolute size is verified to be within
+            // bounds when the root concrete SizedCollectorTask is constructed
+            // with the shared array
+            index = (int) offset;
+            fence = index + (int) length;
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfRef<P_IN, P_OUT>
+                extends SizedCollectorTask<P_IN, P_OUT, Sink<P_OUT>, OfRef<P_IN, P_OUT>>
+                implements Sink<P_OUT> {
+            private final P_OUT[] array;
+
+            OfRef(Spliterator<P_IN> spliterator, PipelineHelper<P_OUT> helper, P_OUT[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfRef(OfRef<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator,
+                  long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            OfRef<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator,
+                                         long offset, long size) {
+                return new OfRef<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(P_OUT value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfInt<P_IN>
+                extends SizedCollectorTask<P_IN, Integer, Sink.OfInt, OfInt<P_IN>>
+                implements Sink.OfInt {
+            private final int[] array;
+
+            OfInt(Spliterator<P_IN> spliterator, PipelineHelper<Integer> helper, int[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfInt(SizedCollectorTask.OfInt<P_IN> parent, Spliterator<P_IN> spliterator,
+                  long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            SizedCollectorTask.OfInt<P_IN> makeChild(Spliterator<P_IN> spliterator,
+                                                     long offset, long size) {
+                return new SizedCollectorTask.OfInt<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(int value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfLong<P_IN>
+                extends SizedCollectorTask<P_IN, Long, Sink.OfLong, OfLong<P_IN>>
+                implements Sink.OfLong {
+            private final long[] array;
+
+            OfLong(Spliterator<P_IN> spliterator, PipelineHelper<Long> helper, long[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfLong(SizedCollectorTask.OfLong<P_IN> parent, Spliterator<P_IN> spliterator,
+                   long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            SizedCollectorTask.OfLong<P_IN> makeChild(Spliterator<P_IN> spliterator,
+                                                      long offset, long size) {
+                return new SizedCollectorTask.OfLong<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(long value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfDouble<P_IN>
+                extends SizedCollectorTask<P_IN, Double, Sink.OfDouble, OfDouble<P_IN>>
+                implements Sink.OfDouble {
+            private final double[] array;
+
+            OfDouble(Spliterator<P_IN> spliterator, PipelineHelper<Double> helper, double[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfDouble(SizedCollectorTask.OfDouble<P_IN> parent, Spliterator<P_IN> spliterator,
+                     long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            SizedCollectorTask.OfDouble<P_IN> makeChild(Spliterator<P_IN> spliterator,
+                                                        long offset, long size) {
+                return new SizedCollectorTask.OfDouble<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(double value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    private static abstract class ToArrayTask<T, T_NODE extends Node<T>,
+                                              K extends ToArrayTask<T, T_NODE, K>>
+            extends CountedCompleter<Void> {
+        protected final T_NODE node;
+        protected final int offset;
+
+        ToArrayTask(T_NODE node, int offset) {
+            this.node = node;
+            this.offset = offset;
+        }
+
+        ToArrayTask(K parent, T_NODE node, int offset) {
+            super(parent);
+            this.node = node;
+            this.offset = offset;
+        }
+
+        abstract void copyNodeToArray();
+
+        abstract K makeChild(int childIndex, int offset);
+
+        @Override
+        public void compute() {
+            ToArrayTask<T, T_NODE, K> task = this;
+            while (true) {
+                if (task.node.getChildCount() == 0) {
+                    task.copyNodeToArray();
+                    task.propagateCompletion();
+                    return;
+                }
+                else {
+                    task.setPendingCount(task.node.getChildCount() - 1);
+
+                    int size = 0;
+                    int i = 0;
+                    for (;i < task.node.getChildCount() - 1; i++) {
+                        K leftTask = task.makeChild(i, task.offset + size);
+                        size += leftTask.node.count();
+                        leftTask.fork();
+                    }
+                    task = task.makeChild(i, task.offset + size);
+                }
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfRef<T>
+                extends ToArrayTask<T, Node<T>, OfRef<T>> {
+            private final T[] array;
+
+            private OfRef(Node<T> node, T[] array, int offset) {
+                super(node, offset);
+                this.array = array;
+            }
+
+            private OfRef(OfRef<T> parent, Node<T> node, int offset) {
+                super(parent, node, offset);
+                this.array = parent.array;
+            }
+
+            @Override
+            OfRef<T> makeChild(int childIndex, int offset) {
+                return new OfRef<>(this, node.getChild(childIndex), offset);
+            }
+
+            @Override
+            void copyNodeToArray() {
+                node.copyInto(array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static class OfPrimitive<T, T_CONS, T_ARR,
+                                         T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                                         T_NODE extends Node.OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>>
+                extends ToArrayTask<T, T_NODE, OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>> {
+            private final T_ARR array;
+
+            private OfPrimitive(T_NODE node, T_ARR array, int offset) {
+                super(node, offset);
+                this.array = array;
+            }
+
+            private OfPrimitive(OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE> parent, T_NODE node, int offset) {
+                super(parent, node, offset);
+                this.array = parent.array;
+            }
+
+            @Override
+            OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE> makeChild(int childIndex, int offset) {
+                return new OfPrimitive<>(this, node.getChild(childIndex), offset);
+            }
+
+            @Override
+            void copyNodeToArray() {
+                node.copyInto(array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt> {
+            private OfInt(Node.OfInt node, int[] array, int offset) {
+                super(node, array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong> {
+            private OfLong(Node.OfLong node, long[] array, int offset) {
+                super(node, array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble> {
+            private OfDouble(Node.OfDouble node, double[] array, int offset) {
+                super(node, array, offset);
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    private static class CollectorTask<P_IN, P_OUT, T_NODE extends Node<P_OUT>, T_BUILDER extends Node.Builder<P_OUT>>
+            extends AbstractTask<P_IN, P_OUT, T_NODE, CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER>> {
+        protected final PipelineHelper<P_OUT> helper;
+        protected final LongFunction<T_BUILDER> builderFactory;
+        protected final BinaryOperator<T_NODE> concFactory;
+
+        CollectorTask(PipelineHelper<P_OUT> helper,
+                      Spliterator<P_IN> spliterator,
+                      LongFunction<T_BUILDER> builderFactory,
+                      BinaryOperator<T_NODE> concFactory) {
+            super(helper, spliterator);
+            this.helper = helper;
+            this.builderFactory = builderFactory;
+            this.concFactory = concFactory;
+        }
+
+        CollectorTask(CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER> parent,
+                      Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            helper = parent.helper;
+            builderFactory = parent.builderFactory;
+            concFactory = parent.concFactory;
+        }
+
+        @Override
+        protected CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER> makeChild(Spliterator<P_IN> spliterator) {
+            return new CollectorTask<>(this, spliterator);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        protected T_NODE doLeaf() {
+            T_BUILDER builder = builderFactory.apply(helper.exactOutputSizeIfKnown(spliterator));
+            return (T_NODE) helper.wrapAndCopyInto(builder, spliterator).build();
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf())
+                setLocalResult(concFactory.apply(leftChild.getLocalResult(), rightChild.getLocalResult()));
+            super.onCompletion(caller);
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfRef<P_IN, P_OUT>
+                extends CollectorTask<P_IN, P_OUT, Node<P_OUT>, Node.Builder<P_OUT>> {
+            OfRef(PipelineHelper<P_OUT> helper,
+                  IntFunction<P_OUT[]> generator,
+                  Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, s -> builder(s, generator), ConcNode::new);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfInt<P_IN>
+                extends CollectorTask<P_IN, Integer, Node.OfInt, Node.Builder.OfInt> {
+            OfInt(PipelineHelper<Integer> helper, Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, Nodes::intBuilder, ConcNode.OfInt::new);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfLong<P_IN>
+                extends CollectorTask<P_IN, Long, Node.OfLong, Node.Builder.OfLong> {
+            OfLong(PipelineHelper<Long> helper, Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, Nodes::longBuilder, ConcNode.OfLong::new);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfDouble<P_IN>
+                extends CollectorTask<P_IN, Double, Node.OfDouble, Node.Builder.OfDouble> {
+            OfDouble(PipelineHelper<Double> helper, Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, Nodes::doubleBuilder, ConcNode.OfDouble::new);
+            }
+        }
+    }
+}
diff --git a/java/util/stream/OpTestCase.java b/java/util/stream/OpTestCase.java
new file mode 100644
index 0000000..331ac0e
--- /dev/null
+++ b/java/util/stream/OpTestCase.java
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import org.testng.annotations.Test;
+
+/**
+ * Base class for streams test cases.  Provides 'exercise' methods for taking
+ * lambdas that construct and modify streams, and evaluates them in different
+ * ways and asserts that they produce equivalent results.
+ */
+@Test
+public abstract class OpTestCase extends LoggingTestCase {
+
+    private final Map<StreamShape, Set<? extends BaseStreamTestScenario>> testScenarios;
+
+    protected OpTestCase() {
+        testScenarios = new EnumMap<>(StreamShape.class);
+        testScenarios.put(StreamShape.REFERENCE, Collections.unmodifiableSet(EnumSet.allOf(StreamTestScenario.class)));
+        testScenarios.put(StreamShape.INT_VALUE, Collections.unmodifiableSet(EnumSet.allOf(IntStreamTestScenario.class)));
+        testScenarios.put(StreamShape.LONG_VALUE, Collections.unmodifiableSet(EnumSet.allOf(LongStreamTestScenario.class)));
+        testScenarios.put(StreamShape.DOUBLE_VALUE, Collections.unmodifiableSet(EnumSet.allOf(DoubleStreamTestScenario.class)));
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static int getStreamFlags(BaseStream s) {
+        return ((AbstractPipeline) s).getStreamFlags();
+    }
+
+    /**
+     * An asserter for results produced when exercising of stream or terminal
+     * tests.
+     *
+     * @param <R> the type of result to assert on
+     */
+    public interface ResultAsserter<R> {
+        /**
+         * Assert a result produced when exercising of stream or terminal
+         * test.
+         *
+         * @param actual the actual result
+         * @param expected the expected result
+         * @param isOrdered true if the pipeline is ordered
+         * @param isParallel true if the pipeline is parallel
+         */
+        void assertResult(R actual, R expected, boolean isOrdered, boolean isParallel);
+    }
+
+    // Exercise stream operations
+
+    public interface BaseStreamTestScenario {
+        StreamShape getShape();
+
+        boolean isParallel();
+
+        boolean isOrdered();
+
+        <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+        void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m);
+    }
+
+    protected <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOps(TestData<T, S_IN> data, Function<S_IN, S_OUT> m) {
+        return withData(data).stream(m).exercise();
+    }
+
+    // Run multiple versions of exercise(), returning the result of the first, and asserting that others return the same result
+    // If the first version is s -> s.foo(), can be used with s -> s.mapToInt(i -> i).foo().mapToObj(i -> i) to test all shape variants
+    @SafeVarargs
+    protected final<T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOpsMulti(TestData<T, S_IN> data,
+                                   Function<S_IN, S_OUT>... ms) {
+        Collection<U> result = null;
+        for (Function<S_IN, S_OUT> m : ms) {
+            if (result == null)
+                result = withData(data).stream(m).exercise();
+            else {
+                Collection<U> r2 = withData(data).stream(m).exercise();
+                assertEquals(result, r2);
+            }
+        }
+        return result;
+    }
+
+    // Run multiple versions of exercise() for an Integer stream, returning the result of the first, and asserting that others return the same result
+    // Automates the conversion between Stream<Integer> and {Int,Long,Double}Stream and back, so client sites look like you are passing the same
+    // lambda four times, but in fact they are four different lambdas since they are transforming four different kinds of streams
+    protected final
+    Collection<Integer> exerciseOpsInt(TestData.OfRef<Integer> data,
+                                       Function<Stream<Integer>, Stream<Integer>> mRef,
+                                       Function<IntStream, IntStream> mInt,
+                                       Function<LongStream, LongStream> mLong,
+                                       Function<DoubleStream, DoubleStream> mDouble) {
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        Function<Stream<Integer>, Stream<Integer>>[] ms = new Function[4];
+        ms[0] = mRef;
+        ms[1] = s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e);
+        ms[2] = s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e);
+        ms[3] = s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e);
+        return exerciseOpsMulti(data, ms);
+    }
+
+    // Run multiple versions of exercise() with multiple terminal operations for all kinds of stream, , and asserting against the expected result
+    // If the first version is s -> s.foo(), can be used with s -> s.mapToInt(i -> i).foo().mapToObj(i -> i) to test all shape variants
+    protected final<T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void exerciseTerminalOpsMulti(TestData<T, S_IN> data,
+                                  R expected,
+                                  Map<String, Function<S_IN, S_OUT>> streams,
+                                  Map<String, Function<S_OUT, R>> terminals) {
+        for (Map.Entry<String, Function<S_IN, S_OUT>> se : streams.entrySet()) {
+            setContext("Intermediate stream", se.getKey());
+            for (Map.Entry<String, Function<S_OUT, R>> te : terminals.entrySet()) {
+                setContext("Terminal stream", te.getKey());
+                withData(data)
+                        .terminal(se.getValue(), te.getValue())
+                        .expectedResult(expected)
+                        .exercise();
+
+            }
+        }
+    }
+
+    // Run multiple versions of exercise() with multiple terminal operation for all kinds of stream, and asserting against the expected result
+    // Automates the conversion between Stream<Integer> and {Int,Long,Double}Stream and back, so client sites look like you are passing the same
+    // lambda four times, but in fact they are four different lambdas since they are transforming four different kinds of streams
+    protected final
+    void exerciseTerminalOpsInt(TestData<Integer, Stream<Integer>> data,
+                                Collection<Integer> expected,
+                                String desc,
+                                Function<Stream<Integer>, Stream<Integer>> mRef,
+                                Function<IntStream, IntStream> mInt,
+                                Function<LongStream, LongStream> mLong,
+                                Function<DoubleStream, DoubleStream> mDouble,
+                                Map<String, Function<Stream<Integer>, Collection<Integer>>> terminals) {
+
+        Map<String, Function<Stream<Integer>, Stream<Integer>>> m = new HashMap<>();
+        m.put("Ref " + desc, mRef);
+        m.put("Int " + desc, s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e));
+        m.put("Long " + desc, s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e));
+        m.put("Double " + desc, s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e));
+
+        exerciseTerminalOpsMulti(data, expected, m, terminals);
+    }
+
+
+    protected <T, U, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOps(Collection<T> data, Function<Stream<T>, S_OUT> m) {
+        TestData.OfRef<T> data1 = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+        return withData(data1).stream(m).exercise();
+    }
+
+    protected <T, U, S_OUT extends BaseStream<U, S_OUT>, I extends Iterable<U>>
+    Collection<U> exerciseOps(Collection<T> data, Function<Stream<T>, S_OUT> m, I expected) {
+        TestData.OfRef<T> data1 = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+        return withData(data1).stream(m).expectedResult(expected).exercise();
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <U, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOps(int[] data, Function<IntStream, S_OUT> m) {
+        return withData(TestData.Factory.ofArray("int array", data)).stream(m).exercise();
+    }
+
+    protected Collection<Integer> exerciseOps(int[] data, Function<IntStream, IntStream> m, int[] expected) {
+        TestData.OfInt data1 = TestData.Factory.ofArray("int array", data);
+        return withData(data1).stream(m).expectedResult(expected).exercise();
+    }
+
+    protected <T, S_IN extends BaseStream<T, S_IN>> DataStreamBuilder<T, S_IN> withData(TestData<T, S_IN> data) {
+        Objects.requireNonNull(data);
+        return new DataStreamBuilder<>(data);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public class DataStreamBuilder<T, S_IN extends BaseStream<T, S_IN>> {
+        final TestData<T, S_IN> data;
+
+        private DataStreamBuilder(TestData<T, S_IN> data) {
+            this.data = Objects.requireNonNull(data);
+        }
+
+        public <U, S_OUT extends BaseStream<U, S_OUT>>
+        ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> ops(IntermediateTestOp... ops) {
+            return new ExerciseDataStreamBuilder<>(data, (S_IN s) -> (S_OUT) chain(s, ops));
+        }
+
+        public <U, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT>
+        stream(Function<S_IN, S_OUT> m) {
+            return new ExerciseDataStreamBuilder<>(data, m);
+        }
+
+        public <U, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT>
+        stream(Function<S_IN, S_OUT> m, IntermediateTestOp<U, U> additionalOp) {
+            return new ExerciseDataStreamBuilder<>(data, s -> (S_OUT) chain(m.apply(s), additionalOp));
+        }
+
+        public <R> ExerciseDataTerminalBuilder<T, T, R, S_IN, S_IN>
+        terminal(Function<S_IN, R> terminalF) {
+            return new ExerciseDataTerminalBuilder<>(data, s -> s, terminalF);
+        }
+
+        public <U, R, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT>
+        terminal(Function<S_IN, S_OUT> streamF, Function<S_OUT, R> terminalF) {
+            return new ExerciseDataTerminalBuilder<>(data, streamF, terminalF);
+        }
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public class ExerciseDataStreamBuilder<T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> {
+        final TestData<T, S_IN> data;
+        final Function<S_IN, S_OUT> m;
+        final StreamShape shape;
+
+        Set<BaseStreamTestScenario> testSet = new HashSet<>();
+
+        Collection<U> refResult;
+
+        Consumer<TestData<T, S_IN>> before = LambdaTestHelpers.bEmpty;
+
+        Consumer<TestData<T, S_IN>> after = LambdaTestHelpers.bEmpty;
+
+        ResultAsserter<Iterable<U>> resultAsserter = (act, exp, ord, par) -> {
+            if (par & !ord) {
+                LambdaTestHelpers.assertContentsUnordered(act, exp);
+            }
+            else {
+                LambdaTestHelpers.assertContentsEqual(act, exp);
+            }
+        };
+
+        private ExerciseDataStreamBuilder(TestData<T, S_IN> data, Function<S_IN, S_OUT> m) {
+            this.data = data;
+
+            this.m = Objects.requireNonNull(m);
+
+            this.shape = ((AbstractPipeline<?, U, ?>) m.apply(data.stream())).getOutputShape();
+
+            // Have to initiate from the output shape of the last stream
+            // This means the stream mapper is required first rather than last
+            testSet.addAll(testScenarios.get(shape));
+        }
+
+        //
+
+        public <I extends Iterable<U>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(I expectedResult) {
+            List<U> l = new ArrayList<>();
+            expectedResult.forEach(l::add);
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(int[] expectedResult) {
+            List l = new ArrayList();
+            for (int anExpectedResult : expectedResult) {
+                l.add(anExpectedResult);
+            }
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(long[] expectedResult) {
+            List l = new ArrayList();
+            for (long anExpectedResult : expectedResult) {
+                l.add(anExpectedResult);
+            }
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(double[] expectedResult) {
+            List l = new ArrayList();
+            for (double anExpectedResult : expectedResult) {
+                l.add(anExpectedResult);
+            }
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> before(Consumer<TestData<T, S_IN>> before) {
+            this.before = Objects.requireNonNull(before);
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> after(Consumer<TestData<T, S_IN>> after) {
+            this.after = Objects.requireNonNull(after);
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> without(BaseStreamTestScenario... tests) {
+            return without(Arrays.asList(tests));
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> without(Collection<? extends BaseStreamTestScenario> tests) {
+            for (BaseStreamTestScenario ts : tests) {
+                if (ts.getShape() == shape) {
+                    testSet.remove(ts);
+                }
+            }
+
+            if (testSet.isEmpty()) {
+                throw new IllegalStateException("Test scenario set is empty");
+            }
+
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> with(BaseStreamTestScenario... tests) {
+            return with(Arrays.asList(tests));
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> with(Collection<? extends BaseStreamTestScenario> tests) {
+            testSet = new HashSet<>();
+
+            for (BaseStreamTestScenario ts : tests) {
+                if (ts.getShape() == shape) {
+                    testSet.add(ts);
+                }
+            }
+
+            if (testSet.isEmpty()) {
+                throw new IllegalStateException("Test scenario set is empty");
+            }
+
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> resultAsserter(ResultAsserter<Iterable<U>> resultAsserter) {
+            this.resultAsserter = resultAsserter;
+            return this;
+        }
+
+        // Build method
+
+        public Collection<U> exercise() {
+            final boolean isStreamOrdered;
+            if (refResult == null) {
+                // Induce the reference result
+                before.accept(data);
+                S_OUT sOut = m.apply(data.stream());
+                isStreamOrdered = StreamOpFlag.ORDERED.isKnown(((AbstractPipeline) sOut).getStreamFlags());
+                Node<U> refNodeResult = ((AbstractPipeline<?, U, ?>) sOut).evaluateToArrayNode(size -> (U[]) new Object[size]);
+                refResult = LambdaTestHelpers.toBoxedList(refNodeResult.spliterator());
+                after.accept(data);
+            }
+            else {
+                S_OUT sOut = m.apply(data.stream());
+                isStreamOrdered = StreamOpFlag.ORDERED.isKnown(((AbstractPipeline) sOut).getStreamFlags());
+            }
+
+            List<Error> errors = new ArrayList<>();
+            for (BaseStreamTestScenario test : testSet) {
+                try {
+                    before.accept(data);
+
+                    List<U> result = new ArrayList<>();
+                    test.run(data, LambdaTestHelpers.<U>toBoxingConsumer(result::add), m);
+
+                    Runnable asserter = () -> resultAsserter.assertResult(result, refResult, isStreamOrdered && test.isOrdered(), test.isParallel());
+
+                    if (refResult.size() > 1000) {
+                        LambdaTestHelpers.launderAssertion(
+                                asserter,
+                                () -> String.format("%n%s: [actual size=%d] != [expected size=%d]", test, result.size(), refResult.size()));
+                    }
+                    else {
+                        LambdaTestHelpers.launderAssertion(
+                                asserter,
+                                () -> String.format("%n%s: [actual] %s != [expected] %s", test, result, refResult));
+                    }
+
+                    after.accept(data);
+                } catch (Throwable t) {
+                    errors.add(new Error(String.format("%s: %s", test, t), t));
+                }
+            }
+
+            if (!errors.isEmpty()) {
+                StringBuilder sb = new StringBuilder();
+                int i = 1;
+                for (Error t : errors) {
+                    sb.append(i++).append(": ");
+                    if (t instanceof AssertionError) {
+                        sb.append(t).append("\n");
+                    }
+                    else {
+                        StringWriter sw = new StringWriter();
+                        PrintWriter pw = new PrintWriter(sw);
+
+                        t.getCause().printStackTrace(pw);
+                        pw.flush();
+                        sb.append(t).append("\n").append(sw);
+                    }
+                }
+                sb.append("--");
+
+                fail(String.format("%d failure(s) for test data: %s\n%s", i - 1, data.toString(), sb));
+            }
+
+            return refResult;
+        }
+    }
+
+    // Exercise terminal operations
+
+    interface BaseTerminalTestScenario<U, R, S_OUT extends BaseStream<U, S_OUT>> {
+        boolean requiresSingleStageSource();
+
+        boolean requiresParallelSource();
+
+        default R run(Function<S_OUT, R> terminalF, S_OUT source, StreamShape shape) {
+            return terminalF.apply(source);
+        }
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    enum TerminalTestScenario implements BaseTerminalTestScenario {
+        SINGLE_SEQUENTIAL(true, false),
+
+        SINGLE_SEQUENTIAL_SHORT_CIRCUIT(true, false) {
+            @Override
+            public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+                source = (BaseStream) chain(source, new ShortCircuitOp(shape));
+                return terminalF.apply(source);
+            }
+        },
+
+        SINGLE_PARALLEL(true, true),
+
+        ALL_SEQUENTIAL(false, false),
+
+        ALL_SEQUENTIAL_SHORT_CIRCUIT(false, false) {
+            @Override
+            public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+                source = (BaseStream) chain(source, new ShortCircuitOp(shape));
+                return terminalF.apply(source);
+            }
+        },
+
+        ALL_PARALLEL(false, true),
+
+        ALL_PARALLEL_SEQUENTIAL(false, false) {
+            @Override
+            public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+                return terminalF.apply(source.sequential());
+            }
+        },
+        ;
+
+        private final boolean requiresSingleStageSource;
+        private final boolean isParallel;
+
+        TerminalTestScenario(boolean requiresSingleStageSource, boolean isParallel) {
+            this.requiresSingleStageSource = requiresSingleStageSource;
+            this.isParallel = isParallel;
+        }
+
+        @Override
+        public boolean requiresSingleStageSource() {
+            return requiresSingleStageSource;
+        }
+
+        @Override
+        public boolean requiresParallelSource() {
+            return isParallel;
+        }
+
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public class ExerciseDataTerminalBuilder<T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> {
+        final TestData<T, S_IN> data;
+        final Function<S_IN, S_OUT> streamF;
+        final Function<S_OUT, R> terminalF;
+
+        R refResult;
+
+        ResultAsserter<R> resultAsserter = (act, exp, ord, par) -> LambdaTestHelpers.assertContentsEqual(act, exp);
+
+        private ExerciseDataTerminalBuilder(TestData<T, S_IN> data, Function<S_IN, S_OUT> streamF, Function<S_OUT, R> terminalF) {
+            this.data = data;
+            this.streamF = Objects.requireNonNull(streamF);
+            this.terminalF = Objects.requireNonNull(terminalF);
+        }
+
+        //
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> expectedResult(R expectedResult) {
+            this.refResult = expectedResult;
+            return this;
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> equalator(BiConsumer<R, R> equalityAsserter) {
+            resultAsserter = (act, exp, ord, par) -> equalityAsserter.accept(act, exp);
+            return this;
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> resultAsserter(ResultAsserter<R> resultAsserter) {
+            this.resultAsserter = resultAsserter;
+            return this;
+        }
+
+        // Build method
+
+        public R exercise() {
+            S_OUT out = streamF.apply(data.stream()).sequential();
+            AbstractPipeline ap = (AbstractPipeline) out;
+            boolean isOrdered = StreamOpFlag.ORDERED.isKnown(ap.getStreamFlags());
+            StreamShape shape = ap.getOutputShape();
+
+            EnumSet<TerminalTestScenario> tests = EnumSet.allOf(TerminalTestScenario.class);
+            // Sequentially collect the output that will be input to the terminal op
+            Node<U> node = ap.evaluateToArrayNode(size -> (U[]) new Object[size]);
+            if (refResult == null) {
+                // Induce the reference result
+                S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(),
+                                                      StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
+                                                      false);
+
+                refResult = (R) TerminalTestScenario.SINGLE_SEQUENTIAL.run(terminalF, source, shape);
+                tests.remove(TerminalTestScenario.SINGLE_SEQUENTIAL);
+            }
+
+            for (BaseTerminalTestScenario test : tests) {
+                S_OUT source;
+                if (test.requiresSingleStageSource()) {
+                    source = (S_OUT) createPipeline(shape, node.spliterator(),
+                                                    StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
+                                                    test.requiresParallelSource());
+                }
+                else {
+                    source = streamF.apply(test.requiresParallelSource()
+                                           ? data.parallelStream() : data.stream());
+                }
+
+                R result = (R) test.run(terminalF, source, shape);
+
+                LambdaTestHelpers.launderAssertion(
+                        () -> resultAsserter.assertResult(result, refResult, isOrdered, test.requiresParallelSource()),
+                        () -> String.format("%s: %s != %s", test, refResult, result));
+            }
+
+            return refResult;
+        }
+
+        AbstractPipeline createPipeline(StreamShape shape, Spliterator s, int flags, boolean parallel) {
+            switch (shape) {
+                case REFERENCE:    return new ReferencePipeline.Head<>(s, flags, parallel);
+                case INT_VALUE:    return new IntPipeline.Head(s, flags, parallel);
+                case LONG_VALUE:   return new LongPipeline.Head(s, flags, parallel);
+                case DOUBLE_VALUE: return new DoublePipeline.Head(s, flags, parallel);
+                default: throw new IllegalStateException("Unknown shape: " + shape);
+            }
+        }
+    }
+
+    protected <T, R> R exerciseTerminalOps(Collection<T> data, Function<Stream<T>, R> m, R expected) {
+        TestData.OfRef<T> data1
+                = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+        return withData(data1).terminal(m).expectedResult(expected).exercise();
+    }
+
+    protected <T, R, S_IN extends BaseStream<T, S_IN>> R
+    exerciseTerminalOps(TestData<T, S_IN> data,
+                        Function<S_IN, R> terminalF) {
+        return withData(data).terminal(terminalF).exercise();
+    }
+
+    protected <T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> R
+    exerciseTerminalOps(TestData<T, S_IN> data,
+                        Function<S_IN, S_OUT> streamF,
+                        Function<S_OUT, R> terminalF) {
+        return withData(data).terminal(streamF, terminalF).exercise();
+    }
+
+    //
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    private static <T> AbstractPipeline<?, T, ?> chain(AbstractPipeline upstream, IntermediateTestOp<?, T> op) {
+        return (AbstractPipeline<?, T, ?>) IntermediateTestOp.chain(upstream, op);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    private static AbstractPipeline<?, ?, ?> chain(AbstractPipeline pipe, IntermediateTestOp... ops) {
+        for (IntermediateTestOp op : ops)
+            pipe = chain(pipe, op);
+        return pipe;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static <T> AbstractPipeline<?, T, ?> chain(BaseStream pipe, IntermediateTestOp<?, T> op) {
+        return chain((AbstractPipeline) pipe, op);
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static AbstractPipeline<?, ?, ?> chain(BaseStream pipe, IntermediateTestOp... ops) {
+        return chain((AbstractPipeline) pipe, ops);
+    }
+
+    // Test data
+
+    static class ShortCircuitOp<T> implements StatelessTestOp<T,T> {
+        private final StreamShape shape;
+
+        ShortCircuitOp(StreamShape shape) {
+            this.shape = shape;
+        }
+
+        @Override
+        public Sink<T> opWrapSink(int flags, boolean parallel, Sink<T> sink) {
+            return sink;
+        }
+
+        @Override
+        public int opGetFlags() {
+            return StreamOpFlag.IS_SHORT_CIRCUIT;
+        }
+
+        @Override
+        public StreamShape outputShape() {
+            return shape;
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return shape;
+        }
+    }
+}
diff --git a/java/util/stream/PipelineHelper.java b/java/util/stream/PipelineHelper.java
new file mode 100644
index 0000000..832d68a
--- /dev/null
+++ b/java/util/stream/PipelineHelper.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+/**
+ * Helper class for executing <a href="package-summary.html#StreamOps">
+ * stream pipelines</a>, capturing all of the information about a stream
+ * pipeline (output shape, intermediate operations, stream flags, parallelism,
+ * etc) in one place.
+ *
+ * <p>
+ * A {@code PipelineHelper} describes the initial segment of a stream pipeline,
+ * including its source, intermediate operations, and may additionally
+ * incorporate information about the terminal (or stateful) operation which
+ * follows the last intermediate operation described by this
+ * {@code PipelineHelper}. The {@code PipelineHelper} is passed to the
+ * {@link TerminalOp#evaluateParallel(PipelineHelper, java.util.Spliterator)},
+ * {@link TerminalOp#evaluateSequential(PipelineHelper, java.util.Spliterator)},
+ * and {@link AbstractPipeline#opEvaluateParallel(PipelineHelper, java.util.Spliterator,
+ * java.util.function.IntFunction)}, methods, which can use the
+ * {@code PipelineHelper} to access information about the pipeline such as
+ * head shape, stream flags, and size, and use the helper methods
+ * such as {@link #wrapAndCopyInto(Sink, Spliterator)},
+ * {@link #copyInto(Sink, Spliterator)}, and {@link #wrapSink(Sink)} to execute
+ * pipeline operations.
+ *
+ * @param <P_OUT> type of output elements from the pipeline
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class PipelineHelper<P_OUT> {
+
+    /**
+     * Gets the stream shape for the source of the pipeline segment.
+     *
+     * @return the stream shape for the source of the pipeline segment.
+     */
+    abstract StreamShape getSourceShape();
+
+    /**
+     * Gets the combined stream and operation flags for the output of the described
+     * pipeline.  This will incorporate stream flags from the stream source, all
+     * the intermediate operations and the terminal operation.
+     *
+     * @return the combined stream and operation flags
+     * @see StreamOpFlag
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract int getStreamAndOpFlags();
+
+    /**
+     * Returns the exact output size of the portion of the output resulting from
+     * applying the pipeline stages described by this {@code PipelineHelper} to
+     * the the portion of the input described by the provided
+     * {@code Spliterator}, if known.  If not known or known infinite, will
+     * return {@code -1}.
+     *
+     * @apiNote
+     * The exact output size is known if the {@code Spliterator} has the
+     * {@code SIZED} characteristic, and the operation flags
+     * {@link StreamOpFlag#SIZED} is known on the combined stream and operation
+     * flags.
+     *
+     * @param spliterator the spliterator describing the relevant portion of the
+     *        source data
+     * @return the exact size if known, or -1 if infinite or unknown
+     */
+    abstract<P_IN> long exactOutputSizeIfKnown(Spliterator<P_IN> spliterator);
+
+    /**
+     * Applies the pipeline stages described by this {@code PipelineHelper} to
+     * the provided {@code Spliterator} and send the results to the provided
+     * {@code Sink}.
+     *
+     * @implSpec
+     * The implementation behaves as if:
+     * <pre>{@code
+     *     intoWrapped(wrapSink(sink), spliterator);
+     * }</pre>
+     *
+     * @param sink the {@code Sink} to receive the results
+     * @param spliterator the spliterator describing the source input to process
+     */
+    abstract<P_IN, S extends Sink<P_OUT>> S wrapAndCopyInto(S sink, Spliterator<P_IN> spliterator);
+
+    /**
+     * Pushes elements obtained from the {@code Spliterator} into the provided
+     * {@code Sink}.  If the stream pipeline is known to have short-circuiting
+     * stages in it (see {@link StreamOpFlag#SHORT_CIRCUIT}), the
+     * {@link Sink#cancellationRequested()} is checked after each
+     * element, stopping if cancellation is requested.
+     *
+     * @implSpec
+     * This method conforms to the {@code Sink} protocol of calling
+     * {@code Sink.begin} before pushing elements, via {@code Sink.accept}, and
+     * calling {@code Sink.end} after all elements have been pushed.
+     *
+     * @param wrappedSink the destination {@code Sink}
+     * @param spliterator the source {@code Spliterator}
+     */
+    abstract<P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator);
+
+    /**
+     * Pushes elements obtained from the {@code Spliterator} into the provided
+     * {@code Sink}, checking {@link Sink#cancellationRequested()} after each
+     * element, and stopping if cancellation is requested.
+     *
+     * @implSpec
+     * This method conforms to the {@code Sink} protocol of calling
+     * {@code Sink.begin} before pushing elements, via {@code Sink.accept}, and
+     * calling {@code Sink.end} after all elements have been pushed or if
+     * cancellation is requested.
+     *
+     * @param wrappedSink the destination {@code Sink}
+     * @param spliterator the source {@code Spliterator}
+     */
+    abstract <P_IN> void copyIntoWithCancel(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator);
+
+    /**
+     * Takes a {@code Sink} that accepts elements of the output type of the
+     * {@code PipelineHelper}, and wrap it with a {@code Sink} that accepts
+     * elements of the input type and implements all the intermediate operations
+     * described by this {@code PipelineHelper}, delivering the result into the
+     * provided {@code Sink}.
+     *
+     * @param sink the {@code Sink} to receive the results
+     * @return a {@code Sink} that implements the pipeline stages and sends
+     *         results to the provided {@code Sink}
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract<P_IN> Sink<P_IN> wrapSink(Sink<P_OUT> sink);
+
+    /**
+     *
+     * @param spliterator
+     * @param <P_IN>
+     * @return
+     */
+    abstract<P_IN> Spliterator<P_OUT> wrapSpliterator(Spliterator<P_IN> spliterator);
+
+    /**
+     * Constructs a @{link Node.Builder} compatible with the output shape of
+     * this {@code PipelineHelper}.
+     *
+     * @param exactSizeIfKnown if >=0 then a builder will be created that has a
+     *        fixed capacity of exactly sizeIfKnown elements; if < 0 then the
+     *        builder has variable capacity.  A fixed capacity builder will fail
+     *        if an element is added after the builder has reached capacity.
+     * @param generator a factory function for array instances
+     * @return a {@code Node.Builder} compatible with the output shape of this
+     *         {@code PipelineHelper}
+     */
+    abstract Node.Builder<P_OUT> makeNodeBuilder(long exactSizeIfKnown,
+                                                 IntFunction<P_OUT[]> generator);
+
+    /**
+     * Collects all output elements resulting from applying the pipeline stages
+     * to the source {@code Spliterator} into a {@code Node}.
+     *
+     * @implNote
+     * If the pipeline has no intermediate operations and the source is backed
+     * by a {@code Node} then that {@code Node} will be returned (or flattened
+     * and then returned). This reduces copying for a pipeline consisting of a
+     * stateful operation followed by a terminal operation that returns an
+     * array, such as:
+     * <pre>{@code
+     *     stream.sorted().toArray();
+     * }</pre>
+     *
+     * @param spliterator the source {@code Spliterator}
+     * @param flatten if true and the pipeline is a parallel pipeline then the
+     *        {@code Node} returned will contain no children, otherwise the
+     *        {@code Node} may represent the root in a tree that reflects the
+     *        shape of the computation tree.
+     * @param generator a factory function for array instances
+     * @return the {@code Node} containing all output elements
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract<P_IN> Node<P_OUT> evaluate(Spliterator<P_IN> spliterator,
+                                        boolean flatten,
+                                        IntFunction<P_OUT[]> generator);
+}
diff --git a/java/util/stream/ReduceOps.java b/java/util/stream/ReduceOps.java
new file mode 100644
index 0000000..3a0f81a
--- /dev/null
+++ b/java/util/stream/ReduceOps.java
@@ -0,0 +1,761 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.ObjDoubleConsumer;
+import java.util.function.ObjIntConsumer;
+import java.util.function.ObjLongConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Factory for creating instances of {@code TerminalOp} that implement
+ * reductions.
+ *
+ * @since 1.8
+ */
+final class ReduceOps {
+
+    private ReduceOps() { }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * reference values.
+     *
+     * @param <T> the type of the input elements
+     * @param <U> the type of the result
+     * @param seed the identity element for the reduction
+     * @param reducer the accumulating function that incorporates an additional
+     *        input element into the result
+     * @param combiner the combining function that combines two intermediate
+     *        results
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <T, U> TerminalOp<T, U>
+    makeRef(U seed, BiFunction<U, ? super T, U> reducer, BinaryOperator<U> combiner) {
+        Objects.requireNonNull(reducer);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<U> implements AccumulatingSink<T, U, ReducingSink> {
+            @Override
+            public void begin(long size) {
+                state = seed;
+            }
+
+            @Override
+            public void accept(T t) {
+                state = reducer.apply(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<T, U, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * reference values producing an optional reference result.
+     *
+     * @param <T> The type of the input elements, and the type of the result
+     * @param operator The reducing function
+     * @return A {@code TerminalOp} implementing the reduction
+     */
+    public static <T> TerminalOp<T, Optional<T>>
+    makeRef(BinaryOperator<T> operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<T, Optional<T>, ReducingSink> {
+            private boolean empty;
+            private T state;
+
+            public void begin(long size) {
+                empty = true;
+                state = null;
+            }
+
+            @Override
+            public void accept(T t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                } else {
+                    state = operator.apply(state, t);
+                }
+            }
+
+            @Override
+            public Optional<T> get() {
+                return empty ? Optional.empty() : Optional.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<T, Optional<T>, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * reference values.
+     *
+     * @param <T> the type of the input elements
+     * @param <I> the type of the intermediate reduction result
+     * @param collector a {@code Collector} defining the reduction
+     * @return a {@code ReduceOp} implementing the reduction
+     */
+    public static <T, I> TerminalOp<T, I>
+    makeRef(Collector<? super T, I, ?> collector) {
+        Supplier<I> supplier = Objects.requireNonNull(collector).supplier();
+        BiConsumer<I, ? super T> accumulator = collector.accumulator();
+        BinaryOperator<I> combiner = collector.combiner();
+        class ReducingSink extends Box<I>
+                implements AccumulatingSink<T, I, ReducingSink> {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(T t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<T, I, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+
+            @Override
+            public int getOpFlags() {
+                return collector.characteristics().contains(Collector.Characteristics.UNORDERED)
+                       ? StreamOpFlag.NOT_ORDERED
+                       : 0;
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * reference values.
+     *
+     * @param <T> the type of the input elements
+     * @param <R> the type of the result
+     * @param seedFactory a factory to produce a new base accumulator
+     * @param accumulator a function to incorporate an element into an
+     *        accumulator
+     * @param reducer a function to combine an accumulator into another
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <T, R> TerminalOp<T, R>
+    makeRef(Supplier<R> seedFactory,
+            BiConsumer<R, ? super T> accumulator,
+            BiConsumer<R,R> reducer) {
+        Objects.requireNonNull(seedFactory);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(reducer);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<T, R, ReducingSink> {
+            @Override
+            public void begin(long size) {
+                state = seedFactory.get();
+            }
+
+            @Override
+            public void accept(T t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                reducer.accept(state, other.state);
+            }
+        }
+        return new ReduceOp<T, R, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code int} values.
+     *
+     * @param identity the identity for the combining function
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Integer, Integer>
+    makeInt(int identity, IntBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Integer, Integer, ReducingSink>, Sink.OfInt {
+            private int state;
+
+            @Override
+            public void begin(long size) {
+                state = identity;
+            }
+
+            @Override
+            public void accept(int t) {
+                state = operator.applyAsInt(state, t);
+            }
+
+            @Override
+            public Integer get() {
+                return state;
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                accept(other.state);
+            }
+        }
+        return new ReduceOp<Integer, Integer, ReducingSink>(StreamShape.INT_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code int} values, producing an optional integer result.
+     *
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Integer, OptionalInt>
+    makeInt(IntBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Integer, OptionalInt, ReducingSink>, Sink.OfInt {
+            private boolean empty;
+            private int state;
+
+            public void begin(long size) {
+                empty = true;
+                state = 0;
+            }
+
+            @Override
+            public void accept(int t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                }
+                else {
+                    state = operator.applyAsInt(state, t);
+                }
+            }
+
+            @Override
+            public OptionalInt get() {
+                return empty ? OptionalInt.empty() : OptionalInt.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<Integer, OptionalInt, ReducingSink>(StreamShape.INT_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * {@code int} values.
+     *
+     * @param <R> The type of the result
+     * @param supplier a factory to produce a new accumulator of the result type
+     * @param accumulator a function to incorporate an int into an
+     *        accumulator
+     * @param combiner a function to combine an accumulator into another
+     * @return A {@code ReduceOp} implementing the reduction
+     */
+    public static <R> TerminalOp<Integer, R>
+    makeInt(Supplier<R> supplier,
+            ObjIntConsumer<R> accumulator,
+            BinaryOperator<R> combiner) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<Integer, R, ReducingSink>, Sink.OfInt {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(int t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<Integer, R, ReducingSink>(StreamShape.INT_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code long} values.
+     *
+     * @param identity the identity for the combining function
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Long, Long>
+    makeLong(long identity, LongBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Long, Long, ReducingSink>, Sink.OfLong {
+            private long state;
+
+            @Override
+            public void begin(long size) {
+                state = identity;
+            }
+
+            @Override
+            public void accept(long t) {
+                state = operator.applyAsLong(state, t);
+            }
+
+            @Override
+            public Long get() {
+                return state;
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                accept(other.state);
+            }
+        }
+        return new ReduceOp<Long, Long, ReducingSink>(StreamShape.LONG_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code long} values, producing an optional long result.
+     *
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Long, OptionalLong>
+    makeLong(LongBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Long, OptionalLong, ReducingSink>, Sink.OfLong {
+            private boolean empty;
+            private long state;
+
+            public void begin(long size) {
+                empty = true;
+                state = 0;
+            }
+
+            @Override
+            public void accept(long t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                }
+                else {
+                    state = operator.applyAsLong(state, t);
+                }
+            }
+
+            @Override
+            public OptionalLong get() {
+                return empty ? OptionalLong.empty() : OptionalLong.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<Long, OptionalLong, ReducingSink>(StreamShape.LONG_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * {@code long} values.
+     *
+     * @param <R> the type of the result
+     * @param supplier a factory to produce a new accumulator of the result type
+     * @param accumulator a function to incorporate an int into an
+     *        accumulator
+     * @param combiner a function to combine an accumulator into another
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <R> TerminalOp<Long, R>
+    makeLong(Supplier<R> supplier,
+             ObjLongConsumer<R> accumulator,
+             BinaryOperator<R> combiner) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<Long, R, ReducingSink>, Sink.OfLong {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(long t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<Long, R, ReducingSink>(StreamShape.LONG_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code double} values.
+     *
+     * @param identity the identity for the combining function
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Double, Double>
+    makeDouble(double identity, DoubleBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Double, Double, ReducingSink>, Sink.OfDouble {
+            private double state;
+
+            @Override
+            public void begin(long size) {
+                state = identity;
+            }
+
+            @Override
+            public void accept(double t) {
+                state = operator.applyAsDouble(state, t);
+            }
+
+            @Override
+            public Double get() {
+                return state;
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                accept(other.state);
+            }
+        }
+        return new ReduceOp<Double, Double, ReducingSink>(StreamShape.DOUBLE_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code double} values, producing an optional double result.
+     *
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Double, OptionalDouble>
+    makeDouble(DoubleBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Double, OptionalDouble, ReducingSink>, Sink.OfDouble {
+            private boolean empty;
+            private double state;
+
+            public void begin(long size) {
+                empty = true;
+                state = 0;
+            }
+
+            @Override
+            public void accept(double t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                }
+                else {
+                    state = operator.applyAsDouble(state, t);
+                }
+            }
+
+            @Override
+            public OptionalDouble get() {
+                return empty ? OptionalDouble.empty() : OptionalDouble.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<Double, OptionalDouble, ReducingSink>(StreamShape.DOUBLE_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * {@code double} values.
+     *
+     * @param <R> the type of the result
+     * @param supplier a factory to produce a new accumulator of the result type
+     * @param accumulator a function to incorporate an int into an
+     *        accumulator
+     * @param combiner a function to combine an accumulator into another
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <R> TerminalOp<Double, R>
+    makeDouble(Supplier<R> supplier,
+               ObjDoubleConsumer<R> accumulator,
+               BinaryOperator<R> combiner) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<Double, R, ReducingSink>, Sink.OfDouble {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(double t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<Double, R, ReducingSink>(StreamShape.DOUBLE_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * A type of {@code TerminalSink} that implements an associative reducing
+     * operation on elements of type {@code T} and producing a result of type
+     * {@code R}.
+     *
+     * @param <T> the type of input element to the combining operation
+     * @param <R> the result type
+     * @param <K> the type of the {@code AccumulatingSink}.
+     */
+    private interface AccumulatingSink<T, R, K extends AccumulatingSink<T, R, K>>
+            extends TerminalSink<T, R> {
+        public void combine(K other);
+    }
+
+    /**
+     * State box for a single state element, used as a base class for
+     * {@code AccumulatingSink} instances
+     *
+     * @param <U> The type of the state element
+     */
+    private static abstract class Box<U> {
+        U state;
+
+        Box() {} // Avoid creation of special accessor
+
+        public U get() {
+            return state;
+        }
+    }
+
+    /**
+     * A {@code TerminalOp} that evaluates a stream pipeline and sends the
+     * output into an {@code AccumulatingSink}, which performs a reduce
+     * operation. The {@code AccumulatingSink} must represent an associative
+     * reducing operation.
+     *
+     * @param <T> the output type of the stream pipeline
+     * @param <R> the result type of the reducing operation
+     * @param <S> the type of the {@code AccumulatingSink}
+     */
+    private static abstract class ReduceOp<T, R, S extends AccumulatingSink<T, R, S>>
+            implements TerminalOp<T, R> {
+        private final StreamShape inputShape;
+
+        /**
+         * Create a {@code ReduceOp} of the specified stream shape which uses
+         * the specified {@code Supplier} to create accumulating sinks.
+         *
+         * @param shape The shape of the stream pipeline
+         */
+        ReduceOp(StreamShape shape) {
+            inputShape = shape;
+        }
+
+        public abstract S makeSink();
+
+        @Override
+        public StreamShape inputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public <P_IN> R evaluateSequential(PipelineHelper<T> helper,
+                                           Spliterator<P_IN> spliterator) {
+            return helper.wrapAndCopyInto(makeSink(), spliterator).get();
+        }
+
+        @Override
+        public <P_IN> R evaluateParallel(PipelineHelper<T> helper,
+                                         Spliterator<P_IN> spliterator) {
+            return new ReduceTask<>(this, helper, spliterator).invoke().get();
+        }
+    }
+
+    /**
+     * A {@code ForkJoinTask} for performing a parallel reduce operation.
+     */
+    @SuppressWarnings("serial")
+    private static final class ReduceTask<P_IN, P_OUT, R,
+                                          S extends AccumulatingSink<P_OUT, R, S>>
+            extends AbstractTask<P_IN, P_OUT, S, ReduceTask<P_IN, P_OUT, R, S>> {
+        private final ReduceOp<P_OUT, R, S> op;
+
+        ReduceTask(ReduceOp<P_OUT, R, S> op,
+                   PipelineHelper<P_OUT> helper,
+                   Spliterator<P_IN> spliterator) {
+            super(helper, spliterator);
+            this.op = op;
+        }
+
+        ReduceTask(ReduceTask<P_IN, P_OUT, R, S> parent,
+                   Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+        }
+
+        @Override
+        protected ReduceTask<P_IN, P_OUT, R, S> makeChild(Spliterator<P_IN> spliterator) {
+            return new ReduceTask<>(this, spliterator);
+        }
+
+        @Override
+        protected S doLeaf() {
+            return helper.wrapAndCopyInto(op.makeSink(), spliterator);
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf()) {
+                S leftResult = leftChild.getLocalResult();
+                leftResult.combine(rightChild.getLocalResult());
+                setLocalResult(leftResult);
+            }
+            // GC spliterator, left and right child
+            super.onCompletion(caller);
+        }
+    }
+}
diff --git a/java/util/stream/ReferencePipeline.java b/java/util/stream/ReferencePipeline.java
new file mode 100644
index 0000000..84ec8c5
--- /dev/null
+++ b/java/util/stream/ReferencePipeline.java
@@ -0,0 +1,694 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code U}.
+ *
+ * @param <P_IN> type of elements in the upstream source
+ * @param <P_OUT> type of elements in produced by this stage
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class ReferencePipeline<P_IN, P_OUT>
+        extends AbstractPipeline<P_IN, P_OUT, Stream<P_OUT>>
+        implements Stream<P_OUT>  {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    ReferencePipeline(Supplier<? extends Spliterator<?>> source,
+                      int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    ReferencePipeline(Spliterator<?> source,
+                      int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing
+     * pipeline.
+     *
+     * @param upstream the upstream element source.
+     */
+    ReferencePipeline(AbstractPipeline<?, P_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.REFERENCE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<P_OUT> evaluateToNode(PipelineHelper<P_OUT> helper,
+                                        Spliterator<P_IN> spliterator,
+                                        boolean flattenTree,
+                                        IntFunction<P_OUT[]> generator) {
+        return Nodes.collect(helper, spliterator, flattenTree, generator);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<P_OUT> wrap(PipelineHelper<P_OUT> ph,
+                                     Supplier<Spliterator<P_IN>> supplier,
+                                     boolean isParallel) {
+        return new StreamSpliterators.WrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator<P_OUT> lazySpliterator(Supplier<? extends Spliterator<P_OUT>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator<>(supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final void forEachWithCancel(Spliterator<P_OUT> spliterator, Sink<P_OUT> sink) {
+        do { } while (!sink.cancellationRequested() && spliterator.tryAdvance(sink));
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<P_OUT> makeNodeBuilder(long exactSizeIfKnown, IntFunction<P_OUT[]> generator) {
+        return Nodes.builder(exactSizeIfKnown, generator);
+    }
+
+
+    // BaseStream
+
+    @Override
+    public final Iterator<P_OUT> iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+
+    // Stream
+
+    // Stateless intermediate operations from Stream
+
+    @Override
+    public Stream<P_OUT> unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
+                                     StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
+                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        if (predicate.test(u))
+                            downstream.accept(u);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            public Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
+                return new Sink.ChainedReference<P_OUT, R>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.apply(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream mapToInt(ToIntFunction<? super P_OUT> mapper) {
+        Objects.requireNonNull(mapper);
+        return new IntPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                              StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedReference<P_OUT, Integer>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.applyAsInt(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream mapToLong(ToLongFunction<? super P_OUT> mapper) {
+        Objects.requireNonNull(mapper);
+        return new LongPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                      StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedReference<P_OUT, Long>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.applyAsLong(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream mapToDouble(ToDoubleFunction<? super P_OUT> mapper) {
+        Objects.requireNonNull(mapper);
+        return new DoublePipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedReference<P_OUT, Double>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.applyAsDouble(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <R> Stream<R> flatMap(Function<? super P_OUT, ? extends Stream<? extends R>> mapper) {
+        Objects.requireNonNull(mapper);
+        // We can do better than this, by polling cancellationRequested when stream is infinite
+        return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            public Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
+                return new Sink.ChainedReference<P_OUT, R>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (Stream<? extends R> result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstream);
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream flatMapToInt(Function<? super P_OUT, ? extends IntStream> mapper) {
+        Objects.requireNonNull(mapper);
+        // We can do better than this, by polling cancellationRequested when stream is infinite
+        return new IntPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                              StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedReference<P_OUT, Integer>(sink) {
+                    IntConsumer downstreamAsInt = downstream::accept;
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (IntStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsInt);
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream flatMapToDouble(Function<? super P_OUT, ? extends DoubleStream> mapper) {
+        Objects.requireNonNull(mapper);
+        // We can do better than this, by polling cancellationRequested when stream is infinite
+        return new DoublePipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedReference<P_OUT, Double>(sink) {
+                    DoubleConsumer downstreamAsDouble = downstream::accept;
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (DoubleStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsDouble);
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream flatMapToLong(Function<? super P_OUT, ? extends LongStream> mapper) {
+        Objects.requireNonNull(mapper);
+        // We can do better than this, by polling cancellationRequested when stream is infinite
+        return new LongPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                                   StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedReference<P_OUT, Long>(sink) {
+                    LongConsumer downstreamAsLong = downstream::accept;
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (LongStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsLong);
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final Stream<P_OUT> peek(Consumer<? super P_OUT> action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
+                                     0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
+                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        action.accept(u);
+                        downstream.accept(u);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate operations from Stream
+
+    @Override
+    public final Stream<P_OUT> distinct() {
+        return DistinctOps.makeRef(this);
+    }
+
+    @Override
+    public final Stream<P_OUT> sorted() {
+        return SortedOps.makeRef(this);
+    }
+
+    @Override
+    public final Stream<P_OUT> sorted(Comparator<? super P_OUT> comparator) {
+        return SortedOps.makeRef(this, comparator);
+    }
+
+    @Override
+    public final Stream<P_OUT> limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeRef(this, 0, maxSize);
+    }
+
+    @Override
+    public final Stream<P_OUT> skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else
+            return SliceOps.makeRef(this, n, -1);
+    }
+
+    // Terminal operations from Stream
+
+    @Override
+    public void forEach(Consumer<? super P_OUT> action) {
+        evaluate(ForEachOps.makeRef(action, false));
+    }
+
+    @Override
+    public void forEachOrdered(Consumer<? super P_OUT> action) {
+        evaluate(ForEachOps.makeRef(action, true));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <A> A[] toArray(IntFunction<A[]> generator) {
+        // Since A has no relation to U (not possible to declare that A is an upper bound of U)
+        // there will be no static type checking.
+        // Therefore use a raw type and assume A == U rather than propagating the separation of A and U
+        // throughout the code-base.
+        // The runtime type of U is never checked for equality with the component type of the runtime type of A[].
+        // Runtime checking will be performed when an element is stored in A[], thus if A is not a
+        // super type of U an ArrayStoreException will be thrown.
+        @SuppressWarnings("rawtypes")
+        IntFunction rawGenerator = (IntFunction) generator;
+        // Android-changed: Eclipse compiler requires explicit (Node<A[]>) cast (b/29399275).
+        return (A[]) Nodes.flatten((Node<A[]>) evaluateToArrayNode(rawGenerator), rawGenerator)
+                .asArray(rawGenerator);
+    }
+
+    @Override
+    public final Object[] toArray() {
+        return toArray(Object[]::new);
+    }
+
+    @Override
+    public final boolean anyMatch(Predicate<? super P_OUT> predicate) {
+        return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(Predicate<? super P_OUT> predicate) {
+        return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(Predicate<? super P_OUT> predicate) {
+        return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final Optional<P_OUT> findFirst() {
+        return evaluate(FindOps.makeRef(true));
+    }
+
+    @Override
+    public final Optional<P_OUT> findAny() {
+        return evaluate(FindOps.makeRef(false));
+    }
+
+    @Override
+    public final P_OUT reduce(final P_OUT identity, final BinaryOperator<P_OUT> accumulator) {
+        return evaluate(ReduceOps.makeRef(identity, accumulator, accumulator));
+    }
+
+    @Override
+    public final Optional<P_OUT> reduce(BinaryOperator<P_OUT> accumulator) {
+        return evaluate(ReduceOps.makeRef(accumulator));
+    }
+
+    @Override
+    public final <R> R reduce(R identity, BiFunction<R, ? super P_OUT, R> accumulator, BinaryOperator<R> combiner) {
+        return evaluate(ReduceOps.makeRef(identity, accumulator, combiner));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
+        A container;
+        if (isParallel()
+                && (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
+                && (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) {
+            container = collector.supplier().get();
+            BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator();
+            forEach(u -> accumulator.accept(container, u));
+        }
+        else {
+            container = evaluate(ReduceOps.makeRef(collector));
+        }
+        return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
+               ? (R) container
+               : collector.finisher().apply(container);
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               BiConsumer<R, ? super P_OUT> accumulator,
+                               BiConsumer<R, R> combiner) {
+        return evaluate(ReduceOps.makeRef(supplier, accumulator, combiner));
+    }
+
+    @Override
+    public final Optional<P_OUT> max(Comparator<? super P_OUT> comparator) {
+        return reduce(BinaryOperator.maxBy(comparator));
+    }
+
+    @Override
+    public final Optional<P_OUT> min(Comparator<? super P_OUT> comparator) {
+        return reduce(BinaryOperator.minBy(comparator));
+
+    }
+
+    @Override
+    public final long count() {
+        return mapToLong(e -> 1L).sum();
+    }
+
+
+    //
+
+    /**
+     * Source stage of a ReferencePipeline.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @param <E_OUT> type of elements in produced by this stage
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN, E_OUT> extends ReferencePipeline<E_IN, E_OUT> {
+        /**
+         * Constructor for the source stage of a Stream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<?>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of a Stream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<?> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(Consumer<? super E_OUT> action) {
+            if (!isParallel()) {
+                sourceStageSpliterator().forEachRemaining(action);
+            }
+            else {
+                super.forEach(action);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(Consumer<? super E_OUT> action) {
+            if (!isParallel()) {
+                sourceStageSpliterator().forEachRemaining(action);
+            }
+            else {
+                super.forEachOrdered(action);
+            }
+        }
+    }
+
+    /**
+     * Base class for a stateless intermediate stage of a Stream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @param <E_OUT> type of elements in produced by this stage
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN, E_OUT>
+            extends ReferencePipeline<E_IN, E_OUT> {
+        /**
+         * Construct a new Stream by appending a stateless intermediate
+         * operation to an existing stream.
+         *
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of a Stream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @param <E_OUT> type of elements in produced by this stage
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN, E_OUT>
+            extends ReferencePipeline<E_IN, E_OUT> {
+        /**
+         * Construct a new Stream by appending a stateful intermediate operation
+         * to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<E_OUT> opEvaluateParallel(PipelineHelper<E_OUT> helper,
+                                                       Spliterator<P_IN> spliterator,
+                                                       IntFunction<E_OUT[]> generator);
+    }
+}
diff --git a/java/util/stream/Sink.java b/java/util/stream/Sink.java
new file mode 100644
index 0000000..2c5609c
--- /dev/null
+++ b/java/util/stream/Sink.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * An extension of {@link Consumer} used to conduct values through the stages of
+ * a stream pipeline, with additional methods to manage size information,
+ * control flow, etc.  Before calling the {@code accept()} method on a
+ * {@code Sink} for the first time, you must first call the {@code begin()}
+ * method to inform it that data is coming (optionally informing the sink how
+ * much data is coming), and after all data has been sent, you must call the
+ * {@code end()} method.  After calling {@code end()}, you should not call
+ * {@code accept()} without again calling {@code begin()}.  {@code Sink} also
+ * offers a mechanism by which the sink can cooperatively signal that it does
+ * not wish to receive any more data (the {@code cancellationRequested()}
+ * method), which a source can poll before sending more data to the
+ * {@code Sink}.
+ *
+ * <p>A sink may be in one of two states: an initial state and an active state.
+ * It starts out in the initial state; the {@code begin()} method transitions
+ * it to the active state, and the {@code end()} method transitions it back into
+ * the initial state, where it can be re-used.  Data-accepting methods (such as
+ * {@code accept()} are only valid in the active state.
+ *
+ * @apiNote
+ * A stream pipeline consists of a source, zero or more intermediate stages
+ * (such as filtering or mapping), and a terminal stage, such as reduction or
+ * for-each.  For concreteness, consider the pipeline:
+ *
+ * <pre>{@code
+ *     int longestStringLengthStartingWithA
+ *         = strings.stream()
+ *                  .filter(s -> s.startsWith("A"))
+ *                  .mapToInt(String::length)
+ *                  .max();
+ * }</pre>
+ *
+ * <p>Here, we have three stages, filtering, mapping, and reducing.  The
+ * filtering stage consumes strings and emits a subset of those strings; the
+ * mapping stage consumes strings and emits ints; the reduction stage consumes
+ * those ints and computes the maximal value.
+ *
+ * <p>A {@code Sink} instance is used to represent each stage of this pipeline,
+ * whether the stage accepts objects, ints, longs, or doubles.  Sink has entry
+ * points for {@code accept(Object)}, {@code accept(int)}, etc, so that we do
+ * not need a specialized interface for each primitive specialization.  (It
+ * might be called a "kitchen sink" for this omnivorous tendency.)  The entry
+ * point to the pipeline is the {@code Sink} for the filtering stage, which
+ * sends some elements "downstream" -- into the {@code Sink} for the mapping
+ * stage, which in turn sends integral values downstream into the {@code Sink}
+ * for the reduction stage. The {@code Sink} implementations associated with a
+ * given stage is expected to know the data type for the next stage, and call
+ * the correct {@code accept} method on its downstream {@code Sink}.  Similarly,
+ * each stage must implement the correct {@code accept} method corresponding to
+ * the data type it accepts.
+ *
+ * <p>The specialized subtypes such as {@link Sink.OfInt} override
+ * {@code accept(Object)} to call the appropriate primitive specialization of
+ * {@code accept}, implement the appropriate primitive specialization of
+ * {@code Consumer}, and re-abstract the appropriate primitive specialization of
+ * {@code accept}.
+ *
+ * <p>The chaining subtypes such as {@link ChainedInt} not only implement
+ * {@code Sink.OfInt}, but also maintain a {@code downstream} field which
+ * represents the downstream {@code Sink}, and implement the methods
+ * {@code begin()}, {@code end()}, and {@code cancellationRequested()} to
+ * delegate to the downstream {@code Sink}.  Most implementations of
+ * intermediate operations will use these chaining wrappers.  For example, the
+ * mapping stage in the above example would look like:
+ *
+ * <pre>{@code
+ *     IntSink is = new Sink.ChainedReference<U>(sink) {
+ *         public void accept(U u) {
+ *             downstream.accept(mapper.applyAsInt(u));
+ *         }
+ *     };
+ * }</pre>
+ *
+ * <p>Here, we implement {@code Sink.ChainedReference<U>}, meaning that we expect
+ * to receive elements of type {@code U} as input, and pass the downstream sink
+ * to the constructor.  Because the next stage expects to receive integers, we
+ * must call the {@code accept(int)} method when emitting values to the downstream.
+ * The {@code accept()} method applies the mapping function from {@code U} to
+ * {@code int} and passes the resulting value to the downstream {@code Sink}.
+ *
+ * @param <T> type of elements for value streams
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public interface Sink<T> extends Consumer<T> {
+    /**
+     * Resets the sink state to receive a fresh data set.  This must be called
+     * before sending any data to the sink.  After calling {@link #end()},
+     * you may call this method to reset the sink for another calculation.
+     * @param size The exact size of the data to be pushed downstream, if
+     * known or {@code -1} if unknown or infinite.
+     *
+     * <p>Prior to this call, the sink must be in the initial state, and after
+     * this call it is in the active state.
+     */
+    default void begin(long size) {}
+
+    /**
+     * Indicates that all elements have been pushed.  If the {@code Sink} is
+     * stateful, it should send any stored state downstream at this time, and
+     * should clear any accumulated state (and associated resources).
+     *
+     * <p>Prior to this call, the sink must be in the active state, and after
+     * this call it is returned to the initial state.
+     */
+    default void end() {}
+
+    /**
+     * Indicates that this {@code Sink} does not wish to receive any more data.
+     *
+     * @implSpec The default implementation always returns false.
+     *
+     * @return true if cancellation is requested
+     */
+    default boolean cancellationRequested() {
+        return false;
+    }
+
+    /**
+     * Accepts an int value.
+     *
+     * @implSpec The default implementation throws IllegalStateException.
+     *
+     * @throws IllegalStateException if this sink does not accept int values
+     */
+    default void accept(int value) {
+        throw new IllegalStateException("called wrong accept method");
+    }
+
+    /**
+     * Accepts a long value.
+     *
+     * @implSpec The default implementation throws IllegalStateException.
+     *
+     * @throws IllegalStateException if this sink does not accept long values
+     */
+    default void accept(long value) {
+        throw new IllegalStateException("called wrong accept method");
+    }
+
+    /**
+     * Accepts a double value.
+     *
+     * @implSpec The default implementation throws IllegalStateException.
+     *
+     * @throws IllegalStateException if this sink does not accept double values
+     */
+    default void accept(double value) {
+        throw new IllegalStateException("called wrong accept method");
+    }
+
+    /**
+     * {@code Sink} that implements {@code Sink<Integer>}, re-abstracts
+     * {@code accept(int)}, and wires {@code accept(Integer)} to bridge to
+     * {@code accept(int)}.
+     */
+    interface OfInt extends Sink<Integer>, IntConsumer {
+        @Override
+        void accept(int value);
+
+        @Override
+        default void accept(Integer i) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Sink.OfInt.accept(Integer)");
+            accept(i.intValue());
+        }
+    }
+
+    /**
+     * {@code Sink} that implements {@code Sink<Long>}, re-abstracts
+     * {@code accept(long)}, and wires {@code accept(Long)} to bridge to
+     * {@code accept(long)}.
+     */
+    interface OfLong extends Sink<Long>, LongConsumer {
+        @Override
+        void accept(long value);
+
+        @Override
+        default void accept(Long i) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Sink.OfLong.accept(Long)");
+            accept(i.longValue());
+        }
+    }
+
+    /**
+     * {@code Sink} that implements {@code Sink<Double>}, re-abstracts
+     * {@code accept(double)}, and wires {@code accept(Double)} to bridge to
+     * {@code accept(double)}.
+     */
+    interface OfDouble extends Sink<Double>, DoubleConsumer {
+        @Override
+        void accept(double value);
+
+        @Override
+        default void accept(Double i) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Sink.OfDouble.accept(Double)");
+            accept(i.doubleValue());
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink<T>}.  The
+     * implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    static abstract class ChainedReference<T, E_OUT> implements Sink<T> {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedReference(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation designed for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink.OfInt}.
+     * The implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    static abstract class ChainedInt<E_OUT> implements Sink.OfInt {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedInt(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation designed for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink.OfLong}.
+     * The implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    static abstract class ChainedLong<E_OUT> implements Sink.OfLong {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedLong(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation designed for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink.OfDouble}.
+     * The implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    static abstract class ChainedDouble<E_OUT> implements Sink.OfDouble {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedDouble(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+}
diff --git a/java/util/stream/SliceOps.java b/java/util/stream/SliceOps.java
new file mode 100644
index 0000000..6a6f85e
--- /dev/null
+++ b/java/util/stream/SliceOps.java
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.IntFunction;
+
+/**
+ * Factory for instances of a short-circuiting stateful intermediate operations
+ * that produce subsequences of their input stream.
+ *
+ * @since 1.8
+ */
+final class SliceOps {
+
+    // No instances
+    private SliceOps() { }
+
+    /**
+     * Calculates the sliced size given the current size, number of elements
+     * skip, and the number of elements to limit.
+     *
+     * @param size the current size
+     * @param skip the number of elements to skip, assumed to be >= 0
+     * @param limit the number of elements to limit, assumed to be >= 0, with
+     *        a value of {@code Long.MAX_VALUE} if there is no limit
+     * @return the sliced size
+     */
+    private static long calcSize(long size, long skip, long limit) {
+        return size >= 0 ? Math.max(-1, Math.min(size - skip, limit)) : -1;
+    }
+
+    /**
+     * Calculates the slice fence, which is one past the index of the slice
+     * range
+     * @param skip the number of elements to skip, assumed to be >= 0
+     * @param limit the number of elements to limit, assumed to be >= 0, with
+     *        a value of {@code Long.MAX_VALUE} if there is no limit
+     * @return the slice fence.
+     */
+    private static long calcSliceFence(long skip, long limit) {
+        long sliceFence = limit >= 0 ? skip + limit : Long.MAX_VALUE;
+        // Check for overflow
+        return (sliceFence >= 0) ? sliceFence : Long.MAX_VALUE;
+    }
+
+    /**
+     * Creates a slice spliterator given a stream shape governing the
+     * spliterator type.  Requires that the underlying Spliterator
+     * be SUBSIZED.
+     */
+    @SuppressWarnings("unchecked")
+    private static <P_IN> Spliterator<P_IN> sliceSpliterator(StreamShape shape,
+                                                             Spliterator<P_IN> s,
+                                                             long skip, long limit) {
+        assert s.hasCharacteristics(Spliterator.SUBSIZED);
+        long sliceFence = calcSliceFence(skip, limit);
+        switch (shape) {
+            case REFERENCE:
+                return new StreamSpliterators
+                        .SliceSpliterator.OfRef<>(s, skip, sliceFence);
+            case INT_VALUE:
+                return (Spliterator<P_IN>) new StreamSpliterators
+                        .SliceSpliterator.OfInt((Spliterator.OfInt) s, skip, sliceFence);
+            case LONG_VALUE:
+                return (Spliterator<P_IN>) new StreamSpliterators
+                        .SliceSpliterator.OfLong((Spliterator.OfLong) s, skip, sliceFence);
+            case DOUBLE_VALUE:
+                return (Spliterator<P_IN>) new StreamSpliterators
+                        .SliceSpliterator.OfDouble((Spliterator.OfDouble) s, skip, sliceFence);
+            default:
+                throw new IllegalStateException("Unknown shape " + shape);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> IntFunction<T[]> castingArray() {
+        return size -> (T[]) new Object[size];
+    }
+
+    /**
+     * Appends a "slice" operation to the provided stream.  The slice operation
+     * may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     * @param skip the number of elements to skip.  Must be >= 0.
+     * @param limit the maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
+                                        long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+
+        return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
+                                                      flags(limit)) {
+            Spliterator<T> unorderedSkipLimitSpliterator(Spliterator<T> s,
+                                                         long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfRef<>(
+                            helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    // @@@ OOMEs will occur for LongStream.longs().filter(i -> true).limit(n)
+                    //     regardless of the value of n
+                    //     Need to adjust the target size of splitting for the
+                    //     SliceTask from say (size / k) to say min(size / k, 1 << 14)
+                    //     This will limit the size of the buffers created at the leaf nodes
+                    //     cancellation will be more aggressive cancelling later tasks
+                    //     if the target slice size has been reached from a given task,
+                    //     cancellation should also clear local results if any
+                    return new SliceTask<>(this, helper, spliterator, castingArray(), skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                              Spliterator<P_IN> spliterator,
+                                              IntFunction<T[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collect(helper, s, true, generator);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator<T> s =  unorderedSkipLimitSpliterator(
+                            helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collect(this, s, true, generator);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<T> opWrapSink(int flags, Sink<T> sink) {
+                return new Sink.ChainedReference<T, T>(sink) {
+                    long n = skip;
+                    long m = limit >= 0 ? limit : Long.MAX_VALUE;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(T t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "slice" operation to the provided IntStream.  The slice
+     * operation may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param upstream An IntStream
+     * @param skip The number of elements to skip.  Must be >= 0.
+     * @param limit The maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static IntStream makeInt(AbstractPipeline<?, Integer, ?> upstream,
+                                    long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+
+        return new IntPipeline.StatefulOp<Integer>(upstream, StreamShape.INT_VALUE,
+                                                   flags(limit)) {
+            Spliterator.OfInt unorderedSkipLimitSpliterator(
+                    Spliterator.OfInt s, long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfInt(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
+                                                               Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfInt(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, Integer[]::new, skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    IntFunction<Integer[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collectInt(helper, s, true);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator.OfInt s =  unorderedSkipLimitSpliterator(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collectInt(this, s, true);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    long n = skip;
+                    long m = limit >= 0 ? limit : Long.MAX_VALUE;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(int t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "slice" operation to the provided LongStream.  The slice
+     * operation may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param upstream A LongStream
+     * @param skip The number of elements to skip.  Must be >= 0.
+     * @param limit The maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static LongStream makeLong(AbstractPipeline<?, Long, ?> upstream,
+                                      long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+
+        return new LongPipeline.StatefulOp<Long>(upstream, StreamShape.LONG_VALUE,
+                                                 flags(limit)) {
+            Spliterator.OfLong unorderedSkipLimitSpliterator(
+                    Spliterator.OfLong s, long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfLong(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
+                                                            Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfLong(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, Long[]::new, skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 IntFunction<Long[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collectLong(helper, s, true);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator.OfLong s =  unorderedSkipLimitSpliterator(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collectLong(this, s, true);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    long n = skip;
+                    long m = limit >= 0 ? limit : Long.MAX_VALUE;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(long t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "slice" operation to the provided DoubleStream.  The slice
+     * operation may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param upstream A DoubleStream
+     * @param skip The number of elements to skip.  Must be >= 0.
+     * @param limit The maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static DoubleStream makeDouble(AbstractPipeline<?, Double, ?> upstream,
+                                          long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+
+        return new DoublePipeline.StatefulOp<Double>(upstream, StreamShape.DOUBLE_VALUE,
+                                                     flags(limit)) {
+            Spliterator.OfDouble unorderedSkipLimitSpliterator(
+                    Spliterator.OfDouble s, long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfDouble(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
+                                                              Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfDouble(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, Double[]::new, skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                   Spliterator<P_IN> spliterator,
+                                                   IntFunction<Double[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collectDouble(helper, s, true);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator.OfDouble s =  unorderedSkipLimitSpliterator(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collectDouble(this, s, true);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    long n = skip;
+                    long m = limit >= 0 ? limit : Long.MAX_VALUE;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(double t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    private static int flags(long limit) {
+        return StreamOpFlag.NOT_SIZED | ((limit != -1) ? StreamOpFlag.IS_SHORT_CIRCUIT : 0);
+    }
+
+    /**
+     * {@code ForkJoinTask} implementing slice computation.
+     *
+     * @param <P_IN> Input element type to the stream pipeline
+     * @param <P_OUT> Output element type from the stream pipeline
+     */
+    @SuppressWarnings("serial")
+    private static final class SliceTask<P_IN, P_OUT>
+            extends AbstractShortCircuitTask<P_IN, P_OUT, Node<P_OUT>, SliceTask<P_IN, P_OUT>> {
+        private final AbstractPipeline<P_OUT, P_OUT, ?> op;
+        private final IntFunction<P_OUT[]> generator;
+        private final long targetOffset, targetSize;
+        private long thisNodeSize;
+
+        private volatile boolean completed;
+
+        SliceTask(AbstractPipeline<P_OUT, P_OUT, ?> op,
+                  PipelineHelper<P_OUT> helper,
+                  Spliterator<P_IN> spliterator,
+                  IntFunction<P_OUT[]> generator,
+                  long offset, long size) {
+            super(helper, spliterator);
+            this.op = op;
+            this.generator = generator;
+            this.targetOffset = offset;
+            this.targetSize = size;
+        }
+
+        SliceTask(SliceTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+            this.generator = parent.generator;
+            this.targetOffset = parent.targetOffset;
+            this.targetSize = parent.targetSize;
+        }
+
+        @Override
+        protected SliceTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) {
+            return new SliceTask<>(this, spliterator);
+        }
+
+        @Override
+        protected final Node<P_OUT> getEmptyResult() {
+            return Nodes.emptyNode(op.getOutputShape());
+        }
+
+        @Override
+        protected final Node<P_OUT> doLeaf() {
+            if (isRoot()) {
+                long sizeIfKnown = StreamOpFlag.SIZED.isPreserved(op.sourceOrOpFlags)
+                                   ? op.exactOutputSizeIfKnown(spliterator)
+                                   : -1;
+                final Node.Builder<P_OUT> nb = op.makeNodeBuilder(sizeIfKnown, generator);
+                Sink<P_OUT> opSink = op.opWrapSink(helper.getStreamAndOpFlags(), nb);
+                helper.copyIntoWithCancel(helper.wrapSink(opSink), spliterator);
+                // There is no need to truncate since the op performs the
+                // skipping and limiting of elements
+                return nb.build();
+            }
+            else {
+                Node<P_OUT> node = helper.wrapAndCopyInto(helper.makeNodeBuilder(-1, generator),
+                                                          spliterator).build();
+                thisNodeSize = node.count();
+                completed = true;
+                spliterator = null;
+                return node;
+            }
+        }
+
+        @Override
+        public final void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf()) {
+                Node<P_OUT> result;
+                thisNodeSize = leftChild.thisNodeSize + rightChild.thisNodeSize;
+                if (canceled) {
+                    thisNodeSize = 0;
+                    result = getEmptyResult();
+                }
+                else if (thisNodeSize == 0)
+                    result = getEmptyResult();
+                else if (leftChild.thisNodeSize == 0)
+                    result = rightChild.getLocalResult();
+                else {
+                    result = Nodes.conc(op.getOutputShape(),
+                                        leftChild.getLocalResult(), rightChild.getLocalResult());
+                }
+                setLocalResult(isRoot() ? doTruncate(result) : result);
+                completed = true;
+            }
+            if (targetSize >= 0
+                && !isRoot()
+                && isLeftCompleted(targetOffset + targetSize))
+                    cancelLaterNodes();
+
+            super.onCompletion(caller);
+        }
+
+        @Override
+        protected void cancel() {
+            super.cancel();
+            if (completed)
+                setLocalResult(getEmptyResult());
+        }
+
+        private Node<P_OUT> doTruncate(Node<P_OUT> input) {
+            long to = targetSize >= 0 ? Math.min(input.count(), targetOffset + targetSize) : thisNodeSize;
+            return input.truncate(targetOffset, to, generator);
+        }
+
+        /**
+         * Determine if the number of completed elements in this node and nodes
+         * to the left of this node is greater than or equal to the target size.
+         *
+         * @param target the target size
+         * @return true if the number of elements is greater than or equal to
+         *         the target size, otherwise false.
+         */
+        private boolean isLeftCompleted(long target) {
+            long size = completed ? thisNodeSize : completedSize(target);
+            if (size >= target)
+                return true;
+            for (SliceTask<P_IN, P_OUT> parent = getParent(), node = this;
+                 parent != null;
+                 node = parent, parent = parent.getParent()) {
+                if (node == parent.rightChild) {
+                    SliceTask<P_IN, P_OUT> left = parent.leftChild;
+                    if (left != null) {
+                        size += left.completedSize(target);
+                        if (size >= target)
+                            return true;
+                    }
+                }
+            }
+            return size >= target;
+        }
+
+        /**
+         * Compute the number of completed elements in this node.
+         * <p>
+         * Computation terminates if all nodes have been processed or the
+         * number of completed elements is greater than or equal to the target
+         * size.
+         *
+         * @param target the target size
+         * @return return the number of completed elements
+         */
+        private long completedSize(long target) {
+            if (completed)
+                return thisNodeSize;
+            else {
+                SliceTask<P_IN, P_OUT> left = leftChild;
+                SliceTask<P_IN, P_OUT> right = rightChild;
+                if (left == null || right == null) {
+                    // must be completed
+                    return thisNodeSize;
+                }
+                else {
+                    long leftSize = left.completedSize(target);
+                    return (leftSize >= target) ? leftSize : leftSize + right.completedSize(target);
+                }
+            }
+        }
+    }
+}
diff --git a/java/util/stream/SliceSpliteratorTest.java b/java/util/stream/SliceSpliteratorTest.java
new file mode 100644
index 0000000..7aa27bf
--- /dev/null
+++ b/java/util/stream/SliceSpliteratorTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Spliterator;
+
+import static java.util.stream.Collectors.toList;
+import static org.testng.Assert.assertEquals;
+
+/**
+ * @bug 8012987
+ */
+@Test
+public class SliceSpliteratorTest extends LoggingTestCase {
+
+    static class UnorderedContentAsserter<T> implements SpliteratorTestHelper.ContentAsserter<T> {
+        Collection<T> source;
+
+        UnorderedContentAsserter(Collection<T> source) {
+            this.source = source;
+        }
+
+        @Override
+        public void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {
+            if (isOrdered) {
+                assertEquals(actual, expected);
+            }
+            else {
+                assertEquals(actual.size(), expected.size());
+                assertTrue(source.containsAll(actual));
+            }
+        }
+    }
+
+    interface SliceTester {
+        void test(int size, int skip, int limit);
+    }
+
+    @DataProvider(name = "sliceSpliteratorDataProvider")
+    public static Object[][] sliceSpliteratorDataProvider() {
+        List<Object[]> data = new ArrayList<>();
+
+        // SIZED/SUBSIZED slice spliterator
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Integer> source =  IntStream.range(0, size).boxed().collect(toList());
+
+                SpliteratorTestHelper.testSpliterator(() -> {
+                    Spliterator<Integer> s = Arrays.spliterator(source.stream().toArray(Integer[]::new));
+
+                    return new StreamSpliterators.SliceSpliterator.OfRef<>(s, skip, limit);
+                });
+            };
+            data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfRef", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Integer> source =  IntStream.range(0, size).boxed().collect(toList());
+
+                SpliteratorTestHelper.testIntSpliterator(() -> {
+                    Spliterator.OfInt s = Arrays.spliterator(source.stream().mapToInt(i->i).toArray());
+
+                    return new StreamSpliterators.SliceSpliterator.OfInt(s, skip, limit);
+                });
+            };
+            data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfInt", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Long> source =  LongStream.range(0, size).boxed().collect(toList());
+
+                SpliteratorTestHelper.testLongSpliterator(() -> {
+                    Spliterator.OfLong s = Arrays.spliterator(source.stream().mapToLong(i->i).toArray());
+
+                    return new StreamSpliterators.SliceSpliterator.OfLong(s, skip, limit);
+                });
+            };
+            data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfLong", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Double> source =  LongStream.range(0, size).asDoubleStream().boxed().collect(toList());
+
+                SpliteratorTestHelper.testDoubleSpliterator(() -> {
+                    Spliterator.OfDouble s = Arrays.spliterator(source.stream().mapToDouble(i->i).toArray());
+
+                    return new StreamSpliterators.SliceSpliterator.OfDouble(s, skip, limit);
+                });
+            };
+            data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfLong", r});
+        }
+
+
+        // Unordered slice spliterator
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Integer> source =  IntStream.range(0, size).boxed().collect(toList());
+                final UnorderedContentAsserter<Integer> uca = new UnorderedContentAsserter<>(source);
+
+                SpliteratorTestHelper.testSpliterator(() -> {
+                    Spliterator<Integer> s = Arrays.spliterator(source.stream().toArray(Integer[]::new));
+
+                    return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
+                }, uca);
+            };
+            data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfRef", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Integer> source =  IntStream.range(0, size).boxed().collect(toList());
+                final UnorderedContentAsserter<Integer> uca = new UnorderedContentAsserter<>(source);
+
+                SpliteratorTestHelper.testIntSpliterator(() -> {
+                    Spliterator.OfInt s = Arrays.spliterator(source.stream().mapToInt(i->i).toArray());
+
+                    return new StreamSpliterators.UnorderedSliceSpliterator.OfInt(s, skip, limit);
+                }, uca);
+            };
+            data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfInt", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Long> source =  LongStream.range(0, size).boxed().collect(toList());
+                final UnorderedContentAsserter<Long> uca = new UnorderedContentAsserter<>(source);
+
+                SpliteratorTestHelper.testLongSpliterator(() -> {
+                    Spliterator.OfLong s = Arrays.spliterator(source.stream().mapToLong(i->i).toArray());
+
+                    return new StreamSpliterators.UnorderedSliceSpliterator.OfLong(s, skip, limit);
+                }, uca);
+            };
+            data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfLong", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Double> source =  LongStream.range(0, size).asDoubleStream().boxed().collect(toList());
+                final UnorderedContentAsserter<Double> uca = new UnorderedContentAsserter<>(source);
+
+                SpliteratorTestHelper.testDoubleSpliterator(() -> {
+                    Spliterator.OfDouble s = Arrays.spliterator(LongStream.range(0, SIZE).asDoubleStream().toArray());
+
+                    return new StreamSpliterators.UnorderedSliceSpliterator.OfDouble(s, skip, limit);
+                }, uca);
+            };
+            data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfLong", r});
+        }
+
+        return data.toArray(new Object[0][]);
+    }
+
+    static final int SIZE = 256;
+
+    static final int STEP = 32;
+
+    @Test(dataProvider = "sliceSpliteratorDataProvider")
+    public void testSliceSpliterator(String description, SliceTester r) {
+        setContext("size", SIZE);
+        for (int skip = 0; skip < SIZE; skip += STEP) {
+            setContext("skip", skip);
+            for (int limit = 0; limit < SIZE; limit += STEP) {
+                setContext("limit", skip);
+                r.test(SIZE, skip, limit);
+            }
+        }
+    }
+}
diff --git a/java/util/stream/SortedOps.java b/java/util/stream/SortedOps.java
new file mode 100644
index 0000000..592b609
--- /dev/null
+++ b/java/util/stream/SortedOps.java
@@ -0,0 +1,701 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+
+/**
+ * Factory methods for transforming streams into sorted streams.
+ *
+ * @since 1.8
+ */
+final class SortedOps {
+
+    private SortedOps() { }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream) {
+        return new OfRef<>(upstream);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     * @param comparator the comparator to order elements by
+     */
+    static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
+                                Comparator<? super T> comparator) {
+        return new OfRef<>(upstream, comparator);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> IntStream makeInt(AbstractPipeline<?, Integer, ?> upstream) {
+        return new OfInt(upstream);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> LongStream makeLong(AbstractPipeline<?, Long, ?> upstream) {
+        return new OfLong(upstream);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> DoubleStream makeDouble(AbstractPipeline<?, Double, ?> upstream) {
+        return new OfDouble(upstream);
+    }
+
+    /**
+     * Specialized subtype for sorting reference streams
+     */
+    private static final class OfRef<T> extends ReferencePipeline.StatefulOp<T, T> {
+        /**
+         * Comparator used for sorting
+         */
+        private final boolean isNaturalSort;
+        private final Comparator<? super T> comparator;
+
+        /**
+         * Sort using natural order of {@literal <T>} which must be
+         * {@code Comparable}.
+         */
+        OfRef(AbstractPipeline<?, T, ?> upstream) {
+            super(upstream, StreamShape.REFERENCE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+            this.isNaturalSort = true;
+            // Will throw CCE when we try to sort if T is not Comparable
+            @SuppressWarnings("unchecked")
+            Comparator<? super T> comp = (Comparator<? super T>) Comparator.naturalOrder();
+            this.comparator = comp;
+        }
+
+        /**
+         * Sort using the provided comparator.
+         *
+         * @param comparator The comparator to be used to evaluate ordering.
+         */
+        OfRef(AbstractPipeline<?, T, ?> upstream, Comparator<? super T> comparator) {
+            super(upstream, StreamShape.REFERENCE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.NOT_SORTED);
+            this.isNaturalSort = false;
+            this.comparator = Objects.requireNonNull(comparator);
+        }
+
+        @Override
+        public Sink<T> opWrapSink(int flags, Sink<T> sink) {
+            Objects.requireNonNull(sink);
+
+            // If the input is already naturally sorted and this operation
+            // also naturally sorted then this is a no-op
+            if (StreamOpFlag.SORTED.isKnown(flags) && isNaturalSort)
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedRefSortingSink<>(sink, comparator);
+            else
+                return new RefSortingSink<>(sink, comparator);
+        }
+
+        @Override
+        public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 IntFunction<T[]> generator) {
+            // If the input is already naturally sorted and this operation
+            // naturally sorts then collect the output
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags()) && isNaturalSort) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                // @@@ Weak two-pass parallel implementation; parallel collect, parallel sort
+                T[] flattenedData = helper.evaluate(spliterator, true, generator).asArray(generator);
+                Arrays.parallelSort(flattenedData, comparator);
+                return Nodes.node(flattenedData);
+            }
+        }
+    }
+
+    /**
+     * Specialized subtype for sorting int streams.
+     */
+    private static final class OfInt extends IntPipeline.StatefulOp<Integer> {
+        OfInt(AbstractPipeline<?, Integer, ?> upstream) {
+            super(upstream, StreamShape.INT_VALUE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+        }
+
+        @Override
+        public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+            Objects.requireNonNull(sink);
+
+            if (StreamOpFlag.SORTED.isKnown(flags))
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedIntSortingSink(sink);
+            else
+                return new IntSortingSink(sink);
+        }
+
+        @Override
+        public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                       Spliterator<P_IN> spliterator,
+                                                       IntFunction<Integer[]> generator) {
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                Node.OfInt n = (Node.OfInt) helper.evaluate(spliterator, true, generator);
+
+                int[] content = n.asPrimitiveArray();
+                Arrays.parallelSort(content);
+
+                return Nodes.node(content);
+            }
+        }
+    }
+
+    /**
+     * Specialized subtype for sorting long streams.
+     */
+    private static final class OfLong extends LongPipeline.StatefulOp<Long> {
+        OfLong(AbstractPipeline<?, Long, ?> upstream) {
+            super(upstream, StreamShape.LONG_VALUE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+        }
+
+        @Override
+        public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+            Objects.requireNonNull(sink);
+
+            if (StreamOpFlag.SORTED.isKnown(flags))
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedLongSortingSink(sink);
+            else
+                return new LongSortingSink(sink);
+        }
+
+        @Override
+        public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    IntFunction<Long[]> generator) {
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                Node.OfLong n = (Node.OfLong) helper.evaluate(spliterator, true, generator);
+
+                long[] content = n.asPrimitiveArray();
+                Arrays.parallelSort(content);
+
+                return Nodes.node(content);
+            }
+        }
+    }
+
+    /**
+     * Specialized subtype for sorting double streams.
+     */
+    private static final class OfDouble extends DoublePipeline.StatefulOp<Double> {
+        OfDouble(AbstractPipeline<?, Double, ?> upstream) {
+            super(upstream, StreamShape.DOUBLE_VALUE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+        }
+
+        @Override
+        public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+            Objects.requireNonNull(sink);
+
+            if (StreamOpFlag.SORTED.isKnown(flags))
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedDoubleSortingSink(sink);
+            else
+                return new DoubleSortingSink(sink);
+        }
+
+        @Override
+        public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      IntFunction<Double[]> generator) {
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                Node.OfDouble n = (Node.OfDouble) helper.evaluate(spliterator, true, generator);
+
+                double[] content = n.asPrimitiveArray();
+                Arrays.parallelSort(content);
+
+                return Nodes.node(content);
+            }
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on reference streams.
+     *
+     * <p>
+     * Note: documentation below applies to reference and all primitive sinks.
+     * <p>
+     * Sorting sinks first accept all elements, buffering then into an array
+     * or a re-sizable data structure, if the size of the pipeline is known or
+     * unknown respectively.  At the end of the sink protocol those elements are
+     * sorted and then pushed downstream.
+     * This class records if {@link #cancellationRequested} is called.  If so it
+     * can be inferred that the source pushing source elements into the pipeline
+     * knows that the pipeline is short-circuiting.  In such cases sub-classes
+     * pushing elements downstream will preserve the short-circuiting protocol
+     * by calling {@code downstream.cancellationRequested()} and checking the
+     * result is {@code false} before an element is pushed.
+     * <p>
+     * Note that the above behaviour is an optimization for sorting with
+     * sequential streams.  It is not an error that more elements, than strictly
+     * required to produce a result, may flow through the pipeline.  This can
+     * occur, in general (not restricted to just sorting), for short-circuiting
+     * parallel pipelines.
+     */
+    private static abstract class AbstractRefSortingSink<T> extends Sink.ChainedReference<T, T> {
+        protected final Comparator<? super T> comparator;
+        // @@@ could be a lazy final value, if/when support is added
+        protected boolean cancellationWasRequested;
+
+        AbstractRefSortingSink(Sink<? super T> downstream, Comparator<? super T> comparator) {
+            super(downstream);
+            this.comparator = comparator;
+        }
+
+        /**
+         * Records is cancellation is requested so short-circuiting behaviour
+         * can be preserved when the sorted elements are pushed downstream.
+         *
+         * @return false, as this sink never short-circuits.
+         */
+        @Override
+        public final boolean cancellationRequested() {
+            cancellationWasRequested = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED reference streams.
+     */
+    private static final class SizedRefSortingSink<T> extends AbstractRefSortingSink<T> {
+        private T[] array;
+        private int offset;
+
+        SizedRefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
+            super(sink, comparator);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = (T[]) new Object[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset, comparator);
+            downstream.begin(offset);
+            if (!cancellationWasRequested) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(T t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on reference streams.
+     */
+    private static final class RefSortingSink<T> extends AbstractRefSortingSink<T> {
+        private ArrayList<T> list;
+
+        RefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
+            super(sink, comparator);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            list = (size >= 0) ? new ArrayList<T>((int) size) : new ArrayList<T>();
+        }
+
+        @Override
+        public void end() {
+            list.sort(comparator);
+            downstream.begin(list.size());
+            if (!cancellationWasRequested) {
+                list.forEach(downstream::accept);
+            }
+            else {
+                for (T t : list) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(t);
+                }
+            }
+            downstream.end();
+            list = null;
+        }
+
+        @Override
+        public void accept(T t) {
+            list.add(t);
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on int streams.
+     */
+    private static abstract class AbstractIntSortingSink extends Sink.ChainedInt<Integer> {
+        protected boolean cancellationWasRequested;
+
+        AbstractIntSortingSink(Sink<? super Integer> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public final boolean cancellationRequested() {
+            cancellationWasRequested = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED int streams.
+     */
+    private static final class SizedIntSortingSink extends AbstractIntSortingSink {
+        private int[] array;
+        private int offset;
+
+        SizedIntSortingSink(Sink<? super Integer> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = new int[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset);
+            downstream.begin(offset);
+            if (!cancellationWasRequested) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(int t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on int streams.
+     */
+    private static final class IntSortingSink extends AbstractIntSortingSink {
+        private SpinedBuffer.OfInt b;
+
+        IntSortingSink(Sink<? super Integer> sink) {
+            super(sink);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            b = (size > 0) ? new SpinedBuffer.OfInt((int) size) : new SpinedBuffer.OfInt();
+        }
+
+        @Override
+        public void end() {
+            int[] ints = b.asPrimitiveArray();
+            Arrays.sort(ints);
+            downstream.begin(ints.length);
+            if (!cancellationWasRequested) {
+                for (int anInt : ints)
+                    downstream.accept(anInt);
+            }
+            else {
+                for (int anInt : ints) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(anInt);
+                }
+            }
+            downstream.end();
+        }
+
+        @Override
+        public void accept(int t) {
+            b.accept(t);
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on long streams.
+     */
+    private static abstract class AbstractLongSortingSink extends Sink.ChainedLong<Long> {
+        protected boolean cancellationWasRequested;
+
+        AbstractLongSortingSink(Sink<? super Long> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public final boolean cancellationRequested() {
+            cancellationWasRequested = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED long streams.
+     */
+    private static final class SizedLongSortingSink extends AbstractLongSortingSink {
+        private long[] array;
+        private int offset;
+
+        SizedLongSortingSink(Sink<? super Long> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = new long[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset);
+            downstream.begin(offset);
+            if (!cancellationWasRequested) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(long t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on long streams.
+     */
+    private static final class LongSortingSink extends AbstractLongSortingSink {
+        private SpinedBuffer.OfLong b;
+
+        LongSortingSink(Sink<? super Long> sink) {
+            super(sink);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            b = (size > 0) ? new SpinedBuffer.OfLong((int) size) : new SpinedBuffer.OfLong();
+        }
+
+        @Override
+        public void end() {
+            long[] longs = b.asPrimitiveArray();
+            Arrays.sort(longs);
+            downstream.begin(longs.length);
+            if (!cancellationWasRequested) {
+                for (long aLong : longs)
+                    downstream.accept(aLong);
+            }
+            else {
+                for (long aLong : longs) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(aLong);
+                }
+            }
+            downstream.end();
+        }
+
+        @Override
+        public void accept(long t) {
+            b.accept(t);
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on long streams.
+     */
+    private static abstract class AbstractDoubleSortingSink extends Sink.ChainedDouble<Double> {
+        protected boolean cancellationWasRequested;
+
+        AbstractDoubleSortingSink(Sink<? super Double> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public final boolean cancellationRequested() {
+            cancellationWasRequested = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED double streams.
+     */
+    private static final class SizedDoubleSortingSink extends AbstractDoubleSortingSink {
+        private double[] array;
+        private int offset;
+
+        SizedDoubleSortingSink(Sink<? super Double> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = new double[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset);
+            downstream.begin(offset);
+            if (!cancellationWasRequested) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(double t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on double streams.
+     */
+    private static final class DoubleSortingSink extends AbstractDoubleSortingSink {
+        private SpinedBuffer.OfDouble b;
+
+        DoubleSortingSink(Sink<? super Double> sink) {
+            super(sink);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            b = (size > 0) ? new SpinedBuffer.OfDouble((int) size) : new SpinedBuffer.OfDouble();
+        }
+
+        @Override
+        public void end() {
+            double[] doubles = b.asPrimitiveArray();
+            Arrays.sort(doubles);
+            downstream.begin(doubles.length);
+            if (!cancellationWasRequested) {
+                for (double aDouble : doubles)
+                    downstream.accept(aDouble);
+            }
+            else {
+                for (double aDouble : doubles) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(aDouble);
+                }
+            }
+            downstream.end();
+        }
+
+        @Override
+        public void accept(double t) {
+            b.accept(t);
+        }
+    }
+}
diff --git a/java/util/stream/SpinedBuffer.java b/java/util/stream/SpinedBuffer.java
new file mode 100644
index 0000000..d21518a
--- /dev/null
+++ b/java/util/stream/SpinedBuffer.java
@@ -0,0 +1,1077 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+
+/**
+ * An ordered collection of elements.  Elements can be added, but not removed.
+ * Goes through a building phase, during which elements can be added, and a
+ * traversal phase, during which elements can be traversed in order but no
+ * further modifications are possible.
+ *
+ * <p> One or more arrays are used to store elements. The use of a multiple
+ * arrays has better performance characteristics than a single array used by
+ * {@link ArrayList}, as when the capacity of the list needs to be increased
+ * no copying of elements is required.  This is usually beneficial in the case
+ * where the results will be traversed a small number of times.
+ *
+ * @param <E> the type of elements in this list
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public class SpinedBuffer<E>
+        extends AbstractSpinedBuffer
+        implements Consumer<E>, Iterable<E> {
+
+    /*
+     * We optimistically hope that all the data will fit into the first chunk,
+     * so we try to avoid inflating the spine[] and priorElementCount[] arrays
+     * prematurely.  So methods must be prepared to deal with these arrays being
+     * null.  If spine is non-null, then spineIndex points to the current chunk
+     * within the spine, otherwise it is zero.  The spine and priorElementCount
+     * arrays are always the same size, and for any i <= spineIndex,
+     * priorElementCount[i] is the sum of the sizes of all the prior chunks.
+     *
+     * The curChunk pointer is always valid.  The elementIndex is the index of
+     * the next element to be written in curChunk; this may be past the end of
+     * curChunk so we have to check before writing. When we inflate the spine
+     * array, curChunk becomes the first element in it.  When we clear the
+     * buffer, we discard all chunks except the first one, which we clear,
+     * restoring it to the initial single-chunk state.
+     */
+
+    /**
+     * Chunk that we're currently writing into; may or may not be aliased with
+     * the first element of the spine.
+     */
+    protected E[] curChunk;
+
+    /**
+     * All chunks, or null if there is only one chunk.
+     */
+    protected E[][] spine;
+
+    /**
+     * Constructs an empty list with the specified initial capacity.
+     *
+     * @param  initialCapacity  the initial capacity of the list
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public SpinedBuffer(int initialCapacity) {
+        super(initialCapacity);
+        curChunk = (E[]) new Object[1 << initialChunkPower];
+    }
+
+    /**
+     * Constructs an empty list with an initial capacity of sixteen.
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public SpinedBuffer() {
+        super();
+        curChunk = (E[]) new Object[1 << initialChunkPower];
+    }
+
+    /**
+     * Returns the current capacity of the buffer
+     */
+    protected long capacity() {
+        return (spineIndex == 0)
+               ? curChunk.length
+               : priorElementCount[spineIndex] + spine[spineIndex].length;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void inflateSpine() {
+        if (spine == null) {
+            spine = (E[][]) new Object[MIN_SPINE_SIZE][];
+            priorElementCount = new long[MIN_SPINE_SIZE];
+            spine[0] = curChunk;
+        }
+    }
+
+    /**
+     * Ensure that the buffer has at least capacity to hold the target size
+     */
+    @SuppressWarnings("unchecked")
+    protected final void ensureCapacity(long targetSize) {
+        long capacity = capacity();
+        if (targetSize > capacity) {
+            inflateSpine();
+            for (int i=spineIndex+1; targetSize > capacity; i++) {
+                if (i >= spine.length) {
+                    int newSpineSize = spine.length * 2;
+                    spine = Arrays.copyOf(spine, newSpineSize);
+                    priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize);
+                }
+                int nextChunkSize = chunkSize(i);
+                spine[i] = (E[]) new Object[nextChunkSize];
+                priorElementCount[i] = priorElementCount[i-1] + spine[i-1].length;
+                capacity += nextChunkSize;
+            }
+        }
+    }
+
+    /**
+     * Force the buffer to increase its capacity.
+     */
+    protected void increaseCapacity() {
+        ensureCapacity(capacity() + 1);
+    }
+
+    /**
+     * Retrieve the element at the specified index.
+     */
+    public E get(long index) {
+        // @@@ can further optimize by caching last seen spineIndex,
+        // which is going to be right most of the time
+
+        // Casts to int are safe since the spine array index is the index minus
+        // the prior element count from the current spine
+        if (spineIndex == 0) {
+            if (index < elementIndex)
+                return curChunk[((int) index)];
+            else
+                throw new IndexOutOfBoundsException(Long.toString(index));
+        }
+
+        if (index >= count())
+            throw new IndexOutOfBoundsException(Long.toString(index));
+
+        for (int j=0; j <= spineIndex; j++)
+            if (index < priorElementCount[j] + spine[j].length)
+                return spine[j][((int) (index - priorElementCount[j]))];
+
+        throw new IndexOutOfBoundsException(Long.toString(index));
+    }
+
+    /**
+     * Copy the elements, starting at the specified offset, into the specified
+     * array.
+     */
+    public void copyInto(E[] array, int offset) {
+        long finalOffset = offset + count();
+        if (finalOffset > array.length || finalOffset < offset) {
+            throw new IndexOutOfBoundsException("does not fit");
+        }
+
+        if (spineIndex == 0)
+            System.arraycopy(curChunk, 0, array, offset, elementIndex);
+        else {
+            // full chunks
+            for (int i=0; i < spineIndex; i++) {
+                System.arraycopy(spine[i], 0, array, offset, spine[i].length);
+                offset += spine[i].length;
+            }
+            if (elementIndex > 0)
+                System.arraycopy(curChunk, 0, array, offset, elementIndex);
+        }
+    }
+
+    /**
+     * Create a new array using the specified array factory, and copy the
+     * elements into it.
+     */
+    public E[] asArray(IntFunction<E[]> arrayFactory) {
+        long size = count();
+        if (size >= Nodes.MAX_ARRAY_SIZE)
+            throw new IllegalArgumentException(Nodes.BAD_SIZE);
+        E[] result = arrayFactory.apply((int) size);
+        copyInto(result, 0);
+        return result;
+    }
+
+    @Override
+    public void clear() {
+        if (spine != null) {
+            curChunk = spine[0];
+            for (int i=0; i<curChunk.length; i++)
+                curChunk[i] = null;
+            spine = null;
+            priorElementCount = null;
+        }
+        else {
+            for (int i=0; i<elementIndex; i++)
+                curChunk[i] = null;
+        }
+        elementIndex = 0;
+        spineIndex = 0;
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public void forEach(Consumer<? super E> consumer) {
+        // completed chunks, if any
+        for (int j = 0; j < spineIndex; j++)
+            for (E t : spine[j])
+                consumer.accept(t);
+
+        // current chunk
+        for (int i=0; i<elementIndex; i++)
+            consumer.accept(curChunk[i]);
+    }
+
+    @Override
+    public void accept(E e) {
+        if (elementIndex == curChunk.length) {
+            inflateSpine();
+            if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null)
+                increaseCapacity();
+            elementIndex = 0;
+            ++spineIndex;
+            curChunk = spine[spineIndex];
+        }
+        curChunk[elementIndex++] = e;
+    }
+
+    @Override
+    public String toString() {
+        List<E> list = new ArrayList<>();
+        forEach(list::add);
+        return "SpinedBuffer:" + list.toString();
+    }
+
+    private static final int SPLITERATOR_CHARACTERISTICS
+            = Spliterator.SIZED | Spliterator.ORDERED | Spliterator.SUBSIZED;
+
+    /**
+     * Return a {@link Spliterator} describing the contents of the buffer.
+     */
+    public Spliterator<E> spliterator() {
+        class Splitr implements Spliterator<E> {
+            // The current spine index
+            int splSpineIndex;
+
+            // Last spine index
+            final int lastSpineIndex;
+
+            // The current element index into the current spine
+            int splElementIndex;
+
+            // Last spine's last element index + 1
+            final int lastSpineElementFence;
+
+            // When splSpineIndex >= lastSpineIndex and
+            // splElementIndex >= lastSpineElementFence then
+            // this spliterator is fully traversed
+            // tryAdvance can set splSpineIndex > spineIndex if the last spine is full
+
+            // The current spine array
+            E[] splChunk;
+
+            Splitr(int firstSpineIndex, int lastSpineIndex,
+                   int firstSpineElementIndex, int lastSpineElementFence) {
+                this.splSpineIndex = firstSpineIndex;
+                this.lastSpineIndex = lastSpineIndex;
+                this.splElementIndex = firstSpineElementIndex;
+                this.lastSpineElementFence = lastSpineElementFence;
+                assert spine != null || firstSpineIndex == 0 && lastSpineIndex == 0;
+                splChunk = (spine == null) ? curChunk : spine[firstSpineIndex];
+            }
+
+            @Override
+            public long estimateSize() {
+                return (splSpineIndex == lastSpineIndex)
+                       ? (long) lastSpineElementFence - splElementIndex
+                       : // # of elements prior to end -
+                       priorElementCount[lastSpineIndex] + lastSpineElementFence -
+                       // # of elements prior to current
+                       priorElementCount[splSpineIndex] - splElementIndex;
+            }
+
+            @Override
+            public int characteristics() {
+                return SPLITERATOR_CHARACTERISTICS;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super E> consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    consumer.accept(splChunk[splElementIndex++]);
+
+                    if (splElementIndex == splChunk.length) {
+                        splElementIndex = 0;
+                        ++splSpineIndex;
+                        if (spine != null && splSpineIndex <= lastSpineIndex)
+                            splChunk = spine[splSpineIndex];
+                    }
+                    return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super E> consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    int i = splElementIndex;
+                    // completed chunks, if any
+                    for (int sp = splSpineIndex; sp < lastSpineIndex; sp++) {
+                        E[] chunk = spine[sp];
+                        for (; i < chunk.length; i++) {
+                            consumer.accept(chunk[i]);
+                        }
+                        i = 0;
+                    }
+                    // last (or current uncompleted) chunk
+                    E[] chunk = (splSpineIndex == lastSpineIndex) ? splChunk : spine[lastSpineIndex];
+                    int hElementIndex = lastSpineElementFence;
+                    for (; i < hElementIndex; i++) {
+                        consumer.accept(chunk[i]);
+                    }
+                    // mark consumed
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = lastSpineElementFence;
+                }
+            }
+
+            @Override
+            public Spliterator<E> trySplit() {
+                if (splSpineIndex < lastSpineIndex) {
+                    // split just before last chunk (if it is full this means 50:50 split)
+                    Spliterator<E> ret = new Splitr(splSpineIndex, lastSpineIndex - 1,
+                                                    splElementIndex, spine[lastSpineIndex-1].length);
+                    // position to start of last chunk
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = 0;
+                    splChunk = spine[splSpineIndex];
+                    return ret;
+                }
+                else if (splSpineIndex == lastSpineIndex) {
+                    int t = (lastSpineElementFence - splElementIndex) / 2;
+                    if (t == 0)
+                        return null;
+                    else {
+                        Spliterator<E> ret = Arrays.spliterator(splChunk, splElementIndex, splElementIndex + t);
+                        splElementIndex += t;
+                        return ret;
+                    }
+                }
+                else {
+                    return null;
+                }
+            }
+        }
+        return new Splitr(0, spineIndex, 0, elementIndex);
+    }
+
+    /**
+     * An ordered collection of primitive values.  Elements can be added, but
+     * not removed. Goes through a building phase, during which elements can be
+     * added, and a traversal phase, during which elements can be traversed in
+     * order but no further modifications are possible.
+     *
+     * <p> One or more arrays are used to store elements. The use of a multiple
+     * arrays has better performance characteristics than a single array used by
+     * {@link ArrayList}, as when the capacity of the list needs to be increased
+     * no copying of elements is required.  This is usually beneficial in the case
+     * where the results will be traversed a small number of times.
+     *
+     * @param <E> the wrapper type for this primitive type
+     * @param <T_ARR> the array type for this primitive type
+     * @param <T_CONS> the Consumer type for this primitive type
+     */
+    abstract static class OfPrimitive<E, T_ARR, T_CONS>
+            extends AbstractSpinedBuffer implements Iterable<E> {
+
+        /*
+         * We optimistically hope that all the data will fit into the first chunk,
+         * so we try to avoid inflating the spine[] and priorElementCount[] arrays
+         * prematurely.  So methods must be prepared to deal with these arrays being
+         * null.  If spine is non-null, then spineIndex points to the current chunk
+         * within the spine, otherwise it is zero.  The spine and priorElementCount
+         * arrays are always the same size, and for any i <= spineIndex,
+         * priorElementCount[i] is the sum of the sizes of all the prior chunks.
+         *
+         * The curChunk pointer is always valid.  The elementIndex is the index of
+         * the next element to be written in curChunk; this may be past the end of
+         * curChunk so we have to check before writing. When we inflate the spine
+         * array, curChunk becomes the first element in it.  When we clear the
+         * buffer, we discard all chunks except the first one, which we clear,
+         * restoring it to the initial single-chunk state.
+         */
+
+        // The chunk we're currently writing into
+        T_ARR curChunk;
+
+        // All chunks, or null if there is only one chunk
+        T_ARR[] spine;
+
+        /**
+         * Constructs an empty list with the specified initial capacity.
+         *
+         * @param  initialCapacity  the initial capacity of the list
+         * @throws IllegalArgumentException if the specified initial capacity
+         *         is negative
+         */
+        OfPrimitive(int initialCapacity) {
+            super(initialCapacity);
+            curChunk = newArray(1 << initialChunkPower);
+        }
+
+        /**
+         * Constructs an empty list with an initial capacity of sixteen.
+         */
+        OfPrimitive() {
+            super();
+            curChunk = newArray(1 << initialChunkPower);
+        }
+
+        @Override
+        public abstract Iterator<E> iterator();
+
+        @Override
+        public abstract void forEach(Consumer<? super E> consumer);
+
+        /** Create a new array-of-array of the proper type and size */
+        protected abstract T_ARR[] newArrayArray(int size);
+
+        /** Create a new array of the proper type and size */
+        public abstract T_ARR newArray(int size);
+
+        /** Get the length of an array */
+        protected abstract int arrayLength(T_ARR array);
+
+        /** Iterate an array with the provided consumer */
+        protected abstract void arrayForEach(T_ARR array, int from, int to,
+                                             T_CONS consumer);
+
+        protected long capacity() {
+            return (spineIndex == 0)
+                   ? arrayLength(curChunk)
+                   : priorElementCount[spineIndex] + arrayLength(spine[spineIndex]);
+        }
+
+        private void inflateSpine() {
+            if (spine == null) {
+                spine = newArrayArray(MIN_SPINE_SIZE);
+                priorElementCount = new long[MIN_SPINE_SIZE];
+                spine[0] = curChunk;
+            }
+        }
+
+        protected final void ensureCapacity(long targetSize) {
+            long capacity = capacity();
+            if (targetSize > capacity) {
+                inflateSpine();
+                for (int i=spineIndex+1; targetSize > capacity; i++) {
+                    if (i >= spine.length) {
+                        int newSpineSize = spine.length * 2;
+                        spine = Arrays.copyOf(spine, newSpineSize);
+                        priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize);
+                    }
+                    int nextChunkSize = chunkSize(i);
+                    spine[i] = newArray(nextChunkSize);
+                    priorElementCount[i] = priorElementCount[i-1] + arrayLength(spine[i - 1]);
+                    capacity += nextChunkSize;
+                }
+            }
+        }
+
+        protected void increaseCapacity() {
+            ensureCapacity(capacity() + 1);
+        }
+
+        protected int chunkFor(long index) {
+            if (spineIndex == 0) {
+                if (index < elementIndex)
+                    return 0;
+                else
+                    throw new IndexOutOfBoundsException(Long.toString(index));
+            }
+
+            if (index >= count())
+                throw new IndexOutOfBoundsException(Long.toString(index));
+
+            for (int j=0; j <= spineIndex; j++)
+                if (index < priorElementCount[j] + arrayLength(spine[j]))
+                    return j;
+
+            throw new IndexOutOfBoundsException(Long.toString(index));
+        }
+
+        public void copyInto(T_ARR array, int offset) {
+            long finalOffset = offset + count();
+            if (finalOffset > arrayLength(array) || finalOffset < offset) {
+                throw new IndexOutOfBoundsException("does not fit");
+            }
+
+            if (spineIndex == 0)
+                System.arraycopy(curChunk, 0, array, offset, elementIndex);
+            else {
+                // full chunks
+                for (int i=0; i < spineIndex; i++) {
+                    System.arraycopy(spine[i], 0, array, offset, arrayLength(spine[i]));
+                    offset += arrayLength(spine[i]);
+                }
+                if (elementIndex > 0)
+                    System.arraycopy(curChunk, 0, array, offset, elementIndex);
+            }
+        }
+
+        public T_ARR asPrimitiveArray() {
+            long size = count();
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            T_ARR result = newArray((int) size);
+            copyInto(result, 0);
+            return result;
+        }
+
+        protected void preAccept() {
+            if (elementIndex == arrayLength(curChunk)) {
+                inflateSpine();
+                if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null)
+                    increaseCapacity();
+                elementIndex = 0;
+                ++spineIndex;
+                curChunk = spine[spineIndex];
+            }
+        }
+
+        public void clear() {
+            if (spine != null) {
+                curChunk = spine[0];
+                spine = null;
+                priorElementCount = null;
+            }
+            elementIndex = 0;
+            spineIndex = 0;
+        }
+
+        @SuppressWarnings("overloads")
+        public void forEach(T_CONS consumer) {
+            // completed chunks, if any
+            for (int j = 0; j < spineIndex; j++)
+                arrayForEach(spine[j], 0, arrayLength(spine[j]), consumer);
+
+            // current chunk
+            arrayForEach(curChunk, 0, elementIndex, consumer);
+        }
+
+        abstract class BaseSpliterator<T_SPLITR extends Spliterator.OfPrimitive<E, T_CONS, T_SPLITR>>
+                implements Spliterator.OfPrimitive<E, T_CONS, T_SPLITR> {
+            // The current spine index
+            int splSpineIndex;
+
+            // Last spine index
+            final int lastSpineIndex;
+
+            // The current element index into the current spine
+            int splElementIndex;
+
+            // Last spine's last element index + 1
+            final int lastSpineElementFence;
+
+            // When splSpineIndex >= lastSpineIndex and
+            // splElementIndex >= lastSpineElementFence then
+            // this spliterator is fully traversed
+            // tryAdvance can set splSpineIndex > spineIndex if the last spine is full
+
+            // The current spine array
+            T_ARR splChunk;
+
+            BaseSpliterator(int firstSpineIndex, int lastSpineIndex,
+                            int firstSpineElementIndex, int lastSpineElementFence) {
+                this.splSpineIndex = firstSpineIndex;
+                this.lastSpineIndex = lastSpineIndex;
+                this.splElementIndex = firstSpineElementIndex;
+                this.lastSpineElementFence = lastSpineElementFence;
+                assert spine != null || firstSpineIndex == 0 && lastSpineIndex == 0;
+                splChunk = (spine == null) ? curChunk : spine[firstSpineIndex];
+            }
+
+            abstract T_SPLITR newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                             int firstSpineElementIndex, int lastSpineElementFence);
+
+            abstract void arrayForOne(T_ARR array, int index, T_CONS consumer);
+
+            abstract T_SPLITR arraySpliterator(T_ARR array, int offset, int len);
+
+            @Override
+            public long estimateSize() {
+                return (splSpineIndex == lastSpineIndex)
+                       ? (long) lastSpineElementFence - splElementIndex
+                       : // # of elements prior to end -
+                       priorElementCount[lastSpineIndex] + lastSpineElementFence -
+                       // # of elements prior to current
+                       priorElementCount[splSpineIndex] - splElementIndex;
+            }
+
+            @Override
+            public int characteristics() {
+                return SPLITERATOR_CHARACTERISTICS;
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    arrayForOne(splChunk, splElementIndex++, consumer);
+
+                    if (splElementIndex == arrayLength(splChunk)) {
+                        splElementIndex = 0;
+                        ++splSpineIndex;
+                        if (spine != null && splSpineIndex <= lastSpineIndex)
+                            splChunk = spine[splSpineIndex];
+                    }
+                    return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    int i = splElementIndex;
+                    // completed chunks, if any
+                    for (int sp = splSpineIndex; sp < lastSpineIndex; sp++) {
+                        T_ARR chunk = spine[sp];
+                        arrayForEach(chunk, i, arrayLength(chunk), consumer);
+                        i = 0;
+                    }
+                    // last (or current uncompleted) chunk
+                    T_ARR chunk = (splSpineIndex == lastSpineIndex) ? splChunk : spine[lastSpineIndex];
+                    arrayForEach(chunk, i, lastSpineElementFence, consumer);
+                    // mark consumed
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = lastSpineElementFence;
+                }
+            }
+
+            @Override
+            public T_SPLITR trySplit() {
+                if (splSpineIndex < lastSpineIndex) {
+                    // split just before last chunk (if it is full this means 50:50 split)
+                    T_SPLITR ret = newSpliterator(splSpineIndex, lastSpineIndex - 1,
+                                                  splElementIndex, arrayLength(spine[lastSpineIndex - 1]));
+                    // position us to start of last chunk
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = 0;
+                    splChunk = spine[splSpineIndex];
+                    return ret;
+                }
+                else if (splSpineIndex == lastSpineIndex) {
+                    int t = (lastSpineElementFence - splElementIndex) / 2;
+                    if (t == 0)
+                        return null;
+                    else {
+                        T_SPLITR ret = arraySpliterator(splChunk, splElementIndex, t);
+                        splElementIndex += t;
+                        return ret;
+                    }
+                }
+                else {
+                    return null;
+                }
+            }
+        }
+    }
+
+    /**
+     * An ordered collection of {@code int} values.
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class OfInt extends SpinedBuffer.OfPrimitive<Integer, int[], IntConsumer>
+            implements IntConsumer {
+        // Android-changed: Made public for CTS tests only.
+        public OfInt() { }
+
+        // Android-changed: Made public for CTS tests only.
+        public OfInt(int initialCapacity) {
+            super(initialCapacity);
+        }
+
+        @Override
+        public void forEach(Consumer<? super Integer> consumer) {
+            if (consumer instanceof IntConsumer) {
+                forEach((IntConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfInt.forEach(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        @Override
+        protected int[][] newArrayArray(int size) {
+            return new int[size][];
+        }
+
+        @Override
+        public int[] newArray(int size) {
+            return new int[size];
+        }
+
+        @Override
+        protected int arrayLength(int[] array) {
+            return array.length;
+        }
+
+        @Override
+        protected void arrayForEach(int[] array,
+                                    int from, int to,
+                                    IntConsumer consumer) {
+            for (int i = from; i < to; i++)
+                consumer.accept(array[i]);
+        }
+
+        @Override
+        public void accept(int i) {
+            preAccept();
+            curChunk[elementIndex++] = i;
+        }
+
+        public int get(long index) {
+            // Casts to int are safe since the spine array index is the index minus
+            // the prior element count from the current spine
+            int ch = chunkFor(index);
+            if (spineIndex == 0 && ch == 0)
+                return curChunk[(int) index];
+            else
+                return spine[ch][(int) (index - priorElementCount[ch])];
+        }
+
+        @Override
+        public PrimitiveIterator.OfInt iterator() {
+            return Spliterators.iterator(spliterator());
+        }
+
+        public Spliterator.OfInt spliterator() {
+            class Splitr extends BaseSpliterator<Spliterator.OfInt>
+                    implements Spliterator.OfInt {
+                Splitr(int firstSpineIndex, int lastSpineIndex,
+                       int firstSpineElementIndex, int lastSpineElementFence) {
+                    super(firstSpineIndex, lastSpineIndex,
+                          firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                Splitr newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                      int firstSpineElementIndex, int lastSpineElementFence) {
+                    return new Splitr(firstSpineIndex, lastSpineIndex,
+                                      firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                void arrayForOne(int[] array, int index, IntConsumer consumer) {
+                    consumer.accept(array[index]);
+                }
+
+                @Override
+                Spliterator.OfInt arraySpliterator(int[] array, int offset, int len) {
+                    return Arrays.spliterator(array, offset, offset+len);
+                }
+            }
+            return new Splitr(0, spineIndex, 0, elementIndex);
+        }
+
+        @Override
+        public String toString() {
+            int[] array = asPrimitiveArray();
+            if (array.length < 200) {
+                return String.format("%s[length=%d, chunks=%d]%s",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array));
+            }
+            else {
+                int[] array2 = Arrays.copyOf(array, 200);
+                return String.format("%s[length=%d, chunks=%d]%s...",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array2));
+            }
+        }
+    }
+
+    /**
+     * An ordered collection of {@code long} values.
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class OfLong extends SpinedBuffer.OfPrimitive<Long, long[], LongConsumer>
+            implements LongConsumer {
+        // Android-changed: Made public for CTS tests only.
+        public OfLong() { }
+
+        // Android-changed: Made public for CTS tests only.
+        public OfLong(int initialCapacity) {
+            super(initialCapacity);
+        }
+
+        @Override
+        public void forEach(Consumer<? super Long> consumer) {
+            if (consumer instanceof LongConsumer) {
+                forEach((LongConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfLong.forEach(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        @Override
+        protected long[][] newArrayArray(int size) {
+            return new long[size][];
+        }
+
+        @Override
+        public long[] newArray(int size) {
+            return new long[size];
+        }
+
+        @Override
+        protected int arrayLength(long[] array) {
+            return array.length;
+        }
+
+        @Override
+        protected void arrayForEach(long[] array,
+                                    int from, int to,
+                                    LongConsumer consumer) {
+            for (int i = from; i < to; i++)
+                consumer.accept(array[i]);
+        }
+
+        @Override
+        public void accept(long i) {
+            preAccept();
+            curChunk[elementIndex++] = i;
+        }
+
+        public long get(long index) {
+            // Casts to int are safe since the spine array index is the index minus
+            // the prior element count from the current spine
+            int ch = chunkFor(index);
+            if (spineIndex == 0 && ch == 0)
+                return curChunk[(int) index];
+            else
+                return spine[ch][(int) (index - priorElementCount[ch])];
+        }
+
+        @Override
+        public PrimitiveIterator.OfLong iterator() {
+            return Spliterators.iterator(spliterator());
+        }
+
+
+        public Spliterator.OfLong spliterator() {
+            class Splitr extends BaseSpliterator<Spliterator.OfLong>
+                    implements Spliterator.OfLong {
+                Splitr(int firstSpineIndex, int lastSpineIndex,
+                       int firstSpineElementIndex, int lastSpineElementFence) {
+                    super(firstSpineIndex, lastSpineIndex,
+                          firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                Splitr newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                      int firstSpineElementIndex, int lastSpineElementFence) {
+                    return new Splitr(firstSpineIndex, lastSpineIndex,
+                                      firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                void arrayForOne(long[] array, int index, LongConsumer consumer) {
+                    consumer.accept(array[index]);
+                }
+
+                @Override
+                Spliterator.OfLong arraySpliterator(long[] array, int offset, int len) {
+                    return Arrays.spliterator(array, offset, offset+len);
+                }
+            }
+            return new Splitr(0, spineIndex, 0, elementIndex);
+        }
+
+        @Override
+        public String toString() {
+            long[] array = asPrimitiveArray();
+            if (array.length < 200) {
+                return String.format("%s[length=%d, chunks=%d]%s",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array));
+            }
+            else {
+                long[] array2 = Arrays.copyOf(array, 200);
+                return String.format("%s[length=%d, chunks=%d]%s...",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array2));
+            }
+        }
+    }
+
+    /**
+     * An ordered collection of {@code double} values.
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class OfDouble
+            extends SpinedBuffer.OfPrimitive<Double, double[], DoubleConsumer>
+            implements DoubleConsumer {
+        // Android-changed: Made public for CTS tests only.
+        public OfDouble() { }
+
+        // Android-changed: Made public for CTS tests only.
+        public OfDouble(int initialCapacity) {
+            super(initialCapacity);
+        }
+
+        @Override
+        public void forEach(Consumer<? super Double> consumer) {
+            if (consumer instanceof DoubleConsumer) {
+                forEach((DoubleConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfDouble.forEach(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        @Override
+        protected double[][] newArrayArray(int size) {
+            return new double[size][];
+        }
+
+        @Override
+        public double[] newArray(int size) {
+            return new double[size];
+        }
+
+        @Override
+        protected int arrayLength(double[] array) {
+            return array.length;
+        }
+
+        @Override
+        protected void arrayForEach(double[] array,
+                                    int from, int to,
+                                    DoubleConsumer consumer) {
+            for (int i = from; i < to; i++)
+                consumer.accept(array[i]);
+        }
+
+        @Override
+        public void accept(double i) {
+            preAccept();
+            curChunk[elementIndex++] = i;
+        }
+
+        public double get(long index) {
+            // Casts to int are safe since the spine array index is the index minus
+            // the prior element count from the current spine
+            int ch = chunkFor(index);
+            if (spineIndex == 0 && ch == 0)
+                return curChunk[(int) index];
+            else
+                return spine[ch][(int) (index - priorElementCount[ch])];
+        }
+
+        @Override
+        public PrimitiveIterator.OfDouble iterator() {
+            return Spliterators.iterator(spliterator());
+        }
+
+        public Spliterator.OfDouble spliterator() {
+            class Splitr extends BaseSpliterator<Spliterator.OfDouble>
+                    implements Spliterator.OfDouble {
+                Splitr(int firstSpineIndex, int lastSpineIndex,
+                       int firstSpineElementIndex, int lastSpineElementFence) {
+                    super(firstSpineIndex, lastSpineIndex,
+                          firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                Splitr newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                      int firstSpineElementIndex, int lastSpineElementFence) {
+                    return new Splitr(firstSpineIndex, lastSpineIndex,
+                                      firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                void arrayForOne(double[] array, int index, DoubleConsumer consumer) {
+                    consumer.accept(array[index]);
+                }
+
+                @Override
+                Spliterator.OfDouble arraySpliterator(double[] array, int offset, int len) {
+                    return Arrays.spliterator(array, offset, offset+len);
+                }
+            }
+            return new Splitr(0, spineIndex, 0, elementIndex);
+        }
+
+        @Override
+        public String toString() {
+            double[] array = asPrimitiveArray();
+            if (array.length < 200) {
+                return String.format("%s[length=%d, chunks=%d]%s",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array));
+            }
+            else {
+                double[] array2 = Arrays.copyOf(array, 200);
+                return String.format("%s[length=%d, chunks=%d]%s...",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array2));
+            }
+        }
+    }
+}
+
diff --git a/java/util/stream/SpinedBufferTest.java b/java/util/stream/SpinedBufferTest.java
new file mode 100644
index 0000000..26a62ca
--- /dev/null
+++ b/java/util/stream/SpinedBufferTest.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+@Test
+public class SpinedBufferTest {
+
+    // Create sizes around the boundary of spines
+    static List<Integer> sizes;
+    static {
+        try {
+            sizes = IntStream.range(0, 15)
+                             .map(i -> 1 << i)
+                             .flatMap(i -> Arrays.stream(new int[] { i-2, i-1, i, i+1, i+2 }))
+                             .filter(i -> i >= 0)
+                             .boxed()
+                             .distinct()
+                             .collect(Collectors.toList());
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static final int TEST_SIZE = 5000;
+
+    // SpinedBuffer
+
+    @DataProvider(name = "SpinedBuffer")
+    public Object[][] createSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            int[] array = IntStream.range(0, size).toArray();
+
+            SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+
+            sb = new SpinedBuffer<>(size / 2);
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+
+            sb = new SpinedBuffer<>(size);
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+
+            sb = new SpinedBuffer<>(size * 2);
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "SpinedBuffer")
+    public void testSpliterator(int[] array, SpinedBuffer<Integer> sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "SpinedBuffer", groups = { "serialization-hostile" })
+    public void testLastSplit(int[] array, SpinedBuffer<Integer> sb) {
+        Spliterator<Integer> spliterator = sb.spliterator();
+        Spliterator<Integer> split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Integer> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining(contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Integer> end = Arrays.stream(array)
+                .boxed()
+                .skip(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testSpinedBuffer() {
+        List<Integer> list1 = new ArrayList<>();
+        List<Integer> list2 = new ArrayList<>();
+        SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+        for (int i = 0; i < TEST_SIZE; i++) {
+            list1.add(i);
+            sb.accept(i);
+        }
+        Iterator<Integer> it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.next());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), (Integer) i, Integer.toString(i));
+
+        list2.clear();
+        sb.forEach(list2::add);
+        assertEquals(list1, list2);
+        Integer[] array = sb.asArray(LambdaTestHelpers.integerArrayGenerator);
+        list2.clear();
+        for (Integer i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+
+    // IntSpinedBuffer
+
+    @DataProvider(name = "IntSpinedBuffer")
+    public Object[][] createIntSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            int[] array = IntStream.range(0, size).toArray();
+            SpinedBuffer.OfInt sb = new SpinedBuffer.OfInt();
+            Arrays.stream(array).forEach(sb);
+
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "IntSpinedBuffer")
+    public void testIntSpliterator(int[] array, SpinedBuffer.OfInt sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testIntSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "IntSpinedBuffer", groups = { "serialization-hostile" })
+    public void testIntLastSplit(int[] array, SpinedBuffer.OfInt sb) {
+        Spliterator.OfInt spliterator = sb.spliterator();
+        Spliterator.OfInt split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Integer> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining((IntConsumer) contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Integer> end = Arrays.stream(array)
+                .boxed()
+                .skip(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testIntSpinedBuffer() {
+        List<Integer> list1 = new ArrayList<>();
+        List<Integer> list2 = new ArrayList<>();
+        SpinedBuffer.OfInt sb = new SpinedBuffer.OfInt();
+        for (int i = 0; i < TEST_SIZE; i++) {
+            list1.add(i);
+            sb.accept(i);
+        }
+        PrimitiveIterator.OfInt it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.nextInt());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), i, Integer.toString(i));
+
+        list2.clear();
+        sb.forEach((int i) -> list2.add(i));
+        assertEquals(list1, list2);
+        int[] array = sb.asPrimitiveArray();
+        list2.clear();
+        for (int i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+
+    // LongSpinedBuffer
+
+    @DataProvider(name = "LongSpinedBuffer")
+    public Object[][] createLongSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            long[] array = LongStream.range(0, size).toArray();
+            SpinedBuffer.OfLong sb = new SpinedBuffer.OfLong();
+            Arrays.stream(array).forEach(sb);
+
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "LongSpinedBuffer")
+    public void testLongSpliterator(long[] array, SpinedBuffer.OfLong sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testLongSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "LongSpinedBuffer", groups = { "serialization-hostile" })
+    public void testLongLastSplit(long[] array, SpinedBuffer.OfLong sb) {
+        Spliterator.OfLong spliterator = sb.spliterator();
+        Spliterator.OfLong split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Long> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining((LongConsumer) contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Long> end = Arrays.stream(array)
+                .boxed()
+                .skip(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testLongSpinedBuffer() {
+        List<Long> list1 = new ArrayList<>();
+        List<Long> list2 = new ArrayList<>();
+        SpinedBuffer.OfLong sb = new SpinedBuffer.OfLong();
+        for (long i = 0; i < TEST_SIZE; i++) {
+            list1.add(i);
+            sb.accept(i);
+        }
+        PrimitiveIterator.OfLong it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.nextLong());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), i, Long.toString(i));
+
+        list2.clear();
+        sb.forEach((long i) -> list2.add(i));
+        assertEquals(list1, list2);
+        long[] array = sb.asPrimitiveArray();
+        list2.clear();
+        for (long i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+
+    // DoubleSpinedBuffer
+
+    @DataProvider(name = "DoubleSpinedBuffer")
+    public Object[][] createDoubleSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            // @@@ replace with double range when implemented
+            double[] array = LongStream.range(0, size).asDoubleStream().toArray();
+            SpinedBuffer.OfDouble sb = new SpinedBuffer.OfDouble();
+            Arrays.stream(array).forEach(sb);
+
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "DoubleSpinedBuffer")
+    public void testDoubleSpliterator(double[] array, SpinedBuffer.OfDouble sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testDoubleSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "DoubleSpinedBuffer", groups = { "serialization-hostile" })
+    public void testLongLastSplit(double[] array, SpinedBuffer.OfDouble sb) {
+        Spliterator.OfDouble spliterator = sb.spliterator();
+        Spliterator.OfDouble split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Double> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining((DoubleConsumer) contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Double> end = Arrays.stream(array)
+                .boxed()
+                .skip(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testDoubleSpinedBuffer() {
+        List<Double> list1 = new ArrayList<>();
+        List<Double> list2 = new ArrayList<>();
+        SpinedBuffer.OfDouble sb = new SpinedBuffer.OfDouble();
+        for (long i = 0; i < TEST_SIZE; i++) {
+            list1.add((double) i);
+            sb.accept((double) i);
+        }
+        PrimitiveIterator.OfDouble it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.nextDouble());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), (double) i, Double.toString(i));
+
+        list2.clear();
+        sb.forEach((double i) -> list2.add(i));
+        assertEquals(list1, list2);
+        double[] array = sb.asPrimitiveArray();
+        list2.clear();
+        for (double i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+}
diff --git a/java/util/stream/SpliteratorTestHelper.java b/java/util/stream/SpliteratorTestHelper.java
new file mode 100644
index 0000000..cf9ce2a
--- /dev/null
+++ b/java/util/stream/SpliteratorTestHelper.java
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Spliterator;
+import java.util.function.*;
+
+import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+/**
+ * Assertion methods for spliterators, to be called from other tests
+ */
+public class SpliteratorTestHelper {
+
+    public interface ContentAsserter<T> {
+        void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered);
+    }
+
+    private static ContentAsserter<Object> DEFAULT_CONTENT_ASSERTER
+            = SpliteratorTestHelper::assertContents;
+
+    @SuppressWarnings("unchecked")
+    private static <T> ContentAsserter<T> defaultContentAsserter() {
+        return (ContentAsserter<T>) DEFAULT_CONTENT_ASSERTER;
+    }
+
+    public static void testSpliterator(Supplier<Spliterator<Integer>> supplier) {
+        testSpliterator(supplier, defaultContentAsserter());
+    }
+
+    public static void testSpliterator(Supplier<Spliterator<Integer>> supplier,
+                                       ContentAsserter<Integer> asserter) {
+        testSpliterator(supplier, (Consumer<Integer> b) -> b, asserter);
+    }
+
+    public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier) {
+        testIntSpliterator(supplier, defaultContentAsserter());
+    }
+
+    public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier,
+                                          ContentAsserter<Integer> asserter) {
+        class BoxingAdapter implements Consumer<Integer>, IntConsumer {
+            private final Consumer<Integer> b;
+
+            BoxingAdapter(Consumer<Integer> b) {
+                this.b = b;
+            }
+
+            @Override
+            public void accept(Integer value) {
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public void accept(int value) {
+                b.accept(value);
+            }
+        }
+
+        testSpliterator(supplier, BoxingAdapter::new, asserter);
+    }
+
+    public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier) {
+        testLongSpliterator(supplier, defaultContentAsserter());
+    }
+
+    public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier,
+                                           ContentAsserter<Long> asserter) {
+        class BoxingAdapter implements Consumer<Long>, LongConsumer {
+            private final Consumer<Long> b;
+
+            BoxingAdapter(Consumer<Long> b) {
+                this.b = b;
+            }
+
+            @Override
+            public void accept(Long value) {
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public void accept(long value) {
+                b.accept(value);
+            }
+        }
+
+        testSpliterator(supplier, BoxingAdapter::new, asserter);
+    }
+
+    public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier) {
+        testDoubleSpliterator(supplier, defaultContentAsserter());
+    }
+
+    public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier,
+                                             ContentAsserter<Double> asserter) {
+        class BoxingAdapter implements Consumer<Double>, DoubleConsumer {
+            private final Consumer<Double> b;
+
+            BoxingAdapter(Consumer<Double> b) {
+                this.b = b;
+            }
+
+            @Override
+            public void accept(Double value) {
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public void accept(double value) {
+                b.accept(value);
+            }
+        }
+
+        testSpliterator(supplier, BoxingAdapter::new, asserter);
+    }
+
+    static <T, S extends Spliterator<T>> void testSpliterator(Supplier<S> supplier,
+                                                              UnaryOperator<Consumer<T>> boxingAdapter,
+                                                              ContentAsserter<T> asserter) {
+        ArrayList<T> fromForEach = new ArrayList<>();
+        Spliterator<T> spliterator = supplier.get();
+        Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
+        spliterator.forEachRemaining(addToFromForEach);
+
+        Collection<T> exp = Collections.unmodifiableList(fromForEach);
+
+        testNullPointerException(supplier);
+        testForEach(exp, supplier, boxingAdapter, asserter);
+        testTryAdvance(exp, supplier, boxingAdapter, asserter);
+        testMixedTryAdvanceForEach(exp, supplier, boxingAdapter, asserter);
+        testMixedTraverseAndSplit(exp, supplier, boxingAdapter, asserter);
+        testSplitAfterFullTraversal(supplier, boxingAdapter);
+        testSplitOnce(exp, supplier, boxingAdapter, asserter);
+        testSplitSixDeep(exp, supplier, boxingAdapter, asserter);
+        testSplitUntilNull(exp, supplier, boxingAdapter, asserter);
+    }
+
+    //
+
+    private static <T, S extends Spliterator<T>> void testNullPointerException(Supplier<S> s) {
+        S sp = s.get();
+        // Have to check instances and use casts to avoid tripwire messages and
+        // directly test the primitive methods
+        if (sp instanceof Spliterator.OfInt) {
+            Spliterator.OfInt psp = (Spliterator.OfInt) sp;
+            executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((IntConsumer) null));
+            executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((IntConsumer) null));
+        }
+        else if (sp instanceof Spliterator.OfLong) {
+            Spliterator.OfLong psp = (Spliterator.OfLong) sp;
+            executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((LongConsumer) null));
+            executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((LongConsumer) null));
+        }
+        else if (sp instanceof Spliterator.OfDouble) {
+            Spliterator.OfDouble psp = (Spliterator.OfDouble) sp;
+            executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((DoubleConsumer) null));
+            executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((DoubleConsumer) null));
+        }
+        else {
+            executeAndCatch(NullPointerException.class, () -> sp.forEachRemaining(null));
+            executeAndCatch(NullPointerException.class, () -> sp.tryAdvance(null));
+        }
+    }
+
+    private static <T, S extends Spliterator<T>> void testForEach(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        ArrayList<T> fromForEach = new ArrayList<>();
+        spliterator = supplier.get();
+        Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
+        spliterator.forEachRemaining(addToFromForEach);
+
+        // Assert that forEach now produces no elements
+        spliterator.forEachRemaining(boxingAdapter.apply(
+                e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+        // Assert that tryAdvance now produce no elements
+        spliterator.tryAdvance(boxingAdapter.apply(
+                e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+        // assert that size, tryAdvance, and forEach are consistent
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, exp.size());
+        }
+        assertEquals(fromForEach.size(), exp.size());
+
+        asserter.assertContents(fromForEach, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testTryAdvance(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        spliterator = supplier.get();
+        ArrayList<T> fromTryAdvance = new ArrayList<>();
+        Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add);
+        while (spliterator.tryAdvance(addToFromTryAdvance)) { }
+
+        // Assert that forEach now produces no elements
+        spliterator.forEachRemaining(boxingAdapter.apply(
+                e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+        // Assert that tryAdvance now produce no elements
+        spliterator.tryAdvance(boxingAdapter.apply(
+                e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+        // assert that size, tryAdvance, and forEach are consistent
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, exp.size());
+        }
+        assertEquals(fromTryAdvance.size(), exp.size());
+
+        asserter.assertContents(fromTryAdvance, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        // tryAdvance first few elements, then forEach rest
+        ArrayList<T> dest = new ArrayList<>();
+        spliterator = supplier.get();
+        Consumer<T> addToDest = boxingAdapter.apply(dest::add);
+        for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { }
+        spliterator.forEachRemaining(addToDest);
+
+        // Assert that forEach now produces no elements
+        spliterator.forEachRemaining(boxingAdapter.apply(
+                e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+        // Assert that tryAdvance now produce no elements
+        spliterator.tryAdvance(boxingAdapter.apply(
+                e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, dest.size());
+        }
+        assertEquals(dest.size(), exp.size());
+
+        asserter.assertContents(dest, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testMixedTraverseAndSplit(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        // tryAdvance first few elements, then forEach rest
+        ArrayList<T> dest = new ArrayList<>();
+        spliterator = supplier.get();
+        Consumer<T> b = boxingAdapter.apply(dest::add);
+
+        Spliterator<T> spl1, spl2, spl3;
+        spliterator.tryAdvance(b);
+        spl2 = spliterator.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        spliterator.tryAdvance(b);
+        spl3 = spliterator.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        spliterator.tryAdvance(b);
+        spliterator.forEachRemaining(b);
+
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, dest.size());
+        }
+        assertEquals(dest.size(), exp.size());
+
+        asserter.assertContents(dest, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal(
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter) {
+        // Full traversal using tryAdvance
+        Spliterator<T> spliterator = supplier.get();
+        while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { }
+        Spliterator<T> split = spliterator.trySplit();
+        assertNull(split);
+
+        // Full traversal using forEach
+        spliterator = supplier.get();
+        spliterator.forEachRemaining(boxingAdapter.apply(e -> { }));
+        split = spliterator.trySplit();
+        assertNull(split);
+
+        // Full traversal using tryAdvance then forEach
+        spliterator = supplier.get();
+        spliterator.tryAdvance(boxingAdapter.apply(e -> { }));
+        spliterator.forEachRemaining(boxingAdapter.apply(e -> { }));
+        split = spliterator.trySplit();
+        assertNull(split);
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitOnce(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        ArrayList<T> fromSplit = new ArrayList<>();
+        Spliterator<T> s1 = supplier.get();
+        Spliterator<T> s2 = s1.trySplit();
+        long s1Size = s1.getExactSizeIfKnown();
+        long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0;
+        Consumer<T> addToFromSplit = boxingAdapter.apply(fromSplit::add);
+        if (s2 != null)
+            s2.forEachRemaining(addToFromSplit);
+        s1.forEachRemaining(addToFromSplit);
+
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, fromSplit.size());
+            if (s1Size >= 0 && s2Size >= 0)
+                assertEquals(sizeIfKnown, s1Size + s2Size);
+        }
+
+        asserter.assertContents(fromSplit, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitSixDeep(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        for (int depth=0; depth < 6; depth++) {
+            List<T> dest = new ArrayList<>();
+            spliterator = supplier.get();
+
+            assertSpliterator(spliterator);
+
+            // verify splitting with forEach
+            splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false);
+            asserter.assertContents(dest, exp, isOrdered);
+
+            // verify splitting with tryAdvance
+            dest.clear();
+            spliterator = supplier.get();
+            splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true);
+            asserter.assertContents(dest, exp, isOrdered);
+        }
+    }
+
+    static void splitSixDeepVisitorUnsafe(int depth, int curLevel, List dest,
+        Spliterator spliterator, UnaryOperator boxingAdapter,
+        int rootCharacteristics, boolean useTryAdvance) {
+      splitSixDeepVisitor(depth, curLevel, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance);
+    }
+
+    // Android-changed: Workaround for jack type inference bug
+     private static <T>
+    // private static <T, S extends Spliterator<T>>
+    // Android-changed: Workaround for jack type inference bug
+    void splitSixDeepVisitor(int depth, int curLevel,
+                             List<T> dest, Spliterator<T> spliterator, UnaryOperator<Consumer<T>> boxingAdapter,
+    //                         List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter,
+                             int rootCharacteristics, boolean useTryAdvance) {
+        if (curLevel < depth) {
+            long beforeSize = spliterator.getExactSizeIfKnown();
+            Spliterator<T> split = spliterator.trySplit();
+            if (split != null) {
+                assertSpliterator(split, rootCharacteristics);
+                assertSpliterator(spliterator, rootCharacteristics);
+
+                if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 &&
+                    (rootCharacteristics & Spliterator.SIZED) != 0) {
+                    assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize());
+                }
+                // Android-changed: Workaround for jack type inference bug
+                splitSixDeepVisitorUnsafe(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance);
+                // splitSixDeepVisitor(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance);
+            }
+            splitSixDeepVisitor(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance);
+        }
+        else {
+            long sizeIfKnown = spliterator.getExactSizeIfKnown();
+            if (useTryAdvance) {
+                Consumer<T> addToDest = boxingAdapter.apply(dest::add);
+                int count = 0;
+                while (spliterator.tryAdvance(addToDest)) {
+                    ++count;
+                }
+
+                if (sizeIfKnown >= 0)
+                    assertEquals(sizeIfKnown, count);
+
+                // Assert that forEach now produces no elements
+                spliterator.forEachRemaining(boxingAdapter.apply(
+                        e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+
+                Spliterator<T> split = spliterator.trySplit();
+                assertNull(split);
+            }
+            else {
+                List<T> leafDest = new ArrayList<>();
+                Consumer<T> addToLeafDest = boxingAdapter.apply(leafDest::add);
+                spliterator.forEachRemaining(addToLeafDest);
+
+                if (sizeIfKnown >= 0)
+                    assertEquals(sizeIfKnown, leafDest.size());
+
+                // Assert that forEach now produces no elements
+                spliterator.tryAdvance(boxingAdapter.apply(
+                        e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+                Spliterator<T> split = spliterator.trySplit();
+                assertNull(split);
+
+                dest.addAll(leafDest);
+            }
+        }
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitUntilNull(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        Spliterator<T> s = supplier.get();
+        boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED);
+        assertSpliterator(s);
+
+        List<T> splits = new ArrayList<>();
+        Consumer<T> c = boxingAdapter.apply(splits::add);
+
+        testSplitUntilNull(new SplitNode<T>(c, s));
+        asserter.assertContents(splits, exp, isOrdered);
+    }
+
+    private static class SplitNode<T> {
+        // Constant for every node
+        final Consumer<T> c;
+        final int rootCharacteristics;
+
+        final Spliterator<T> s;
+
+        SplitNode(Consumer<T> c, Spliterator<T> s) {
+            this(c, s.characteristics(), s);
+        }
+
+        private SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s) {
+            this.c = c;
+            this.rootCharacteristics = rootCharacteristics;
+            this.s = s;
+        }
+
+        SplitNode<T> fromSplit(Spliterator<T> split) {
+            return new SplitNode<>(c, rootCharacteristics, split);
+        }
+    }
+
+    /**
+     * Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator
+     * while not unduly disrupting test infrastructure given the test data sizes that are used are small.
+     * Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26).
+     */
+    private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB
+
+    private static <T> void testSplitUntilNull(SplitNode<T> e) {
+        // Use an explicit stack to avoid a StackOverflowException when testing a Spliterator
+        // that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or
+        // for a spliterator that is badly behaved.
+        Deque<SplitNode<T>> stack = new ArrayDeque<>();
+        stack.push(e);
+
+        int iteration = 0;
+        while (!stack.isEmpty()) {
+            assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18");
+
+            e = stack.pop();
+            Spliterator<T> parentAndRightSplit = e.s;
+
+            long parentEstimateSize = parentAndRightSplit.estimateSize();
+            assertTrue(parentEstimateSize >= 0,
+                       String.format("Split size estimate %d < 0", parentEstimateSize));
+
+            long parentSize = parentAndRightSplit.getExactSizeIfKnown();
+            Spliterator<T> leftSplit = parentAndRightSplit.trySplit();
+            if (leftSplit == null) {
+                parentAndRightSplit.forEachRemaining(e.c);
+                continue;
+            }
+
+            assertSpliterator(leftSplit, e.rootCharacteristics);
+            assertSpliterator(parentAndRightSplit, e.rootCharacteristics);
+
+            if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0
+                && parentAndRightSplit.estimateSize() > 0) {
+                assertTrue(leftSplit.estimateSize() < parentEstimateSize,
+                           String.format("Left split size estimate %d >= parent split size estimate %d",
+                                         leftSplit.estimateSize(), parentEstimateSize));
+                assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize,
+                           String.format("Right split size estimate %d >= parent split size estimate %d",
+                                         leftSplit.estimateSize(), parentEstimateSize));
+            }
+            else {
+                assertTrue(leftSplit.estimateSize() <= parentEstimateSize,
+                           String.format("Left split size estimate %d > parent split size estimate %d",
+                                         leftSplit.estimateSize(), parentEstimateSize));
+                assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize,
+                           String.format("Right split size estimate %d > parent split size estimate %d",
+                                         leftSplit.estimateSize(), parentEstimateSize));
+            }
+
+            long leftSize = leftSplit.getExactSizeIfKnown();
+            long rightSize = parentAndRightSplit.getExactSizeIfKnown();
+            if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0)
+                assertEquals(parentSize, leftSize + rightSize,
+                             String.format("exact left split size %d + exact right split size %d != parent exact split size %d",
+                                           leftSize, rightSize, parentSize));
+
+            // Add right side to stack first so left side is popped off first
+            stack.push(e.fromSplit(parentAndRightSplit));
+            stack.push(e.fromSplit(leftSplit));
+        }
+    }
+
+    private static void assertSpliterator(Spliterator<?> s, int rootCharacteristics) {
+        if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) {
+            assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED),
+                       "Child split is not SUBSIZED when root split is SUBSIZED");
+        }
+        assertSpliterator(s);
+    }
+
+    private static void assertSpliterator(Spliterator<?> s) {
+        if (s.hasCharacteristics(Spliterator.SUBSIZED)) {
+            assertTrue(s.hasCharacteristics(Spliterator.SIZED));
+        }
+        if (s.hasCharacteristics(Spliterator.SIZED)) {
+            assertTrue(s.estimateSize() != Long.MAX_VALUE);
+            assertTrue(s.getExactSizeIfKnown() >= 0);
+        }
+        try {
+            s.getComparator();
+            assertTrue(s.hasCharacteristics(Spliterator.SORTED));
+        } catch (IllegalStateException e) {
+            assertFalse(s.hasCharacteristics(Spliterator.SORTED));
+        }
+    }
+
+    private static<T> void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {
+        if (isOrdered) {
+            assertEquals(actual, expected);
+        }
+        else {
+            LambdaTestHelpers.assertContentsUnordered(actual, expected);
+        }
+    }
+
+    private static void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
+        Exception caught = null;
+        try {
+            r.run();
+        }
+        catch (Exception e) {
+            caught = e;
+        }
+
+        assertNotNull(caught,
+                      String.format("No Exception was thrown, expected an Exception of %s to be thrown",
+                                    expected.getName()));
+        assertTrue(expected.isInstance(caught),
+                   String.format("Exception thrown %s not an instance of %s",
+                                 caught.getClass().getName(), expected.getName()));
+    }
+
+    static<U> void mixedTraverseAndSplit(Consumer<U> b, Spliterator<U> splTop) {
+        Spliterator<U> spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+
+    static void mixedTraverseAndSplit(IntConsumer b, Spliterator.OfInt splTop) {
+        Spliterator.OfInt spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+    static void mixedTraverseAndSplit(LongConsumer b, Spliterator.OfLong splTop) {
+        Spliterator.OfLong spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+
+    static void mixedTraverseAndSplit(DoubleConsumer b, Spliterator.OfDouble splTop) {
+        Spliterator.OfDouble spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+}
diff --git a/java/util/stream/StatefulTestOp.java b/java/util/stream/StatefulTestOp.java
new file mode 100644
index 0000000..904b4e5
--- /dev/null
+++ b/java/util/stream/StatefulTestOp.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+/**
+ * The base type for a stateful test operation.
+ */
+interface StatefulTestOp<E> extends IntermediateTestOp<E, E> {
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+                                            StatefulTestOp op) {
+        switch (op.outputShape()) {
+            case REFERENCE:
+                return new ReferencePipeline.StatefulOp<Object, T>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper,
+                                                                 Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      IntFunction<T[]> generator) {
+                        return op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            case INT_VALUE:
+                return new IntPipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    public <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
+                                                                 Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                            Spliterator<P_IN> spliterator,
+                                                            IntFunction<Integer[]> generator) {
+                        return (Node<Integer>) op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            case LONG_VALUE:
+                return new LongPipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    public <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
+                                                                 Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                         Spliterator<P_IN> spliterator,
+                                                         IntFunction<Long[]> generator) {
+                        return (Node<Long>) op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            case DOUBLE_VALUE:
+                return new DoublePipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    public <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
+                                                                    Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                           Spliterator<P_IN> spliterator,
+                                                           IntFunction<Double[]> generator) {
+                        return (Node<Double>) op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            default: throw new IllegalStateException(op.outputShape().toString());
+        }
+    }
+
+    default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+    default StreamShape outputShape() { return StreamShape.REFERENCE; }
+
+    default int opGetFlags() { return 0; }
+
+    Sink<E> opWrapSink(int flags, boolean parallel, Sink<E> sink);
+
+    @SuppressWarnings("unchecked")
+    default <P_IN> Spliterator<E> opEvaluateParallelLazy(PipelineHelper<E> helper,
+                                                         Spliterator<P_IN> spliterator) {
+        return opEvaluateParallel(helper, spliterator, i -> (E[]) new Object[i]).spliterator();
+    }
+
+    <P_IN> Node<E> opEvaluateParallel(PipelineHelper<E> helper,
+                                      Spliterator<P_IN> spliterator,
+                                      IntFunction<E[]> generator);
+}
diff --git a/java/util/stream/StatelessTestOp.java b/java/util/stream/StatelessTestOp.java
new file mode 100644
index 0000000..3a6194b
--- /dev/null
+++ b/java/util/stream/StatelessTestOp.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * The base type of a stateless test operation
+ */
+interface StatelessTestOp<E_IN, E_OUT> extends IntermediateTestOp<E_IN, E_OUT> {
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+                                            StatelessTestOp<?, T> op) {
+        int flags = op.opGetFlags();
+        switch (op.outputShape()) {
+            case REFERENCE:
+                return new ReferencePipeline.StatelessOp<Object, T>(upstream, op.inputShape(), flags) {
+                    public Sink opWrapSink(int flags, Sink<T> sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            case INT_VALUE:
+                return new IntPipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            case LONG_VALUE:
+                return new LongPipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            case DOUBLE_VALUE:
+                return new DoublePipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            default: throw new IllegalStateException(op.outputShape().toString());
+        }
+    }
+
+    default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+    default StreamShape outputShape() { return StreamShape.REFERENCE; }
+
+    default int opGetFlags() { return 0; }
+
+    Sink<E_IN> opWrapSink(int flags, boolean parallel, Sink<E_OUT> sink);
+}
+
diff --git a/java/util/stream/Stream.java b/java/util/stream/Stream.java
new file mode 100644
index 0000000..c35fc05
--- /dev/null
+++ b/java/util/stream/Stream.java
@@ -0,0 +1,1145 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+import java.util.function.UnaryOperator;
+
+/**
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
+ *
+ * <p>In addition to {@code Stream}, which is a stream of object references,
+ * there are primitive specializations for {@link IntStream}, {@link LongStream},
+ * and {@link DoubleStream}, all of which are referred to as "streams" and
+ * conform to the characteristics and restrictions described here.
+ *
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an I/O channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link Stream#filter(Predicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link Stream#count()} or {@link Stream#forEach(Consumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
+ *
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above.  To preserve correct behavior,
+ * these <em>behavioral parameters</em>:
+ * <ul>
+ * <li>must be <a href="package-summary.html#NonInterference">non-interfering</a>
+ * (they do not modify the stream source); and</li>
+ * <li>in most cases must be <a href="package-summary.html#Statelessness">stateless</a>
+ * (their result should not depend on any state that might change during execution
+ * of the stream pipeline).</li>
+ * </ul>
+ *
+ * <p>Such parameters are always instances of a
+ * <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  Unless otherwise specified these parameters must be
+ * <em>non-null</em>.
+ *
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
+ *
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing.  Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management.  (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
+ *
+ * @param <T> the type of the stream elements
+ * @since 1.8
+ * @see IntStream
+ * @see LongStream
+ * @see DoubleStream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface Stream<T> extends BaseStream<T, Stream<T>> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    Stream<T> filter(Predicate<? super T> predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param <R> The element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream mapToInt(ToIntFunction<? super T> mapper);
+
+    /**
+     * Returns a {@code LongStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream mapToLong(ToLongFunction<? super T> mapper);
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @apiNote
+     * The {@code flatMap()} operation has the effect of applying a one-to-many
+     * transformation to the elements of the stream, and then flattening the
+     * resulting elements into a new stream.
+     *
+     * <p><b>Examples.</b>
+     *
+     * <p>If {@code orders} is a stream of purchase orders, and each purchase
+     * order contains a collection of line items, then the following produces a
+     * stream containing all the line items in all the orders:
+     * <pre>{@code
+     *     orders.flatMap(order -> order.getLineItems().stream())...
+     * }</pre>
+     *
+     * <p>If {@code path} is the path to a file, then the following produces a
+     * stream of the {@code words} contained in that file:
+     * <pre>{@code
+     *     Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);
+     *     Stream<String> words = lines.flatMap(line -> Stream.of(line.split(" +")));
+     * }</pre>
+     * The {@code mapper} function passed to {@code flatMap} splits a line,
+     * using a simple regular expression, into an array of words, and then
+     * creates a stream of words from that array.
+     *
+     * @param <R> The element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     */
+    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of replacing each
+     * element of this stream with the contents of a mapped stream produced by
+     * applying the provided mapping function to each element.  Each mapped
+     * stream is {@link java.util.stream.BaseStream#close() closed} after its
+     * contents have been placed into this stream.  (If a mapped stream is
+     * {@code null} an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     * @see #flatMap(Function)
+     */
+    IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
+
+    /**
+     * Returns an {@code LongStream} consisting of the results of replacing each
+     * element of this stream with the contents of a mapped stream produced by
+     * applying the provided mapping function to each element.  Each mapped
+     * stream is {@link java.util.stream.BaseStream#close() closed} after its
+     * contents have been placed into this stream.  (If a mapped stream is
+     * {@code null} an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     * @see #flatMap(Function)
+     */
+    LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
+
+    /**
+     * Returns an {@code DoubleStream} consisting of the results of replacing
+     * each element of this stream with the contents of a mapped stream produced
+     * by applying the provided mapping function to each element.  Each mapped
+     * stream is {@link java.util.stream.BaseStream#close() closed} after its
+     * contents have placed been into this stream.  (If a mapped stream is
+     * {@code null} an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     * @see #flatMap(Function)
+     */
+    DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
+
+    /**
+     * Returns a stream consisting of the distinct elements (according to
+     * {@link Object#equals(Object)}) of this stream.
+     *
+     * <p>For ordered streams, the selection of distinct elements is stable
+     * (for duplicated elements, the element appearing first in the encounter
+     * order is preserved.)  For unordered streams, no stability guarantees
+     * are made.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * Preserving stability for {@code distinct()} in parallel pipelines is
+     * relatively expensive (requires that the operation act as a full barrier,
+     * with substantial buffering overhead), and stability is often not needed.
+     * Using an unordered stream source (such as {@link #generate(Supplier)})
+     * or removing the ordering constraint with {@link #unordered()} may result
+     * in significantly more efficient execution for {@code distinct()} in parallel
+     * pipelines, if the semantics of your situation permit.  If consistency
+     * with encounter order is required, and you are experiencing poor performance
+     * or memory utilization with {@code distinct()} in parallel pipelines,
+     * switching to sequential execution with {@link #sequential()} may improve
+     * performance.
+     *
+     * @return the new stream
+     */
+    Stream<T> distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, sorted
+     * according to natural order.  If the elements of this stream are not
+     * {@code Comparable}, a {@code java.lang.ClassCastException} may be thrown
+     * when the terminal operation is executed.
+     *
+     * <p>For ordered streams, the sort is stable.  For unordered streams, no
+     * stability guarantees are made.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    Stream<T> sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, sorted
+     * according to the provided {@code Comparator}.
+     *
+     * <p>For ordered streams, the sort is stable.  For unordered streams, no
+     * stability guarantees are made.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @param comparator a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                   <a href="package-summary.html#Statelessness">stateless</a>
+     *                   {@code Comparator} to be used to compare stream elements
+     * @return the new stream
+     */
+    Stream<T> sorted(Comparator<? super T> comparator);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     Stream.of("one", "two", "three", "four")
+     *         .filter(e -> e.length() > 3)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(String::toUpperCase)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .collect(Collectors.toList());
+     * }</pre>
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *                 non-interfering</a> action to perform on the elements as
+     *                 they are consumed from the stream
+     * @return the new stream
+     */
+    Stream<T> peek(Consumer<? super T> action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(Supplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    Stream<T> limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(Supplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    Stream<T> skip(long n);
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic.
+     * For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(Consumer<? super T> action);
+
+    /**
+     * Performs an action for each element of this stream, in the encounter
+     * order of the stream if the stream has a defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>This operation processes the elements one at a time, in encounter
+     * order if one exists.  Performing the action for one element
+     * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * performing the action for subsequent elements, but for any given element,
+     * the action may be performed in whatever thread the library chooses.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(Consumer)
+     */
+    void forEachOrdered(Consumer<? super T> action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array containing the elements of this stream
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing the elements of this stream, using the
+     * provided {@code generator} function to allocate the returned array, as
+     * well as any additional arrays that might be required for a partitioned
+     * execution or for resizing.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote
+     * The generator function takes an integer, which is the size of the
+     * desired array, and produces an array of the desired size.  This can be
+     * concisely expressed with an array constructor reference:
+     * <pre>{@code
+     *     Person[] men = people.stream()
+     *                          .filter(p -> p.getGender() == MALE)
+     *                          .toArray(Person[]::new);
+     * }</pre>
+     *
+     * @param <A> the element type of the resulting array
+     * @param generator a function which produces a new array of the desired
+     *                  type and the provided length
+     * @return an array containing the elements in this stream
+     * @throws ArrayStoreException if the runtime type of the array returned
+     * from the array generator is not a supertype of the runtime type of every
+     * element in this stream
+     */
+    <A> A[] toArray(IntFunction<A[]> generator);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     T result = identity;
+     *     for (T element : this stream)
+     *         result = accumulator.apply(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code t},
+     * {@code accumulator.apply(identity, t)} is equal to {@code t}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min, max, average, and string concatenation are all special
+     * cases of reduction. Summing a stream of numbers can be expressed as:
+     *
+     * <pre>{@code
+     *     Integer sum = integers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or:
+     *
+     * <pre>{@code
+     *     Integer sum = integers.reduce(0, Integer::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values
+     * @return the result of the reduction
+     */
+    T reduce(T identity, BinaryOperator<T> accumulator);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code Optional} describing the reduced value,
+     * if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     T result = null;
+     *     for (T element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.apply(result, element);
+     *     }
+     *     return foundAny ? Optional.of(result) : Optional.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values
+     * @return an {@link Optional} describing the result of the reduction
+     * @throws NullPointerException if the result of the reduction is null
+     * @see #reduce(Object, BinaryOperator)
+     * @see #min(Comparator)
+     * @see #max(Comparator)
+     */
+    Optional<T> reduce(BinaryOperator<T> accumulator);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity, accumulation and
+     * combining functions.  This is equivalent to:
+     * <pre>{@code
+     *     U result = identity;
+     *     for (T element : this stream)
+     *         result = accumulator.apply(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the combiner
+     * function.  This means that for all {@code u}, {@code combiner(identity, u)}
+     * is equal to {@code u}.  Additionally, the {@code combiner} function
+     * must be compatible with the {@code accumulator} function; for all
+     * {@code u} and {@code t}, the following must hold:
+     * <pre>{@code
+     *     combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Many reductions using this form can be represented more simply
+     * by an explicit combination of {@code map} and {@code reduce} operations.
+     * The {@code accumulator} function acts as a fused mapper and accumulator,
+     * which can sometimes be more efficient than separate mapping and reduction,
+     * such as when knowing the previously reduced value allows you to avoid
+     * some computation.
+     *
+     * @param <U> The type of the result
+     * @param identity the identity value for the combiner function
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for incorporating an additional element into a result
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values, which must be
+     *                    compatible with the accumulator function
+     * @return the result of the reduction
+     * @see #reduce(BinaryOperator)
+     * @see #reduce(Object, BinaryOperator)
+     */
+    <U> U reduce(U identity,
+                 BiFunction<U, ? super T, U> accumulator,
+                 BinaryOperator<U> combiner);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (T element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(Object, BinaryOperator)}, {@code collect} operations
+     * can be parallelized without requiring additional synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote There are many existing classes in the JDK whose signatures are
+     * well-suited for use with method references as arguments to {@code collect()}.
+     * For example, the following will accumulate strings into an {@code ArrayList}:
+     * <pre>{@code
+     *     List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add,
+     *                                                ArrayList::addAll);
+     * }</pre>
+     *
+     * <p>The following will take a stream of strings and concatenates them into a
+     * single string:
+     * <pre>{@code
+     *     String concat = stringStream.collect(StringBuilder::new, StringBuilder::append,
+     *                                          StringBuilder::append)
+     *                                 .toString();
+     * }</pre>
+     *
+     * @param <R> type of the result
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for incorporating an additional element into a result
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values, which must be
+     *                    compatible with the accumulator function
+     * @return the result of the reduction
+     */
+    <R> R collect(Supplier<R> supplier,
+                  BiConsumer<R, ? super T> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream using a
+     * {@code Collector}.  A {@code Collector}
+     * encapsulates the functions used as arguments to
+     * {@link #collect(Supplier, BiConsumer, BiConsumer)}, allowing for reuse of
+     * collection strategies and composition of collect operations such as
+     * multiple-level grouping or partitioning.
+     *
+     * <p>If the stream is parallel, and the {@code Collector}
+     * is {@link Collector.Characteristics#CONCURRENT concurrent}, and
+     * either the stream is unordered or the collector is
+     * {@link Collector.Characteristics#UNORDERED unordered},
+     * then a concurrent reduction will be performed (see {@link Collector} for
+     * details on concurrent reduction.)
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>When executed in parallel, multiple intermediate results may be
+     * instantiated, populated, and merged so as to maintain isolation of
+     * mutable data structures.  Therefore, even when executed in parallel
+     * with non-thread-safe data structures (such as {@code ArrayList}), no
+     * additional synchronization is needed for a parallel reduction.
+     *
+     * @apiNote
+     * The following will accumulate strings into an ArrayList:
+     * <pre>{@code
+     *     List<String> asList = stringStream.collect(Collectors.toList());
+     * }</pre>
+     *
+     * <p>The following will classify {@code Person} objects by city:
+     * <pre>{@code
+     *     Map<String, List<Person>> peopleByCity
+     *         = personStream.collect(Collectors.groupingBy(Person::getCity));
+     * }</pre>
+     *
+     * <p>The following will classify {@code Person} objects by state and city,
+     * cascading two {@code Collector}s together:
+     * <pre>{@code
+     *     Map<String, Map<String, List<Person>>> peopleByStateAndCity
+     *         = personStream.collect(Collectors.groupingBy(Person::getState,
+     *                                                      Collectors.groupingBy(Person::getCity)));
+     * }</pre>
+     *
+     * @param <R> the type of the result
+     * @param <A> the intermediate accumulation type of the {@code Collector}
+     * @param collector the {@code Collector} describing the reduction
+     * @return the result of the reduction
+     * @see #collect(Supplier, BiConsumer, BiConsumer)
+     * @see Collectors
+     */
+    <R, A> R collect(Collector<? super T, A, R> collector);
+
+    /**
+     * Returns the minimum element of this stream according to the provided
+     * {@code Comparator}.  This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @param comparator a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                   <a href="package-summary.html#Statelessness">stateless</a>
+     *                   {@code Comparator} to compare elements of this stream
+     * @return an {@code Optional} describing the minimum element of this stream,
+     * or an empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the minimum element is null
+     */
+    Optional<T> min(Comparator<? super T> comparator);
+
+    /**
+     * Returns the maximum element of this stream according to the provided
+     * {@code Comparator}.  This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param comparator a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                   <a href="package-summary.html#Statelessness">stateless</a>
+     *                   {@code Comparator} to compare elements of this stream
+     * @return an {@code Optional} describing the maximum element of this stream,
+     * or an empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the maximum element is null
+     */
+    Optional<T> max(Comparator<? super T> comparator);
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return mapToLong(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(Predicate<? super T> predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(Predicate<? super T> predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(Predicate<? super T> predicate);
+
+    /**
+     * Returns an {@link Optional} describing the first element of this stream,
+     * or an empty {@code Optional} if the stream is empty.  If the stream has
+     * no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code Optional} describing the first element of this stream,
+     * or an empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the element selected is null
+     */
+    Optional<T> findFirst();
+
+    /**
+     * Returns an {@link Optional} describing some element of the stream, or an
+     * empty {@code Optional} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code Optional} describing some element of this stream, or an
+     * empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the element selected is null
+     * @see #findFirst()
+     */
+    Optional<T> findAny();
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code Stream}.
+     *
+     * @param <T> type of elements
+     * @return a stream builder
+     */
+    public static<T> Builder<T> builder() {
+        return new Streams.StreamBuilderImpl<>();
+    }
+
+    /**
+     * Returns an empty sequential {@code Stream}.
+     *
+     * @param <T> the type of stream elements
+     * @return an empty sequential stream
+     */
+    public static<T> Stream<T> empty() {
+        return StreamSupport.stream(Spliterators.<T>emptySpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code Stream} containing a single element.
+     *
+     * @param t the single element
+     * @param <T> the type of stream elements
+     * @return a singleton sequential stream
+     */
+    public static<T> Stream<T> of(T t) {
+        return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param <T> the type of stream elements
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs") // Creating a stream from an array is safe
+    public static<T> Stream<T> of(T... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code Stream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code Stream} will be
+     * the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * @param <T> the type of stream elements
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code Stream}
+     */
+    public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
+        Objects.requireNonNull(f);
+        final Iterator<T> iterator = new Iterator<T>() {
+            @SuppressWarnings("unchecked")
+            T t = (T) Streams.NONE;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public T next() {
+                return t = (t == Streams.NONE) ? seed : f.apply(t);
+            }
+        };
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code Supplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param <T> the type of stream elements
+     * @param s the {@code Supplier} of generated elements
+     * @return a new infinite sequential unordered {@code Stream}
+     */
+    public static<T> Stream<T> generate(Supplier<T> s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.stream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowException}.
+     *
+     * @param <T> The type of stream elements
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        @SuppressWarnings("unchecked")
+        Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
+                (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
+        Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for a {@code Stream}.  This allows the creation of a
+     * {@code Stream} by generating elements individually and adding them to the
+     * {@code Builder} (without the copying overhead that comes from using
+     * an {@code ArrayList} as a temporary buffer.)
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase begins
+     * when the {@link #build()} method is called, which creates an ordered
+     * {@code Stream} whose elements are the elements that were added to the stream
+     * builder, in the order they were added.
+     *
+     * @param <T> the type of stream elements
+     * @see Stream#builder()
+     * @since 1.8
+     */
+    public interface Builder<T> extends Consumer<T> {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        @Override
+        void accept(T t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        default Builder<T> add(T t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further attempts
+         * to operate on the builder after it has entered the built state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        Stream<T> build();
+
+    }
+}
diff --git a/java/util/stream/StreamFlagsTest.java b/java/util/stream/StreamFlagsTest.java
new file mode 100644
index 0000000..29243cf
--- /dev/null
+++ b/java/util/stream/StreamFlagsTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.*;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlag;
+import java.util.stream.Streams;
+
+import static java.util.stream.StreamOpFlag.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * StreamFlagsTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class StreamFlagsTest {
+    Stream<String> arrayList = new ArrayList<String>().stream();
+    Stream<String> linkedList = new LinkedList<String>().stream();
+    Stream<String> hashSet = new HashSet<String>().stream();
+    Stream<String> treeSet = new TreeSet<String>().stream();
+    Stream<String> linkedHashSet = new LinkedHashSet<String>().stream();
+    Stream<String> repeat = Stream.generate(() -> "");
+
+    Stream<?>[] streams = { arrayList, linkedList, hashSet, treeSet, linkedHashSet, repeat };
+
+    private void assertFlags(int value, EnumSet<StreamOpFlag> setFlags, EnumSet<StreamOpFlag> clearFlags) {
+        for (StreamOpFlag flag : setFlags)
+            assertTrue(flag.isKnown(value));
+        for (StreamOpFlag flag : clearFlags)
+            assertTrue(!flag.isKnown(value));
+    }
+
+    public void testBaseStreams() {
+        Stream<String> arrayList = new ArrayList<String>().stream();
+        Stream<String> linkedList = new LinkedList<String>().stream();
+        Stream<String> hashSet = new HashSet<String>().stream();
+        Stream<String> treeSet = new TreeSet<String>().stream();
+        Stream<String> linkedHashSet = new LinkedHashSet<String>().stream();
+        Stream<String> repeat = Stream.generate(() -> "");
+
+        assertFlags(OpTestCase.getStreamFlags(arrayList),
+                    EnumSet.of(ORDERED, SIZED),
+                    EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(linkedList),
+                    EnumSet.of(ORDERED, SIZED),
+                    EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(hashSet),
+                    EnumSet.of(SIZED, DISTINCT),
+                    EnumSet.of(ORDERED, SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(treeSet),
+                    EnumSet.of(ORDERED, SIZED, DISTINCT, SORTED),
+                    EnumSet.of(SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(linkedHashSet),
+                    EnumSet.of(ORDERED, DISTINCT, SIZED),
+                    EnumSet.of(SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(repeat),
+                    EnumSet.noneOf(StreamOpFlag.class),
+                    EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
+    }
+
+    public void testFilter() {
+        for (Stream<?> s : streams) {
+            int baseFlags = OpTestCase.getStreamFlags(s);
+            int filteredFlags = OpTestCase.getStreamFlags(s.filter((Object e) -> true));
+            int expectedFlags = baseFlags & ~SIZED.set();
+
+            assertEquals(filteredFlags, expectedFlags);
+        }
+    }
+}
diff --git a/java/util/stream/StreamOpFlag.java b/java/util/stream/StreamOpFlag.java
new file mode 100644
index 0000000..83a3660
--- /dev/null
+++ b/java/util/stream/StreamOpFlag.java
@@ -0,0 +1,782 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.Spliterator;
+
+/**
+ * Flags corresponding to characteristics of streams and operations. Flags are
+ * utilized by the stream framework to control, specialize or optimize
+ * computation.
+ *
+ * <p>
+ * Stream flags may be used to describe characteristics of several different
+ * entities associated with streams: stream sources, intermediate operations,
+ * and terminal operations.  Not all stream flags are meaningful for all
+ * entities; the following table summarizes which flags are meaningful in what
+ * contexts:
+ *
+ * <div>
+ * <table>
+ *   <caption>Type Characteristics</caption>
+ *   <thead class="tableSubHeadingColor">
+ *     <tr>
+ *       <th colspan="2">&nbsp;</th>
+ *       <th>{@code DISTINCT}</th>
+ *       <th>{@code SORTED}</th>
+ *       <th>{@code ORDERED}</th>
+ *       <th>{@code SIZED}</th>
+ *       <th>{@code SHORT_CIRCUIT}</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *      <tr>
+ *        <th colspan="2" class="tableSubHeadingColor">Stream source</th>
+ *        <td>Y</td>
+ *        <td>Y</td>
+ *        <td>Y</td>
+ *        <td>Y</td>
+ *        <td>N</td>
+ *      </tr>
+ *      <tr>
+ *        <th colspan="2" class="tableSubHeadingColor">Intermediate operation</th>
+ *        <td>PCI</td>
+ *        <td>PCI</td>
+ *        <td>PCI</td>
+ *        <td>PC</td>
+ *        <td>PI</td>
+ *      </tr>
+ *      <tr>
+ *        <th colspan="2" class="tableSubHeadingColor">Terminal operation</th>
+ *        <td>N</td>
+ *        <td>N</td>
+ *        <td>PC</td>
+ *        <td>N</td>
+ *        <td>PI</td>
+ *      </tr>
+ *   </tbody>
+ *   <tfoot>
+ *       <tr>
+ *         <th class="tableSubHeadingColor" colspan="2">Legend</th>
+ *         <th colspan="6" rowspan="7">&nbsp;</th>
+ *       </tr>
+ *       <tr>
+ *         <th class="tableSubHeadingColor">Flag</th>
+ *         <th class="tableSubHeadingColor">Meaning</th>
+ *         <th colspan="6"></th>
+ *       </tr>
+ *       <tr><td>Y</td><td>Allowed</td></tr>
+ *       <tr><td>N</td><td>Invalid</td></tr>
+ *       <tr><td>P</td><td>Preserves</td></tr>
+ *       <tr><td>C</td><td>Clears</td></tr>
+ *       <tr><td>I</td><td>Injects</td></tr>
+ *   </tfoot>
+ * </table>
+ * </div>
+ *
+ * <p>In the above table, "PCI" means "may preserve, clear, or inject"; "PC"
+ * means "may preserve or clear", "PI" means "may preserve or inject", and "N"
+ * means "not valid".
+ *
+ * <p>Stream flags are represented by unioned bit sets, so that a single word
+ * may describe all the characteristics of a given stream entity, and that, for
+ * example, the flags for a stream source can be efficiently combined with the
+ * flags for later operations on that stream.
+ *
+ * <p>The bit masks {@link #STREAM_MASK}, {@link #OP_MASK}, and
+ * {@link #TERMINAL_OP_MASK} can be ANDed with a bit set of stream flags to
+ * produce a mask containing only the valid flags for that entity type.
+ *
+ * <p>When describing a stream source, one only need describe what
+ * characteristics that stream has; when describing a stream operation, one need
+ * describe whether the operation preserves, injects, or clears that
+ * characteristic.  Accordingly, two bits are used for each flag, so as to allow
+ * representing not only the presence of of a characteristic, but how an
+ * operation modifies that characteristic.  There are two common forms in which
+ * flag bits are combined into an {@code int} bit set.  <em>Stream flags</em>
+ * are a unioned bit set constructed by ORing the enum characteristic values of
+ * {@link #set()} (or, more commonly, ORing the corresponding static named
+ * constants prefixed with {@code IS_}).  <em>Operation flags</em> are a unioned
+ * bit set constructed by ORing the enum characteristic values of {@link #set()}
+ * or {@link #clear()} (to inject, or clear, respectively, the corresponding
+ * flag), or more commonly ORing the corresponding named constants prefixed with
+ * {@code IS_} or {@code NOT_}.  Flags that are not marked with {@code IS_} or
+ * {@code NOT_} are implicitly treated as preserved.  Care must be taken when
+ * combining bitsets that the correct combining operations are applied in the
+ * correct order.
+ *
+ * <p>
+ * With the exception of {@link #SHORT_CIRCUIT}, stream characteristics can be
+ * derived from the equivalent {@link java.util.Spliterator} characteristics:
+ * {@link java.util.Spliterator#DISTINCT}, {@link java.util.Spliterator#SORTED},
+ * {@link java.util.Spliterator#ORDERED}, and
+ * {@link java.util.Spliterator#SIZED}.  A spliterator characteristics bit set
+ * can be converted to stream flags using the method
+ * {@link #fromCharacteristics(java.util.Spliterator)} and converted back using
+ * {@link #toCharacteristics(int)}.  (The bit set
+ * {@link #SPLITERATOR_CHARACTERISTICS_MASK} is used to AND with a bit set to
+ * produce a valid spliterator characteristics bit set that can be converted to
+ * stream flags.)
+ *
+ * <p>
+ * The source of a stream encapsulates a spliterator. The characteristics of
+ * that source spliterator when transformed to stream flags will be a proper
+ * subset of stream flags of that stream.
+ * For example:
+ * <pre> {@code
+ *     Spliterator s = ...;
+ *     Stream stream = Streams.stream(s);
+ *     flagsFromSplitr = fromCharacteristics(s.characteristics());
+ *     assert(flagsFromSplitr & stream.getStreamFlags() == flagsFromSplitr);
+ * }</pre>
+ *
+ * <p>
+ * An intermediate operation, performed on an input stream to create a new
+ * output stream, may preserve, clear or inject stream or operation
+ * characteristics.  Similarly, a terminal operation, performed on an input
+ * stream to produce an output result may preserve, clear or inject stream or
+ * operation characteristics.  Preservation means that if that characteristic
+ * is present on the input, then it is also present on the output.  Clearing
+ * means that the characteristic is not present on the output regardless of the
+ * input.  Injection means that the characteristic is present on the output
+ * regardless of the input.  If a characteristic is not cleared or injected then
+ * it is implicitly preserved.
+ *
+ * <p>
+ * A pipeline consists of a stream source encapsulating a spliterator, one or
+ * more intermediate operations, and finally a terminal operation that produces
+ * a result.  At each stage of the pipeline, a combined stream and operation
+ * flags can be calculated, using {@link #combineOpFlags(int, int)}.  Such flags
+ * ensure that preservation, clearing and injecting information is retained at
+ * each stage.
+ *
+ * The combined stream and operation flags for the source stage of the pipeline
+ * is calculated as follows:
+ * <pre> {@code
+ *     int flagsForSourceStage = combineOpFlags(sourceFlags, INITIAL_OPS_VALUE);
+ * }</pre>
+ *
+ * The combined stream and operation flags of each subsequent intermediate
+ * operation stage in the pipeline is calculated as follows:
+ * <pre> {@code
+ *     int flagsForThisStage = combineOpFlags(flagsForPreviousStage, thisOpFlags);
+ * }</pre>
+ *
+ * Finally the flags output from the last intermediate operation of the pipeline
+ * are combined with the operation flags of the terminal operation to produce
+ * the flags output from the pipeline.
+ *
+ * <p>Those flags can then be used to apply optimizations. For example, if
+ * {@code SIZED.isKnown(flags)} returns true then the stream size remains
+ * constant throughout the pipeline, this information can be utilized to
+ * pre-allocate data structures and combined with
+ * {@link java.util.Spliterator#SUBSIZED} that information can be utilized to
+ * perform concurrent in-place updates into a shared array.
+ *
+ * For specific details see the {@link AbstractPipeline} constructors.
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public enum StreamOpFlag {
+
+    /*
+     * Each characteristic takes up 2 bits in a bit set to accommodate
+     * preserving, clearing and setting/injecting information.
+     *
+     * This applies to stream flags, intermediate/terminal operation flags, and
+     * combined stream and operation flags. Even though the former only requires
+     * 1 bit of information per characteristic, is it more efficient when
+     * combining flags to align set and inject bits.
+     *
+     * Characteristics belong to certain types, see the Type enum. Bit masks for
+     * the types are constructed as per the following table:
+     *
+     *                        DISTINCT  SORTED  ORDERED  SIZED  SHORT_CIRCUIT
+     *          SPLITERATOR      01       01       01      01        00
+     *               STREAM      01       01       01      01        00
+     *                   OP      11       11       11      10        01
+     *          TERMINAL_OP      00       00       10      00        01
+     * UPSTREAM_TERMINAL_OP      00       00       10      00        00
+     *
+     * 01 = set/inject
+     * 10 = clear
+     * 11 = preserve
+     *
+     * Construction of the columns is performed using a simple builder for
+     * non-zero values.
+     */
+
+
+    // The following flags correspond to characteristics on Spliterator
+    // and the values MUST be equal.
+    //
+
+    /**
+     * Characteristic value signifying that, for each pair of
+     * encountered elements in a stream {@code x, y}, {@code !x.equals(y)}.
+     * <p>
+     * A stream may have this value or an intermediate operation can preserve,
+     * clear or inject this value.
+     */
+    // 0, 0x00000001
+    // Matches Spliterator.DISTINCT
+    DISTINCT(0,
+             set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
+
+    /**
+     * Characteristic value signifying that encounter order follows a natural
+     * sort order of comparable elements.
+     * <p>
+     * A stream can have this value or an intermediate operation can preserve,
+     * clear or inject this value.
+     * <p>
+     * Note: The {@link java.util.Spliterator#SORTED} characteristic can define
+     * a sort order with an associated non-null comparator.  Augmenting flag
+     * state with addition properties such that those properties can be passed
+     * to operations requires some disruptive changes for a singular use-case.
+     * Furthermore, comparing comparators for equality beyond that of identity
+     * is likely to be unreliable.  Therefore the {@code SORTED} characteristic
+     * for a defined non-natural sort order is not mapped internally to the
+     * {@code SORTED} flag.
+     */
+    // 1, 0x00000004
+    // Matches Spliterator.SORTED
+    SORTED(1,
+           set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
+
+    /**
+     * Characteristic value signifying that an encounter order is
+     * defined for stream elements.
+     * <p>
+     * A stream can have this value, an intermediate operation can preserve,
+     * clear or inject this value, or a terminal operation can preserve or clear
+     * this value.
+     */
+    // 2, 0x00000010
+    // Matches Spliterator.ORDERED
+    ORDERED(2,
+            set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP).clear(Type.TERMINAL_OP)
+                    .clear(Type.UPSTREAM_TERMINAL_OP)),
+
+    /**
+     * Characteristic value signifying that size of the stream
+     * is of a known finite size that is equal to the known finite
+     * size of the source spliterator input to the first stream
+     * in the pipeline.
+     * <p>
+     * A stream can have this value or an intermediate operation can preserve or
+     * clear this value.
+     */
+    // 3, 0x00000040
+    // Matches Spliterator.SIZED
+    SIZED(3,
+          set(Type.SPLITERATOR).set(Type.STREAM).clear(Type.OP)),
+
+    // The following Spliterator characteristics are not currently used but a
+    // gap in the bit set is deliberately retained to enable corresponding
+    // stream flags if//when required without modification to other flag values.
+    //
+    // 4, 0x00000100 NONNULL(4, ...
+    // 5, 0x00000400 IMMUTABLE(5, ...
+    // 6, 0x00001000 CONCURRENT(6, ...
+    // 7, 0x00004000 SUBSIZED(7, ...
+
+    // The following 4 flags are currently undefined and a free for any further
+    // spliterator characteristics.
+    //
+    //  8, 0x00010000
+    //  9, 0x00040000
+    // 10, 0x00100000
+    // 11, 0x00400000
+
+    // The following flags are specific to streams and operations
+    //
+
+    /**
+     * Characteristic value signifying that an operation may short-circuit the
+     * stream.
+     * <p>
+     * An intermediate operation can preserve or inject this value,
+     * or a terminal operation can preserve or inject this value.
+     */
+    // 12, 0x01000000
+    SHORT_CIRCUIT(12,
+                  set(Type.OP).set(Type.TERMINAL_OP));
+
+    // The following 2 flags are currently undefined and a free for any further
+    // stream flags if/when required
+    //
+    // 13, 0x04000000
+    // 14, 0x10000000
+    // 15, 0x40000000
+
+    /**
+     * Type of a flag
+     */
+    enum Type {
+        /**
+         * The flag is associated with spliterator characteristics.
+         */
+        SPLITERATOR,
+
+        /**
+         * The flag is associated with stream flags.
+         */
+        STREAM,
+
+        /**
+         * The flag is associated with intermediate operation flags.
+         */
+        OP,
+
+        /**
+         * The flag is associated with terminal operation flags.
+         */
+        TERMINAL_OP,
+
+        /**
+         * The flag is associated with terminal operation flags that are
+         * propagated upstream across the last stateful operation boundary
+         */
+        UPSTREAM_TERMINAL_OP
+    }
+
+    /**
+     * The bit pattern for setting/injecting a flag.
+     */
+    private static final int SET_BITS = 0b01;
+
+    /**
+     * The bit pattern for clearing a flag.
+     */
+    private static final int CLEAR_BITS = 0b10;
+
+    /**
+     * The bit pattern for preserving a flag.
+     */
+    private static final int PRESERVE_BITS = 0b11;
+
+    private static MaskBuilder set(Type t) {
+        return new MaskBuilder(new EnumMap<>(Type.class)).set(t);
+    }
+
+    private static class MaskBuilder {
+        final Map<Type, Integer> map;
+
+        MaskBuilder(Map<Type, Integer> map) {
+            this.map = map;
+        }
+
+        MaskBuilder mask(Type t, Integer i) {
+            map.put(t, i);
+            return this;
+        }
+
+        MaskBuilder set(Type t) {
+            return mask(t, SET_BITS);
+        }
+
+        MaskBuilder clear(Type t) {
+            return mask(t, CLEAR_BITS);
+        }
+
+        MaskBuilder setAndClear(Type t) {
+            return mask(t, PRESERVE_BITS);
+        }
+
+        Map<Type, Integer> build() {
+            for (Type t : Type.values()) {
+                map.putIfAbsent(t, 0b00);
+            }
+            return map;
+        }
+    }
+
+    /**
+     * The mask table for a flag, this is used to determine if a flag
+     * corresponds to a certain flag type and for creating mask constants.
+     */
+    private final Map<Type, Integer> maskTable;
+
+    /**
+     * The bit position in the bit mask.
+     */
+    private final int bitPosition;
+
+    /**
+     * The set 2 bit set offset at the bit position.
+     */
+    private final int set;
+
+    /**
+     * The clear 2 bit set offset at the bit position.
+     */
+    private final int clear;
+
+    /**
+     * The preserve 2 bit set offset at the bit position.
+     */
+    private final int preserve;
+
+    private StreamOpFlag(int position, MaskBuilder maskBuilder) {
+        this.maskTable = maskBuilder.build();
+        // Two bits per flag
+        position *= 2;
+        this.bitPosition = position;
+        this.set = SET_BITS << position;
+        this.clear = CLEAR_BITS << position;
+        this.preserve = PRESERVE_BITS << position;
+    }
+
+    /**
+     * Gets the bitmap associated with setting this characteristic.
+     *
+     * @return the bitmap for setting this characteristic
+     */
+    // Android-changed: Made public for CTS tests only.
+    public int set() {
+        return set;
+    }
+
+    /**
+     * Gets the bitmap associated with clearing this characteristic.
+     *
+     * @return the bitmap for clearing this characteristic
+     */
+    // Android-changed: Made public for CTS tests only.
+    public int clear() {
+        return clear;
+    }
+
+    /**
+     * Determines if this flag is a stream-based flag.
+     *
+     * @return true if a stream-based flag, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isStreamFlag() {
+        return maskTable.get(Type.STREAM) > 0;
+    }
+
+    /**
+     * Checks if this flag is set on stream flags, injected on operation flags,
+     * and injected on combined stream and operation flags.
+     *
+     * @param flags the stream flags, operation flags, or combined stream and
+     *        operation flags
+     * @return true if this flag is known, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isKnown(int flags) {
+        return (flags & preserve) == set;
+    }
+
+    /**
+     * Checks if this flag is cleared on operation flags or combined stream and
+     * operation flags.
+     *
+     * @param flags the operation flags or combined stream and operations flags.
+     * @return true if this flag is preserved, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isCleared(int flags) {
+        return (flags & preserve) == clear;
+    }
+
+    /**
+     * Checks if this flag is preserved on combined stream and operation flags.
+     *
+     * @param flags the combined stream and operations flags.
+     * @return true if this flag is preserved, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isPreserved(int flags) {
+        return (flags & preserve) == preserve;
+    }
+
+    /**
+     * Determines if this flag can be set for a flag type.
+     *
+     * @param t the flag type.
+     * @return true if this flag can be set for the flag type, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean canSet(Type t) {
+        return (maskTable.get(t) & SET_BITS) > 0;
+    }
+
+    /**
+     * The bit mask for spliterator characteristics
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int SPLITERATOR_CHARACTERISTICS_MASK = createMask(Type.SPLITERATOR);
+
+    /**
+     * The bit mask for source stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int STREAM_MASK = createMask(Type.STREAM);
+
+    /**
+     * The bit mask for intermediate operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int OP_MASK = createMask(Type.OP);
+
+    /**
+     * The bit mask for terminal operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int TERMINAL_OP_MASK = createMask(Type.TERMINAL_OP);
+
+    /**
+     * The bit mask for upstream terminal operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int UPSTREAM_TERMINAL_OP_MASK = createMask(Type.UPSTREAM_TERMINAL_OP);
+
+    private static int createMask(Type t) {
+        int mask = 0;
+        for (StreamOpFlag flag : StreamOpFlag.values()) {
+            mask |= flag.maskTable.get(t) << flag.bitPosition;
+        }
+        return mask;
+    }
+
+    /**
+     * Complete flag mask.
+     */
+    private static final int FLAG_MASK = createFlagMask();
+
+    private static int createFlagMask() {
+        int mask = 0;
+        for (StreamOpFlag flag : StreamOpFlag.values()) {
+            mask |= flag.preserve;
+        }
+        return mask;
+    }
+
+    /**
+     * Flag mask for stream flags that are set.
+     */
+    private static final int FLAG_MASK_IS = STREAM_MASK;
+
+    /**
+     * Flag mask for stream flags that are cleared.
+     */
+    private static final int FLAG_MASK_NOT = STREAM_MASK << 1;
+
+    /**
+     * The initial value to be combined with the stream flags of the first
+     * stream in the pipeline.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int INITIAL_OPS_VALUE = FLAG_MASK_IS | FLAG_MASK_NOT;
+
+    /**
+     * The bit value to set or inject {@link #DISTINCT}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_DISTINCT = DISTINCT.set;
+
+    /**
+     * The bit value to clear {@link #DISTINCT}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_DISTINCT = DISTINCT.clear;
+
+    /**
+     * The bit value to set or inject {@link #SORTED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_SORTED = SORTED.set;
+
+    /**
+     * The bit value to clear {@link #SORTED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_SORTED = SORTED.clear;
+
+    /**
+     * The bit value to set or inject {@link #ORDERED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_ORDERED = ORDERED.set;
+
+    /**
+     * The bit value to clear {@link #ORDERED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_ORDERED = ORDERED.clear;
+
+    /**
+     * The bit value to set {@link #SIZED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_SIZED = SIZED.set;
+
+    /**
+     * The bit value to clear {@link #SIZED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_SIZED = SIZED.clear;
+
+    /**
+     * The bit value to inject {@link #SHORT_CIRCUIT}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_SHORT_CIRCUIT = SHORT_CIRCUIT.set;
+
+    private static int getMask(int flags) {
+        return (flags == 0)
+               ? FLAG_MASK
+               : ~(flags | ((FLAG_MASK_IS & flags) << 1) | ((FLAG_MASK_NOT & flags) >> 1));
+    }
+
+    /**
+     * Combines stream or operation flags with previously combined stream and
+     * operation flags to produce updated combined stream and operation flags.
+     * <p>
+     * A flag set on stream flags or injected on operation flags,
+     * and injected combined stream and operation flags,
+     * will be injected on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag set on stream flags or injected on operation flags,
+     * and cleared on the combined stream and operation flags,
+     * will be cleared on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag set on the stream flags or injected on operation flags,
+     * and preserved on the combined stream and operation flags,
+     * will be injected on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag not set on the stream flags or cleared/preserved on operation
+     * flags, and injected on the combined stream and operation flags,
+     * will be injected on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag not set on the stream flags or cleared/preserved on operation
+     * flags, and cleared on the combined stream and operation flags,
+     * will be cleared on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag not set on the stream flags,
+     * and preserved on the combined stream and operation flags
+     * will be preserved on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag cleared on operation flags,
+     * and preserved on the combined stream and operation flags
+     * will be cleared on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag preserved on operation flags,
+     * and preserved on the combined stream and operation flags
+     * will be preserved on the updated combined stream and operation flags.
+     *
+     * @param newStreamOrOpFlags the stream or operation flags.
+     * @param prevCombOpFlags previously combined stream and operation flags.
+     *        The value {#link INITIAL_OPS_VALUE} must be used as the seed value.
+     * @return the updated combined stream and operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int combineOpFlags(int newStreamOrOpFlags, int prevCombOpFlags) {
+        // 0x01 or 0x10 nibbles are transformed to 0x11
+        // 0x00 nibbles remain unchanged
+        // Then all the bits are flipped
+        // Then the result is logically or'ed with the operation flags.
+        return (prevCombOpFlags & StreamOpFlag.getMask(newStreamOrOpFlags)) | newStreamOrOpFlags;
+    }
+
+    /**
+     * Converts combined stream and operation flags to stream flags.
+     *
+     * <p>Each flag injected on the combined stream and operation flags will be
+     * set on the stream flags.
+     *
+     * @param combOpFlags the combined stream and operation flags.
+     * @return the stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int toStreamFlags(int combOpFlags) {
+        // By flipping the nibbles 0x11 become 0x00 and 0x01 become 0x10
+        // Shift left 1 to restore set flags and mask off anything other than the set flags
+        return ((~combOpFlags) >> 1) & FLAG_MASK_IS & combOpFlags;
+    }
+
+    /**
+     * Converts stream flags to a spliterator characteristic bit set.
+     *
+     * @param streamFlags the stream flags.
+     * @return the spliterator characteristic bit set.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int toCharacteristics(int streamFlags) {
+        return streamFlags & SPLITERATOR_CHARACTERISTICS_MASK;
+    }
+
+    /**
+     * Converts a spliterator characteristic bit set to stream flags.
+     *
+     * @implSpec
+     * If the spliterator is naturally {@code SORTED} (the associated
+     * {@code Comparator} is {@code null}) then the characteristic is converted
+     * to the {@link #SORTED} flag, otherwise the characteristic is not
+     * converted.
+     *
+     * @param spliterator the spliterator from which to obtain characteristic
+     *        bit set.
+     * @return the stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int fromCharacteristics(Spliterator<?> spliterator) {
+        int characteristics = spliterator.characteristics();
+        if ((characteristics & Spliterator.SORTED) != 0 && spliterator.getComparator() != null) {
+            // Do not propagate the SORTED characteristic if it does not correspond
+            // to a natural sort order
+            return characteristics & SPLITERATOR_CHARACTERISTICS_MASK & ~Spliterator.SORTED;
+        }
+        else {
+            return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
+        }
+    }
+
+    /**
+     * Converts a spliterator characteristic bit set to stream flags.
+     *
+     * @param characteristics the spliterator characteristic bit set.
+     * @return the stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int fromCharacteristics(int characteristics) {
+        return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
+    }
+}
diff --git a/java/util/stream/StreamOpFlagTestHelper.java b/java/util/stream/StreamOpFlagTestHelper.java
new file mode 100644
index 0000000..11ed0f1
--- /dev/null
+++ b/java/util/stream/StreamOpFlagTestHelper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.EnumSet;
+
+public class StreamOpFlagTestHelper {
+
+    /** EnumSet containing stream flags */
+    private static final EnumSet<StreamOpFlag> allStreamFlags;
+
+    static {
+        allStreamFlags = EnumSet.allOf(StreamOpFlag.class);
+        for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class))
+            if (!f.isStreamFlag())
+                allStreamFlags.remove(f);
+    }
+
+
+    static EnumSet<StreamOpFlag> allStreamFlags() {
+        // EnumSet is mutable
+        return allStreamFlags.clone();
+    }
+
+    public static boolean isStreamOrdered(Stream<?> s) {
+        return StreamOpFlag.ORDERED.isKnown(OpTestCase.getStreamFlags(s));
+    }
+}
diff --git a/java/util/stream/StreamOpFlagsTest.java b/java/util/stream/StreamOpFlagsTest.java
new file mode 100644
index 0000000..aa47aa2
--- /dev/null
+++ b/java/util/stream/StreamOpFlagsTest.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.StreamOpFlag.*;
+import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class StreamOpFlagsTest {
+
+    public void testNullCombine() {
+        int sourceFlags = StreamOpFlag.IS_SIZED;
+
+        assertEquals(sourceFlags, toStreamFlags(combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE)));
+    }
+
+    public void testInitialOpFlagsFromSourceFlags() {
+        List<StreamOpFlag> flags = new ArrayList<>(StreamOpFlagTestHelper.allStreamFlags());
+        for (int i = 0; i < (1 << flags.size()); i++)  {
+            int sourceFlags = 0;
+            for (int f = 0; f < flags.size(); f++) {
+                if ((i & (1 << f)) != 0)  {
+                    sourceFlags |= flags.get(f).set();
+                }
+            }
+
+            int opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            assertEquals(opsFlags, (~(sourceFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE);
+        }
+    }
+
+    public void testSameCombine() {
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            int sourceFlags = f.set();
+            int opsFlags;
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.set(), opsFlags);
+            assertEquals(sourceFlags, toStreamFlags(opsFlags));
+        }
+    }
+
+    public void testOpClear() {
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            // Clear when source not set
+            int sourceFlags = 0;
+            int opsFlags;
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.clear(), opsFlags);
+            assertEquals(sourceFlags, toStreamFlags(opsFlags));
+
+            // Clear when source set
+            sourceFlags = f.set();
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.clear(), opsFlags);
+            assertEquals(0, toStreamFlags(opsFlags));
+        }
+    }
+
+    public void testOpInject() {
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            // Set when source not set
+            int sourceFlags = 0;
+            int opsFlags;
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.set(), opsFlags);
+            assertEquals(f.set(), toStreamFlags(opsFlags));
+
+            // Set when source set
+            sourceFlags = f.set();
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.set(), opsFlags);
+            assertEquals(sourceFlags, toStreamFlags(opsFlags));
+        }
+    }
+
+    public void testPairSet() {
+        List<Integer> sourceFlagsList
+                = StreamOpFlagTestHelper.allStreamFlags().stream().map(StreamOpFlag::set).collect(toList());
+        sourceFlagsList.add(0, 0);
+
+        for (int sourceFlags : sourceFlagsList) {
+            for (StreamOpFlag f1 : StreamOpFlagTestHelper.allStreamFlags()) {
+                for (StreamOpFlag f2 : StreamOpFlagTestHelper.allStreamFlags()) {
+                    int opsFlags;
+
+                    opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+                    opsFlags = combineOpFlags(f1.set(), opsFlags);
+                    opsFlags = combineOpFlags(f2.set(), opsFlags);
+                    assertEquals(sourceFlags | f1.set() | f2.set(), toStreamFlags(opsFlags));
+                }
+            }
+        }
+    }
+
+    public void testPairSetAndClear() {
+        List<Integer> sourceFlagsList
+                = StreamOpFlagTestHelper.allStreamFlags().stream().map(StreamOpFlag::set).collect(toList());
+        sourceFlagsList.add(0, 0);
+
+        for (int sourceFlags : sourceFlagsList) {
+            for (StreamOpFlag f1 : StreamOpFlagTestHelper.allStreamFlags())  {
+                for (StreamOpFlag f2 : StreamOpFlagTestHelper.allStreamFlags()) {
+                    int opsFlags;
+
+                    opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+                    opsFlags = combineOpFlags(f1.set(), opsFlags);
+                    opsFlags = combineOpFlags(f2.clear(), opsFlags);
+                    if (f1 == f2)
+                        assertEquals((f2.set() == sourceFlags) ? 0 : sourceFlags, toStreamFlags(opsFlags));
+                    else
+                        assertEquals((f2.set() == sourceFlags) ? f1.set() : sourceFlags | f1.set(), toStreamFlags(opsFlags));
+                }
+            }
+        }
+    }
+
+    public void testShortCircuit() {
+        int opsFlags = combineOpFlags(0, StreamOpFlag.INITIAL_OPS_VALUE);
+        assertFalse(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+
+        opsFlags = combineOpFlags(StreamOpFlag.IS_SHORT_CIRCUIT, opsFlags);
+        assertTrue(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+
+        opsFlags = combineOpFlags(0, opsFlags);
+        assertTrue(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+    }
+
+    public void testApplySourceFlags() {
+        int sourceFlags = StreamOpFlag.IS_SIZED | StreamOpFlag.IS_DISTINCT;
+
+        List<Integer> ops = Arrays.asList(StreamOpFlag.NOT_SIZED, StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+
+        int opsFlags = StreamOpFlag.combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+        for (int opFlags : ops) {
+            opsFlags = combineOpFlags(opFlags, opsFlags);
+        }
+        assertFalse(StreamOpFlag.SIZED.isKnown(opsFlags));
+        assertTrue(StreamOpFlag.SIZED.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.SIZED.isPreserved(opsFlags));
+        assertTrue(StreamOpFlag.DISTINCT.isKnown(opsFlags));
+        assertFalse(StreamOpFlag.DISTINCT.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.DISTINCT.isPreserved(opsFlags));
+        assertTrue(StreamOpFlag.SORTED.isKnown(opsFlags));
+        assertFalse(StreamOpFlag.SORTED.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.SORTED.isPreserved(opsFlags));
+        assertTrue(StreamOpFlag.ORDERED.isKnown(opsFlags));
+        assertFalse(StreamOpFlag.ORDERED.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.ORDERED.isPreserved(opsFlags));
+
+        int streamFlags = toStreamFlags(opsFlags);
+        assertFalse(StreamOpFlag.SIZED.isKnown(streamFlags));
+        assertTrue(StreamOpFlag.DISTINCT.isKnown(streamFlags));
+        assertTrue(StreamOpFlag.SORTED.isKnown(streamFlags));
+        assertTrue(StreamOpFlag.ORDERED.isKnown(streamFlags));
+    }
+
+    public void testSpliteratorMask() {
+        assertSpliteratorMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertSpliteratorMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertSpliteratorMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertSpliteratorMask(StreamOpFlag.ORDERED.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+        assertSpliteratorMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertSpliteratorMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertSpliteratorMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.SPLITERATOR_CHARACTERISTICS_MASK, expected);
+    }
+
+    public void testStreamMask() {
+        assertStreamMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertStreamMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertStreamMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertStreamMask(StreamOpFlag.ORDERED.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+        assertStreamMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertStreamMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertStreamMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.STREAM_MASK, expected);
+    }
+
+    public void testOpMask() {
+        assertOpMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertOpMask(StreamOpFlag.DISTINCT.clear(), StreamOpFlag.NOT_DISTINCT);
+
+        assertOpMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertOpMask(StreamOpFlag.SORTED.clear(), StreamOpFlag.NOT_SORTED);
+
+        assertOpMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+        assertOpMask(StreamOpFlag.SIZED.set(), 0);
+        assertOpMask(StreamOpFlag.SIZED.clear(), StreamOpFlag.NOT_SIZED);
+
+        assertOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), StreamOpFlag.IS_SHORT_CIRCUIT);
+        assertOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertOpMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.OP_MASK, expected);
+    }
+
+    public void testTerminalOpMask() {
+        assertTerminalOpMask(StreamOpFlag.DISTINCT.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertTerminalOpMask(StreamOpFlag.SORTED.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertTerminalOpMask(StreamOpFlag.ORDERED.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+        assertTerminalOpMask(StreamOpFlag.SIZED.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), StreamOpFlag.IS_SHORT_CIRCUIT);
+        assertTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertTerminalOpMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.TERMINAL_OP_MASK, expected);
+    }
+
+    public void testUpstreamTerminalOpMask() {
+        assertUpstreamTerminalOpMask(StreamOpFlag.DISTINCT.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.SORTED.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.ORDERED.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.SIZED.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertUpstreamTerminalOpMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.UPSTREAM_TERMINAL_OP_MASK, expected);
+    }
+
+    public void testSpliteratorCharacteristics() {
+        assertEquals(Spliterator.DISTINCT, StreamOpFlag.IS_DISTINCT);
+        assertEquals(Spliterator.SORTED, StreamOpFlag.IS_SORTED);
+        assertEquals(Spliterator.ORDERED, StreamOpFlag.IS_ORDERED);
+        assertEquals(Spliterator.SIZED, StreamOpFlag.IS_SIZED);
+
+        List<Integer> others = Arrays.asList(Spliterator.NONNULL, Spliterator.IMMUTABLE,
+                                             Spliterator.CONCURRENT, Spliterator.SUBSIZED);
+        for (int c : others) {
+            assertNotEquals(c, StreamOpFlag.IS_SHORT_CIRCUIT);
+        }
+    }
+
+    public void testSpliteratorCharacteristicsMask() {
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.ORDERED.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertSpliteratorCharacteristicsMask(int actual, int expected) {
+        assertEquals(StreamOpFlag.fromCharacteristics(actual), expected);
+    }
+
+    public void testSpliteratorSorted() {
+        class SortedEmptySpliterator implements Spliterator<Object> {
+            final Comparator<Object> c;
+
+            SortedEmptySpliterator(Comparator<Object> c) {
+                this.c = c;
+            }
+
+            @Override
+            public Spliterator<Object> trySplit() {
+                return null;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super Object> action) {
+                return false;
+            }
+
+            @Override
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+
+            @Override
+            public int characteristics() {
+                return Spliterator.SORTED;
+            }
+
+            @Override
+            public Comparator<? super Object> getComparator() {
+                return c;
+            }
+        };
+
+        {
+            int flags = StreamOpFlag.fromCharacteristics(new SortedEmptySpliterator(null));
+            assertEquals(flags, StreamOpFlag.IS_SORTED);
+        }
+
+        {
+            int flags = StreamOpFlag.fromCharacteristics(new SortedEmptySpliterator((a, b) -> 0));
+            assertEquals(flags, 0);
+        }
+    }
+}
diff --git a/java/util/stream/StreamReuseTest.java b/java/util/stream/StreamReuseTest.java
new file mode 100644
index 0000000..0ac9d68
--- /dev/null
+++ b/java/util/stream/StreamReuseTest.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.function.Function;
+
+import static org.testng.Assert.fail;
+
+/**
+ * StreamReuseTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class StreamReuseTest {
+
+    private <T, U, E, S extends BaseStream<E, S>, D extends TestData<E, S>> void assertSecondFails(
+            D data,
+            Function<S, T> first,
+            Function<S, U> second,
+            Class<? extends Throwable> exception,
+            String text) {
+        S stream = data.stream();
+        T fr = first.apply(stream);
+        try {
+            U sr = second.apply(stream);
+            fail(text + " (seq)");
+        }
+        catch (Throwable e) {
+            if (exception.isAssignableFrom(e.getClass())) {
+                // Expected
+            }
+            else if (e instanceof Error)
+                throw (Error) e;
+            else if (e instanceof RuntimeException)
+                throw (RuntimeException) e;
+            else
+                throw new AssertionError("Unexpected exception " + e.getClass(), e);
+        }
+
+        stream = data.parallelStream();
+        fr = first.apply(stream);
+        try {
+            U sr = second.apply(stream);
+            fail(text + " (par)");
+        }
+        catch (Throwable e) {
+            if (exception.isAssignableFrom(e.getClass())) {
+                // Expected
+            }
+            else if (e instanceof Error)
+                throw (Error) e;
+            else if (e instanceof RuntimeException)
+                throw (RuntimeException) e;
+            else
+                throw new AssertionError("Unexpected exception " + e.getClass(), e);
+        }
+    }
+
+    // Stream
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::findFirst, Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream findFirst / findFirst succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::findFirst, (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream findFirst / map succeeded erroneously");
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream map / findFirst succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::findFirst, Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream findFirst / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream distinct / findFirst succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::iterator, Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::iterator, Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream iterator / findFirst succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::findFirst, Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream findFirst / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::iterator, (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::iterator, Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream distinct / iterator succeeded erroneously");
+    }
+
+    // IntStream
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::sum, IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream sum / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::sum, (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream sum / map succeeded erroneously");
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream map / sum succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::sum, IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream sum / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream distinct / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::iterator, IntStream::iterator,
+                          IllegalStateException.class,
+                          "IntStream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::iterator, IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream iterator / sum succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::sum, IntStream::iterator,
+                          IllegalStateException.class,
+                          "Stream sum / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::iterator, (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), IntStream::iterator,
+                          IllegalStateException.class,
+                          "IntStream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::iterator, IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, IntStream::iterator,
+                          IllegalStateException.class,
+                          "IntStream distinct / iterator succeeded erroneously");
+    }
+
+    // LongStream
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::sum, LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream sum / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::sum, (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream sum / map succeeded erroneously");
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream map / sum succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::sum, LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream sum / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream distinct / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::iterator, LongStream::iterator,
+                          IllegalStateException.class,
+                          "LongStream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::iterator, LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream iterator / sum succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::sum, LongStream::iterator,
+                          IllegalStateException.class,
+                          "Stream sum / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::iterator, (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), LongStream::iterator,
+                          IllegalStateException.class,
+                          "LongStream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::iterator, LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, LongStream::iterator,
+                          IllegalStateException.class,
+                          "LongStream distinct / iterator succeeded erroneously");
+    }
+
+    // DoubleStream
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::sum, DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream sum / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::sum, (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream sum / map succeeded erroneously");
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream map / sum succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::sum, DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream sum / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream distinct / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::iterator, DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "DoubleStream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::iterator, DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream iterator / sum succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::sum, DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "Stream sum / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::iterator, (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "DoubleStream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::iterator, DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "DoubleStream distinct / iterator succeeded erroneously");
+    }
+}
diff --git a/java/util/stream/StreamShape.java b/java/util/stream/StreamShape.java
new file mode 100644
index 0000000..5bcae4a
--- /dev/null
+++ b/java/util/stream/StreamShape.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * An enum describing the known shape specializations for stream abstractions.
+ * Each will correspond to a specific subinterface of {@link BaseStream}
+ * (e.g., {@code REFERENCE} corresponds to {@code Stream}, {@code INT_VALUE}
+ * corresponds to {@code IntStream}).  Each may also correspond to
+ * specializations of value-handling abstractions such as {@code Spliterator},
+ * {@code Consumer}, etc.
+ *
+ * @apiNote
+ * This enum is used by implementations to determine compatibility between
+ * streams and operations (i.e., if the output shape of a stream is compatible
+ * with the input shape of the next operation).
+ *
+ * <p>Some APIs require you to specify both a generic type and a stream shape
+ * for input or output elements, such as {@link TerminalOp} which has both
+ * generic type parameters for its input types, and a getter for the
+ * input shape.  When representing primitive streams in this way, the
+ * generic type parameter should correspond to the wrapper type for that
+ * primitive type.
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public enum StreamShape {
+    /**
+     * The shape specialization corresponding to {@code Stream} and elements
+     * that are object references.
+     */
+    REFERENCE,
+    /**
+     * The shape specialization corresponding to {@code IntStream} and elements
+     * that are {@code int} values.
+     */
+    INT_VALUE,
+    /**
+     * The shape specialization corresponding to {@code LongStream} and elements
+     * that are {@code long} values.
+     */
+    LONG_VALUE,
+    /**
+     * The shape specialization corresponding to {@code DoubleStream} and
+     * elements that are {@code double} values.
+     */
+    DOUBLE_VALUE
+}
diff --git a/java/util/stream/StreamSpliterators.java b/java/util/stream/StreamSpliterators.java
new file mode 100644
index 0000000..6768342
--- /dev/null
+++ b/java/util/stream/StreamSpliterators.java
@@ -0,0 +1,1548 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleSupplier;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+import java.util.function.LongConsumer;
+import java.util.function.LongSupplier;
+import java.util.function.Supplier;
+
+/**
+ * Spliterator implementations for wrapping and delegating spliterators, used
+ * in the implementation of the {@link Stream#spliterator()} method.
+ *
+ * @since 1.8
+ */
+class StreamSpliterators {
+
+    /**
+     * Abstract wrapping spliterator that binds to the spliterator of a
+     * pipeline helper on first operation.
+     *
+     * <p>This spliterator is not late-binding and will bind to the source
+     * spliterator when first operated on.
+     *
+     * <p>A wrapping spliterator produced from a sequential stream
+     * cannot be split if there are stateful operations present.
+     */
+    private static abstract class AbstractWrappingSpliterator<P_IN, P_OUT,
+                                                              T_BUFFER extends AbstractSpinedBuffer>
+            implements Spliterator<P_OUT> {
+
+        // @@@ Detect if stateful operations are present or not
+        //     If not then can split otherwise cannot
+
+        /**
+         * True if this spliterator supports splitting
+         */
+        final boolean isParallel;
+
+        final PipelineHelper<P_OUT> ph;
+
+        /**
+         * Supplier for the source spliterator.  Client provides either a
+         * spliterator or a supplier.
+         */
+        private Supplier<Spliterator<P_IN>> spliteratorSupplier;
+
+        /**
+         * Source spliterator.  Either provided from client or obtained from
+         * supplier.
+         */
+        Spliterator<P_IN> spliterator;
+
+        /**
+         * Sink chain for the downstream stages of the pipeline, ultimately
+         * leading to the buffer. Used during partial traversal.
+         */
+        Sink<P_IN> bufferSink;
+
+        /**
+         * A function that advances one element of the spliterator, pushing
+         * it to bufferSink.  Returns whether any elements were processed.
+         * Used during partial traversal.
+         */
+        BooleanSupplier pusher;
+
+        /** Next element to consume from the buffer, used during partial traversal */
+        long nextToConsume;
+
+        /** Buffer into which elements are pushed.  Used during partial traversal. */
+        T_BUFFER buffer;
+
+        /**
+         * True if full traversal has occurred (with possible cancelation).
+         * If doing a partial traversal, there may be still elements in buffer.
+         */
+        boolean finished;
+
+        /**
+         * Construct an AbstractWrappingSpliterator from a
+         * {@code Supplier<Spliterator>}.
+         */
+        AbstractWrappingSpliterator(PipelineHelper<P_OUT> ph,
+                                    Supplier<Spliterator<P_IN>> spliteratorSupplier,
+                                    boolean parallel) {
+            this.ph = ph;
+            this.spliteratorSupplier = spliteratorSupplier;
+            this.spliterator = null;
+            this.isParallel = parallel;
+        }
+
+        /**
+         * Construct an AbstractWrappingSpliterator from a
+         * {@code Spliterator}.
+         */
+        AbstractWrappingSpliterator(PipelineHelper<P_OUT> ph,
+                                    Spliterator<P_IN> spliterator,
+                                    boolean parallel) {
+            this.ph = ph;
+            this.spliteratorSupplier = null;
+            this.spliterator = spliterator;
+            this.isParallel = parallel;
+        }
+
+        /**
+         * Called before advancing to set up spliterator, if needed.
+         */
+        final void init() {
+            if (spliterator == null) {
+                spliterator = spliteratorSupplier.get();
+                spliteratorSupplier = null;
+            }
+        }
+
+        /**
+         * Get an element from the source, pushing it into the sink chain,
+         * setting up the buffer if needed
+         * @return whether there are elements to consume from the buffer
+         */
+        final boolean doAdvance() {
+            if (buffer == null) {
+                if (finished)
+                    return false;
+
+                init();
+                initPartialTraversalState();
+                nextToConsume = 0;
+                bufferSink.begin(spliterator.getExactSizeIfKnown());
+                return fillBuffer();
+            }
+            else {
+                ++nextToConsume;
+                boolean hasNext = nextToConsume < buffer.count();
+                if (!hasNext) {
+                    nextToConsume = 0;
+                    buffer.clear();
+                    hasNext = fillBuffer();
+                }
+                return hasNext;
+            }
+        }
+
+        /**
+         * Invokes the shape-specific constructor with the provided arguments
+         * and returns the result.
+         */
+        abstract AbstractWrappingSpliterator<P_IN, P_OUT, ?> wrap(Spliterator<P_IN> s);
+
+        /**
+         * Initializes buffer, sink chain, and pusher for a shape-specific
+         * implementation.
+         */
+        abstract void initPartialTraversalState();
+
+        @Override
+        public Spliterator<P_OUT> trySplit() {
+            if (isParallel && !finished) {
+                init();
+
+                Spliterator<P_IN> split = spliterator.trySplit();
+                return (split == null) ? null : wrap(split);
+            }
+            else
+                return null;
+        }
+
+        /**
+         * If the buffer is empty, push elements into the sink chain until
+         * the source is empty or cancellation is requested.
+         * @return whether there are elements to consume from the buffer
+         */
+        private boolean fillBuffer() {
+            while (buffer.count() == 0) {
+                if (bufferSink.cancellationRequested() || !pusher.getAsBoolean()) {
+                    if (finished)
+                        return false;
+                    else {
+                        bufferSink.end(); // might trigger more elements
+                        finished = true;
+                    }
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public final long estimateSize() {
+            init();
+            // Use the estimate of the wrapped spliterator
+            // Note this may not be accurate if there are filter/flatMap
+            // operations filtering or adding elements to the stream
+            return spliterator.estimateSize();
+        }
+
+        @Override
+        public final long getExactSizeIfKnown() {
+            init();
+            return StreamOpFlag.SIZED.isKnown(ph.getStreamAndOpFlags())
+                   ? spliterator.getExactSizeIfKnown()
+                   : -1;
+        }
+
+        @Override
+        public final int characteristics() {
+            init();
+
+            // Get the characteristics from the pipeline
+            int c = StreamOpFlag.toCharacteristics(StreamOpFlag.toStreamFlags(ph.getStreamAndOpFlags()));
+
+            // Mask off the size and uniform characteristics and replace with
+            // those of the spliterator
+            // Note that a non-uniform spliterator can change from something
+            // with an exact size to an estimate for a sub-split, for example
+            // with HashSet where the size is known at the top level spliterator
+            // but for sub-splits only an estimate is known
+            if ((c & Spliterator.SIZED) != 0) {
+                c &= ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+                c |= (spliterator.characteristics() & (Spliterator.SIZED | Spliterator.SUBSIZED));
+            }
+
+            return c;
+        }
+
+        @Override
+        public Comparator<? super P_OUT> getComparator() {
+            if (!hasCharacteristics(SORTED))
+                throw new IllegalStateException();
+            return null;
+        }
+
+        @Override
+        public final String toString() {
+            return String.format("%s[%s]", getClass().getName(), spliterator);
+        }
+    }
+
+    static final class WrappingSpliterator<P_IN, P_OUT>
+            extends AbstractWrappingSpliterator<P_IN, P_OUT, SpinedBuffer<P_OUT>> {
+
+        WrappingSpliterator(PipelineHelper<P_OUT> ph,
+                            Supplier<Spliterator<P_IN>> supplier,
+                            boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        WrappingSpliterator(PipelineHelper<P_OUT> ph,
+                            Spliterator<P_IN> spliterator,
+                            boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        WrappingSpliterator<P_IN, P_OUT> wrap(Spliterator<P_IN> s) {
+            return new WrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer<P_OUT> b = new SpinedBuffer<>();
+            buffer = b;
+            bufferSink = ph.wrapSink(b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super P_OUT> consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super P_OUT> consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink<P_OUT>) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    static final class IntWrappingSpliterator<P_IN>
+            extends AbstractWrappingSpliterator<P_IN, Integer, SpinedBuffer.OfInt>
+            implements Spliterator.OfInt {
+
+        IntWrappingSpliterator(PipelineHelper<Integer> ph,
+                               Supplier<Spliterator<P_IN>> supplier,
+                               boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        IntWrappingSpliterator(PipelineHelper<Integer> ph,
+                               Spliterator<P_IN> spliterator,
+                               boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        AbstractWrappingSpliterator<P_IN, Integer, ?> wrap(Spliterator<P_IN> s) {
+            return new IntWrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer.OfInt b = new SpinedBuffer.OfInt();
+            buffer = b;
+            bufferSink = ph.wrapSink((Sink.OfInt) b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public Spliterator.OfInt trySplit() {
+            return (Spliterator.OfInt) super.trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink.OfInt) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    static final class LongWrappingSpliterator<P_IN>
+            extends AbstractWrappingSpliterator<P_IN, Long, SpinedBuffer.OfLong>
+            implements Spliterator.OfLong {
+
+        LongWrappingSpliterator(PipelineHelper<Long> ph,
+                                Supplier<Spliterator<P_IN>> supplier,
+                                boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        LongWrappingSpliterator(PipelineHelper<Long> ph,
+                                Spliterator<P_IN> spliterator,
+                                boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        AbstractWrappingSpliterator<P_IN, Long, ?> wrap(Spliterator<P_IN> s) {
+            return new LongWrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer.OfLong b = new SpinedBuffer.OfLong();
+            buffer = b;
+            bufferSink = ph.wrapSink((Sink.OfLong) b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public Spliterator.OfLong trySplit() {
+            return (Spliterator.OfLong) super.trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink.OfLong) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    static final class DoubleWrappingSpliterator<P_IN>
+            extends AbstractWrappingSpliterator<P_IN, Double, SpinedBuffer.OfDouble>
+            implements Spliterator.OfDouble {
+
+        DoubleWrappingSpliterator(PipelineHelper<Double> ph,
+                                  Supplier<Spliterator<P_IN>> supplier,
+                                  boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        DoubleWrappingSpliterator(PipelineHelper<Double> ph,
+                                  Spliterator<P_IN> spliterator,
+                                  boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        AbstractWrappingSpliterator<P_IN, Double, ?> wrap(Spliterator<P_IN> s) {
+            return new DoubleWrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer.OfDouble b = new SpinedBuffer.OfDouble();
+            buffer = b;
+            bufferSink = ph.wrapSink((Sink.OfDouble) b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public Spliterator.OfDouble trySplit() {
+            return (Spliterator.OfDouble) super.trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink.OfDouble) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    /**
+     * Spliterator implementation that delegates to an underlying spliterator,
+     * acquiring the spliterator from a {@code Supplier<Spliterator>} on the
+     * first call to any spliterator method.
+     * @param <T>
+     */
+    static class DelegatingSpliterator<T, T_SPLITR extends Spliterator<T>>
+            implements Spliterator<T> {
+        private final Supplier<? extends T_SPLITR> supplier;
+
+        private T_SPLITR s;
+
+        DelegatingSpliterator(Supplier<? extends T_SPLITR> supplier) {
+            this.supplier = supplier;
+        }
+
+        T_SPLITR get() {
+            if (s == null) {
+                s = supplier.get();
+            }
+            return s;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public T_SPLITR trySplit() {
+            return (T_SPLITR) get().trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> consumer) {
+            return get().tryAdvance(consumer);
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> consumer) {
+            get().forEachRemaining(consumer);
+        }
+
+        @Override
+        public long estimateSize() {
+            return get().estimateSize();
+        }
+
+        @Override
+        public int characteristics() {
+            return get().characteristics();
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            return get().getComparator();
+        }
+
+        @Override
+        public long getExactSizeIfKnown() {
+            return get().getExactSizeIfKnown();
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getName() + "[" + get() + "]";
+        }
+
+        static class OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+            extends DelegatingSpliterator<T, T_SPLITR>
+            implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+            OfPrimitive(Supplier<? extends T_SPLITR> supplier) {
+                super(supplier);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS consumer) {
+                return get().tryAdvance(consumer);
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS consumer) {
+                get().forEachRemaining(consumer);
+            }
+        }
+
+        static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, Spliterator.OfInt>
+                implements Spliterator.OfInt {
+
+            OfInt(Supplier<Spliterator.OfInt> supplier) {
+                super(supplier);
+            }
+        }
+
+        static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, Spliterator.OfLong>
+                implements Spliterator.OfLong {
+
+            OfLong(Supplier<Spliterator.OfLong> supplier) {
+                super(supplier);
+            }
+        }
+
+        static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, Spliterator.OfDouble>
+                implements Spliterator.OfDouble {
+
+            OfDouble(Supplier<Spliterator.OfDouble> supplier) {
+                super(supplier);
+            }
+        }
+    }
+
+    /**
+     * A slice Spliterator from a source Spliterator that reports
+     * {@code SUBSIZED}.
+     *
+     */
+    static abstract class SliceSpliterator<T, T_SPLITR extends Spliterator<T>> {
+        // The start index of the slice
+        final long sliceOrigin;
+        // One past the last index of the slice
+        final long sliceFence;
+
+        // The spliterator to slice
+        T_SPLITR s;
+        // current (absolute) index, modified on advance/split
+        long index;
+        // one past last (absolute) index or sliceFence, which ever is smaller
+        long fence;
+
+        SliceSpliterator(T_SPLITR s, long sliceOrigin, long sliceFence, long origin, long fence) {
+            assert s.hasCharacteristics(Spliterator.SUBSIZED);
+            this.s = s;
+            this.sliceOrigin = sliceOrigin;
+            this.sliceFence = sliceFence;
+            this.index = origin;
+            this.fence = fence;
+        }
+
+        protected abstract T_SPLITR makeSpliterator(T_SPLITR s, long sliceOrigin, long sliceFence, long origin, long fence);
+
+        public T_SPLITR trySplit() {
+            if (sliceOrigin >= fence)
+                return null;
+
+            if (index >= fence)
+                return null;
+
+            // Keep splitting until the left and right splits intersect with the slice
+            // thereby ensuring the size estimate decreases.
+            // This also avoids creating empty spliterators which can result in
+            // existing and additionally created F/J tasks that perform
+            // redundant work on no elements.
+            while (true) {
+                @SuppressWarnings("unchecked")
+                T_SPLITR leftSplit = (T_SPLITR) s.trySplit();
+                if (leftSplit == null)
+                    return null;
+
+                long leftSplitFenceUnbounded = index + leftSplit.estimateSize();
+                long leftSplitFence = Math.min(leftSplitFenceUnbounded, sliceFence);
+                if (sliceOrigin >= leftSplitFence) {
+                    // The left split does not intersect with, and is to the left of, the slice
+                    // The right split does intersect
+                    // Discard the left split and split further with the right split
+                    index = leftSplitFence;
+                }
+                else if (leftSplitFence >= sliceFence) {
+                    // The right split does not intersect with, and is to the right of, the slice
+                    // The left split does intersect
+                    // Discard the right split and split further with the left split
+                    s = leftSplit;
+                    fence = leftSplitFence;
+                }
+                else if (index >= sliceOrigin && leftSplitFenceUnbounded <= sliceFence) {
+                    // The left split is contained within the slice, return the underlying left split
+                    // Right split is contained within or intersects with the slice
+                    index = leftSplitFence;
+                    return leftSplit;
+                } else {
+                    // The left split intersects with the slice
+                    // Right split is contained within or intersects with the slice
+                    return makeSpliterator(leftSplit, sliceOrigin, sliceFence, index, index = leftSplitFence);
+                }
+            }
+        }
+
+        public long estimateSize() {
+            return (sliceOrigin < fence)
+                   ? fence - Math.max(sliceOrigin, index) : 0;
+        }
+
+        public int characteristics() {
+            return s.characteristics();
+        }
+
+        static final class OfRef<T>
+                extends SliceSpliterator<T, Spliterator<T>>
+                implements Spliterator<T> {
+
+            OfRef(Spliterator<T> s, long sliceOrigin, long sliceFence) {
+                this(s, sliceOrigin, sliceFence, 0, Math.min(s.estimateSize(), sliceFence));
+            }
+
+            private OfRef(Spliterator<T> s,
+                          long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator<T> makeSpliterator(Spliterator<T> s,
+                                                     long sliceOrigin, long sliceFence,
+                                                     long origin, long fence) {
+                return new OfRef<>(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return false;
+
+                while (sliceOrigin > index) {
+                    s.tryAdvance(e -> {});
+                    index++;
+                }
+
+                if (index >= fence)
+                    return false;
+
+                index++;
+                return s.tryAdvance(action);
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return;
+
+                if (index >= fence)
+                    return;
+
+                if (index >= sliceOrigin && (index + s.estimateSize()) <= sliceFence) {
+                    // The spliterator is contained within the slice
+                    s.forEachRemaining(action);
+                    index = fence;
+                } else {
+                    // The spliterator intersects with the slice
+                    while (sliceOrigin > index) {
+                        s.tryAdvance(e -> {});
+                        index++;
+                    }
+                    // Traverse elements up to the fence
+                    for (;index < fence; index++) {
+                        s.tryAdvance(action);
+                    }
+                }
+            }
+        }
+
+        static abstract class OfPrimitive<T,
+                T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                T_CONS>
+                extends SliceSpliterator<T, T_SPLITR>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+
+            OfPrimitive(T_SPLITR s, long sliceOrigin, long sliceFence) {
+                this(s, sliceOrigin, sliceFence, 0, Math.min(s.estimateSize(), sliceFence));
+            }
+
+            private OfPrimitive(T_SPLITR s,
+                                long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return false;
+
+                while (sliceOrigin > index) {
+                    s.tryAdvance(emptyConsumer());
+                    index++;
+                }
+
+                if (index >= fence)
+                    return false;
+
+                index++;
+                return s.tryAdvance(action);
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return;
+
+                if (index >= fence)
+                    return;
+
+                if (index >= sliceOrigin && (index + s.estimateSize()) <= sliceFence) {
+                    // The spliterator is contained within the slice
+                    s.forEachRemaining(action);
+                    index = fence;
+                } else {
+                    // The spliterator intersects with the slice
+                    while (sliceOrigin > index) {
+                        s.tryAdvance(emptyConsumer());
+                        index++;
+                    }
+                    // Traverse elements up to the fence
+                    for (;index < fence; index++) {
+                        s.tryAdvance(action);
+                    }
+                }
+            }
+
+            protected abstract T_CONS emptyConsumer();
+        }
+
+        static final class OfInt extends OfPrimitive<Integer, Spliterator.OfInt, IntConsumer>
+                implements Spliterator.OfInt {
+            OfInt(Spliterator.OfInt s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfInt(Spliterator.OfInt s,
+                  long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator.OfInt makeSpliterator(Spliterator.OfInt s,
+                                                        long sliceOrigin, long sliceFence,
+                                                        long origin, long fence) {
+                return new SliceSpliterator.OfInt(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected IntConsumer emptyConsumer() {
+                return e -> {};
+            }
+        }
+
+        static final class OfLong extends OfPrimitive<Long, Spliterator.OfLong, LongConsumer>
+                implements Spliterator.OfLong {
+            OfLong(Spliterator.OfLong s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfLong(Spliterator.OfLong s,
+                   long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator.OfLong makeSpliterator(Spliterator.OfLong s,
+                                                         long sliceOrigin, long sliceFence,
+                                                         long origin, long fence) {
+                return new SliceSpliterator.OfLong(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected LongConsumer emptyConsumer() {
+                return e -> {};
+            }
+        }
+
+        static final class OfDouble extends OfPrimitive<Double, Spliterator.OfDouble, DoubleConsumer>
+                implements Spliterator.OfDouble {
+            OfDouble(Spliterator.OfDouble s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfDouble(Spliterator.OfDouble s,
+                     long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s,
+                                                           long sliceOrigin, long sliceFence,
+                                                           long origin, long fence) {
+                return new SliceSpliterator.OfDouble(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected DoubleConsumer emptyConsumer() {
+                return e -> {};
+            }
+        }
+    }
+
+    /**
+     * A slice Spliterator that does not preserve order, if any, of a source
+     * Spliterator.
+     *
+     * Note: The source spliterator may report {@code ORDERED} since that
+     * spliterator be the result of a previous pipeline stage that was
+     * collected to a {@code Node}. It is the order of the pipeline stage
+     * that governs whether the this slice spliterator is to be used or not.
+     */
+    static abstract class UnorderedSliceSpliterator<T, T_SPLITR extends Spliterator<T>> {
+        static final int CHUNK_SIZE = 1 << 7;
+
+        // The spliterator to slice
+        protected final T_SPLITR s;
+        protected final boolean unlimited;
+        private final long skipThreshold;
+        private final AtomicLong permits;
+
+        UnorderedSliceSpliterator(T_SPLITR s, long skip, long limit) {
+            this.s = s;
+            this.unlimited = limit < 0;
+            this.skipThreshold = limit >= 0 ? limit : 0;
+            this.permits = new AtomicLong(limit >= 0 ? skip + limit : skip);
+        }
+
+        UnorderedSliceSpliterator(T_SPLITR s,
+                                  UnorderedSliceSpliterator<T, T_SPLITR> parent) {
+            this.s = s;
+            this.unlimited = parent.unlimited;
+            this.permits = parent.permits;
+            this.skipThreshold = parent.skipThreshold;
+        }
+
+        /**
+         * Acquire permission to skip or process elements.  The caller must
+         * first acquire the elements, then consult this method for guidance
+         * as to what to do with the data.
+         *
+         * <p>We use an {@code AtomicLong} to atomically maintain a counter,
+         * which is initialized as skip+limit if we are limiting, or skip only
+         * if we are not limiting.  The user should consult the method
+         * {@code checkPermits()} before acquiring data elements.
+         *
+         * @param numElements the number of elements the caller has in hand
+         * @return the number of elements that should be processed; any
+         * remaining elements should be discarded.
+         */
+        protected final long acquirePermits(long numElements) {
+            long remainingPermits;
+            long grabbing;
+            // permits never increase, and don't decrease below zero
+            assert numElements > 0;
+            do {
+                remainingPermits = permits.get();
+                if (remainingPermits == 0)
+                    return unlimited ? numElements : 0;
+                grabbing = Math.min(remainingPermits, numElements);
+            } while (grabbing > 0 &&
+                     !permits.compareAndSet(remainingPermits, remainingPermits - grabbing));
+
+            if (unlimited)
+                return Math.max(numElements - grabbing, 0);
+            else if (remainingPermits > skipThreshold)
+                return Math.max(grabbing - (remainingPermits - skipThreshold), 0);
+            else
+                return grabbing;
+        }
+
+        enum PermitStatus { NO_MORE, MAYBE_MORE, UNLIMITED }
+
+        /** Call to check if permits might be available before acquiring data */
+        protected final PermitStatus permitStatus() {
+            if (permits.get() > 0)
+                return PermitStatus.MAYBE_MORE;
+            else
+                return unlimited ?  PermitStatus.UNLIMITED : PermitStatus.NO_MORE;
+        }
+
+        public final T_SPLITR trySplit() {
+            // Stop splitting when there are no more limit permits
+            if (permits.get() == 0)
+                return null;
+            @SuppressWarnings("unchecked")
+            T_SPLITR split = (T_SPLITR) s.trySplit();
+            return split == null ? null : makeSpliterator(split);
+        }
+
+        protected abstract T_SPLITR makeSpliterator(T_SPLITR s);
+
+        public final long estimateSize() {
+            return s.estimateSize();
+        }
+
+        public final int characteristics() {
+            return s.characteristics() &
+                   ~(Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED);
+        }
+
+        static final class OfRef<T> extends UnorderedSliceSpliterator<T, Spliterator<T>>
+                implements Spliterator<T>, Consumer<T> {
+            T tmpSlot;
+
+            OfRef(Spliterator<T> s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfRef(Spliterator<T> s, OfRef<T> parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public final void accept(T t) {
+                tmpSlot = t;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                while (permitStatus() != PermitStatus.NO_MORE) {
+                    if (!s.tryAdvance(this))
+                        return false;
+                    else if (acquirePermits(1) == 1) {
+                        action.accept(tmpSlot);
+                        tmpSlot = null;
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                ArrayBuffer.OfRef<T> sb = null;
+                PermitStatus permitStatus;
+                while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) {
+                    if (permitStatus == PermitStatus.MAYBE_MORE) {
+                        // Optimistically traverse elements up to a threshold of CHUNK_SIZE
+                        if (sb == null)
+                            sb = new ArrayBuffer.OfRef<>(CHUNK_SIZE);
+                        else
+                            sb.reset();
+                        long permitsRequested = 0;
+                        do { } while (s.tryAdvance(sb) && ++permitsRequested < CHUNK_SIZE);
+                        if (permitsRequested == 0)
+                            return;
+                        sb.forEach(action, acquirePermits(permitsRequested));
+                    }
+                    else {
+                        // Must be UNLIMITED; let 'er rip
+                        s.forEachRemaining(action);
+                        return;
+                    }
+                }
+            }
+
+            @Override
+            protected Spliterator<T> makeSpliterator(Spliterator<T> s) {
+                return new UnorderedSliceSpliterator.OfRef<>(s, this);
+            }
+        }
+
+        /**
+         * Concrete sub-types must also be an instance of type {@code T_CONS}.
+         *
+         * @param <T_BUFF> the type of the spined buffer. Must also be a type of
+         *        {@code T_CONS}.
+         */
+        static abstract class OfPrimitive<
+                T,
+                T_CONS,
+                T_BUFF extends ArrayBuffer.OfPrimitive<T_CONS>,
+                T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+                extends UnorderedSliceSpliterator<T, T_SPLITR>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+            OfPrimitive(T_SPLITR s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfPrimitive(T_SPLITR s, UnorderedSliceSpliterator.OfPrimitive<T, T_CONS, T_BUFF, T_SPLITR> parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS action) {
+                Objects.requireNonNull(action);
+                @SuppressWarnings("unchecked")
+                T_CONS consumer = (T_CONS) this;
+
+                while (permitStatus() != PermitStatus.NO_MORE) {
+                    if (!s.tryAdvance(consumer))
+                        return false;
+                    else if (acquirePermits(1) == 1) {
+                        acceptConsumed(action);
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            protected abstract void acceptConsumed(T_CONS action);
+
+            @Override
+            public void forEachRemaining(T_CONS action) {
+                Objects.requireNonNull(action);
+
+                T_BUFF sb = null;
+                PermitStatus permitStatus;
+                while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) {
+                    if (permitStatus == PermitStatus.MAYBE_MORE) {
+                        // Optimistically traverse elements up to a threshold of CHUNK_SIZE
+                        if (sb == null)
+                            sb = bufferCreate(CHUNK_SIZE);
+                        else
+                            sb.reset();
+                        @SuppressWarnings("unchecked")
+                        T_CONS sbc = (T_CONS) sb;
+                        long permitsRequested = 0;
+                        do { } while (s.tryAdvance(sbc) && ++permitsRequested < CHUNK_SIZE);
+                        if (permitsRequested == 0)
+                            return;
+                        sb.forEach(action, acquirePermits(permitsRequested));
+                    }
+                    else {
+                        // Must be UNLIMITED; let 'er rip
+                        s.forEachRemaining(action);
+                        return;
+                    }
+                }
+            }
+
+            protected abstract T_BUFF bufferCreate(int initialCapacity);
+        }
+
+        static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, ArrayBuffer.OfInt, Spliterator.OfInt>
+                implements Spliterator.OfInt, IntConsumer {
+
+            int tmpValue;
+
+            OfInt(Spliterator.OfInt s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfInt(Spliterator.OfInt s, UnorderedSliceSpliterator.OfInt parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public void accept(int value) {
+                tmpValue = value;
+            }
+
+            @Override
+            protected void acceptConsumed(IntConsumer action) {
+                action.accept(tmpValue);
+            }
+
+            @Override
+            protected ArrayBuffer.OfInt bufferCreate(int initialCapacity) {
+                return new ArrayBuffer.OfInt(initialCapacity);
+            }
+
+            @Override
+            protected Spliterator.OfInt makeSpliterator(Spliterator.OfInt s) {
+                return new UnorderedSliceSpliterator.OfInt(s, this);
+            }
+        }
+
+        static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, ArrayBuffer.OfLong, Spliterator.OfLong>
+                implements Spliterator.OfLong, LongConsumer {
+
+            long tmpValue;
+
+            OfLong(Spliterator.OfLong s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfLong(Spliterator.OfLong s, UnorderedSliceSpliterator.OfLong parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public void accept(long value) {
+                tmpValue = value;
+            }
+
+            @Override
+            protected void acceptConsumed(LongConsumer action) {
+                action.accept(tmpValue);
+            }
+
+            @Override
+            protected ArrayBuffer.OfLong bufferCreate(int initialCapacity) {
+                return new ArrayBuffer.OfLong(initialCapacity);
+            }
+
+            @Override
+            protected Spliterator.OfLong makeSpliterator(Spliterator.OfLong s) {
+                return new UnorderedSliceSpliterator.OfLong(s, this);
+            }
+        }
+
+        static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, ArrayBuffer.OfDouble, Spliterator.OfDouble>
+                implements Spliterator.OfDouble, DoubleConsumer {
+
+            double tmpValue;
+
+            OfDouble(Spliterator.OfDouble s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfDouble(Spliterator.OfDouble s, UnorderedSliceSpliterator.OfDouble parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public void accept(double value) {
+                tmpValue = value;
+            }
+
+            @Override
+            protected void acceptConsumed(DoubleConsumer action) {
+                action.accept(tmpValue);
+            }
+
+            @Override
+            protected ArrayBuffer.OfDouble bufferCreate(int initialCapacity) {
+                return new ArrayBuffer.OfDouble(initialCapacity);
+            }
+
+            @Override
+            protected Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s) {
+                return new UnorderedSliceSpliterator.OfDouble(s, this);
+            }
+        }
+    }
+
+    /**
+     * A wrapping spliterator that only reports distinct elements of the
+     * underlying spliterator. Does not preserve size and encounter order.
+     */
+    static final class DistinctSpliterator<T> implements Spliterator<T>, Consumer<T> {
+
+        // The value to represent null in the ConcurrentHashMap
+        private static final Object NULL_VALUE = new Object();
+
+        // The underlying spliterator
+        private final Spliterator<T> s;
+
+        // ConcurrentHashMap holding distinct elements as keys
+        private final ConcurrentHashMap<T, Boolean> seen;
+
+        // Temporary element, only used with tryAdvance
+        private T tmpSlot;
+
+        DistinctSpliterator(Spliterator<T> s) {
+            this(s, new ConcurrentHashMap<>());
+        }
+
+        private DistinctSpliterator(Spliterator<T> s, ConcurrentHashMap<T, Boolean> seen) {
+            this.s = s;
+            this.seen = seen;
+        }
+
+        @Override
+        public void accept(T t) {
+            this.tmpSlot = t;
+        }
+
+        @SuppressWarnings("unchecked")
+        private T mapNull(T t) {
+            return t != null ? t : (T) NULL_VALUE;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            while (s.tryAdvance(this)) {
+                if (seen.putIfAbsent(mapNull(tmpSlot), Boolean.TRUE) == null) {
+                    action.accept(tmpSlot);
+                    tmpSlot = null;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            s.forEachRemaining(t -> {
+                if (seen.putIfAbsent(mapNull(t), Boolean.TRUE) == null) {
+                    action.accept(t);
+                }
+            });
+        }
+
+        @Override
+        public Spliterator<T> trySplit() {
+            Spliterator<T> split = s.trySplit();
+            return (split != null) ? new DistinctSpliterator<>(split, seen) : null;
+        }
+
+        @Override
+        public long estimateSize() {
+            return s.estimateSize();
+        }
+
+        @Override
+        public int characteristics() {
+            return (s.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED |
+                                            Spliterator.SORTED | Spliterator.ORDERED))
+                   | Spliterator.DISTINCT;
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            return s.getComparator();
+        }
+    }
+
+    /**
+     * A Spliterator that infinitely supplies elements in no particular order.
+     *
+     * <p>Splitting divides the estimated size in two and stops when the
+     * estimate size is 0.
+     *
+     * <p>The {@code forEachRemaining} method if invoked will never terminate.
+     * The {@code tryAdvance} method always returns true.
+     *
+     */
+    static abstract class InfiniteSupplyingSpliterator<T> implements Spliterator<T> {
+        long estimate;
+
+        protected InfiniteSupplyingSpliterator(long estimate) {
+            this.estimate = estimate;
+        }
+
+        @Override
+        public long estimateSize() {
+            return estimate;
+        }
+
+        @Override
+        public int characteristics() {
+            return IMMUTABLE;
+        }
+
+        static final class OfRef<T> extends InfiniteSupplyingSpliterator<T> {
+            final Supplier<T> s;
+
+            OfRef(long size, Supplier<T> s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.get());
+                return true;
+            }
+
+            @Override
+            public Spliterator<T> trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfRef<>(estimate >>>= 1, s);
+            }
+        }
+
+        static final class OfInt extends InfiniteSupplyingSpliterator<Integer>
+                implements Spliterator.OfInt {
+            final IntSupplier s;
+
+            OfInt(long size, IntSupplier s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(IntConsumer action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.getAsInt());
+                return true;
+            }
+
+            @Override
+            public Spliterator.OfInt trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfInt(estimate = estimate >>> 1, s);
+            }
+        }
+
+        static final class OfLong extends InfiniteSupplyingSpliterator<Long>
+                implements Spliterator.OfLong {
+            final LongSupplier s;
+
+            OfLong(long size, LongSupplier s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(LongConsumer action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.getAsLong());
+                return true;
+            }
+
+            @Override
+            public Spliterator.OfLong trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfLong(estimate = estimate >>> 1, s);
+            }
+        }
+
+        static final class OfDouble extends InfiniteSupplyingSpliterator<Double>
+                implements Spliterator.OfDouble {
+            final DoubleSupplier s;
+
+            OfDouble(long size, DoubleSupplier s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(DoubleConsumer action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.getAsDouble());
+                return true;
+            }
+
+            @Override
+            public Spliterator.OfDouble trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfDouble(estimate = estimate >>> 1, s);
+            }
+        }
+    }
+
+    // @@@ Consolidate with Node.Builder
+    static abstract class ArrayBuffer {
+        int index;
+
+        void reset() {
+            index = 0;
+        }
+
+        static final class OfRef<T> extends ArrayBuffer implements Consumer<T> {
+            final Object[] array;
+
+            OfRef(int size) {
+                this.array = new Object[size];
+            }
+
+            @Override
+            public void accept(T t) {
+                array[index++] = t;
+            }
+
+            public void forEach(Consumer<? super T> action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    @SuppressWarnings("unchecked")
+                    T t = (T) array[i];
+                    action.accept(t);
+                }
+            }
+        }
+
+        static abstract class OfPrimitive<T_CONS> extends ArrayBuffer {
+            int index;
+
+            @Override
+            void reset() {
+                index = 0;
+            }
+
+            abstract void forEach(T_CONS action, long fence);
+        }
+
+        static final class OfInt extends OfPrimitive<IntConsumer>
+                implements IntConsumer {
+            final int[] array;
+
+            OfInt(int size) {
+                this.array = new int[size];
+            }
+
+            @Override
+            public void accept(int t) {
+                array[index++] = t;
+            }
+
+            @Override
+            public void forEach(IntConsumer action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    action.accept(array[i]);
+                }
+            }
+        }
+
+        static final class OfLong extends OfPrimitive<LongConsumer>
+                implements LongConsumer {
+            final long[] array;
+
+            OfLong(int size) {
+                this.array = new long[size];
+            }
+
+            @Override
+            public void accept(long t) {
+                array[index++] = t;
+            }
+
+            @Override
+            public void forEach(LongConsumer action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    action.accept(array[i]);
+                }
+            }
+        }
+
+        static final class OfDouble extends OfPrimitive<DoubleConsumer>
+                implements DoubleConsumer {
+            final double[] array;
+
+            OfDouble(int size) {
+                this.array = new double[size];
+            }
+
+            @Override
+            public void accept(double t) {
+                array[index++] = t;
+            }
+
+            @Override
+            void forEach(DoubleConsumer action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    action.accept(array[i]);
+                }
+            }
+        }
+    }
+}
+
diff --git a/java/util/stream/StreamSupport.java b/java/util/stream/StreamSupport.java
new file mode 100644
index 0000000..9a1820c
--- /dev/null
+++ b/java/util/stream/StreamSupport.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.Supplier;
+
+/**
+ * Low-level utility methods for creating and manipulating streams.
+ *
+ * <p>This class is mostly for library writers presenting stream views
+ * of data structures; most static stream methods intended for end users are in
+ * the various {@code Stream} classes.
+ *
+ * @since 1.8
+ */
+public final class StreamSupport {
+
+    // Suppresses default constructor, ensuring non-instantiability.
+    private StreamSupport() {}
+
+    /**
+     * Creates a new sequential or parallel {@code Stream} from a
+     * {@code Spliterator}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated
+     * size after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #stream(java.util.function.Supplier, int, boolean)} should be used
+     * to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param <T> the type of stream elements
+     * @param spliterator a {@code Spliterator} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code Stream}
+     */
+    public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
+        Objects.requireNonNull(spliterator);
+        return new ReferencePipeline.Head<>(spliterator,
+                                            StreamOpFlag.fromCharacteristics(spliterator),
+                                            parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code Stream} from a
+     * {@code Supplier} of {@code Spliterator}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #stream(java.util.Spliterator, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param <T> the type of stream elements
+     * @param supplier a {@code Supplier} of a {@code Spliterator}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code Stream}
+     * @see #stream(java.util.Spliterator, boolean)
+     */
+    public static <T> Stream<T> stream(Supplier<? extends Spliterator<T>> supplier,
+                                       int characteristics,
+                                       boolean parallel) {
+        Objects.requireNonNull(supplier);
+        return new ReferencePipeline.Head<>(supplier,
+                                            StreamOpFlag.fromCharacteristics(characteristics),
+                                            parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code IntStream} from a
+     * {@code Spliterator.OfInt}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated size
+     * after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #intStream(java.util.function.Supplier, int, boolean)} should be
+     * used to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param spliterator a {@code Spliterator.OfInt} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code IntStream}
+     */
+    public static IntStream intStream(Spliterator.OfInt spliterator, boolean parallel) {
+        return new IntPipeline.Head<>(spliterator,
+                                      StreamOpFlag.fromCharacteristics(spliterator),
+                                      parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code IntStream} from a
+     * {@code Supplier} of {@code Spliterator.OfInt}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #intStream(java.util.Spliterator.OfInt, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param supplier a {@code Supplier} of a {@code Spliterator.OfInt}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator.OfInt}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code IntStream}
+     * @see #intStream(java.util.Spliterator.OfInt, boolean)
+     */
+    public static IntStream intStream(Supplier<? extends Spliterator.OfInt> supplier,
+                                      int characteristics,
+                                      boolean parallel) {
+        return new IntPipeline.Head<>(supplier,
+                                      StreamOpFlag.fromCharacteristics(characteristics),
+                                      parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code LongStream} from a
+     * {@code Spliterator.OfLong}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated
+     * size after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #longStream(java.util.function.Supplier, int, boolean)} should be
+     * used to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param spliterator a {@code Spliterator.OfLong} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code LongStream}
+     */
+    public static LongStream longStream(Spliterator.OfLong spliterator,
+                                        boolean parallel) {
+        return new LongPipeline.Head<>(spliterator,
+                                       StreamOpFlag.fromCharacteristics(spliterator),
+                                       parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code LongStream} from a
+     * {@code Supplier} of {@code Spliterator.OfLong}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #longStream(java.util.Spliterator.OfLong, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param supplier a {@code Supplier} of a {@code Spliterator.OfLong}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator.OfLong}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code LongStream}
+     * @see #longStream(java.util.Spliterator.OfLong, boolean)
+     */
+    public static LongStream longStream(Supplier<? extends Spliterator.OfLong> supplier,
+                                        int characteristics,
+                                        boolean parallel) {
+        return new LongPipeline.Head<>(supplier,
+                                       StreamOpFlag.fromCharacteristics(characteristics),
+                                       parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code DoubleStream} from a
+     * {@code Spliterator.OfDouble}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated size
+     * after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #doubleStream(java.util.function.Supplier, int, boolean)} should
+     * be used to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param spliterator A {@code Spliterator.OfDouble} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code DoubleStream}
+     */
+    public static DoubleStream doubleStream(Spliterator.OfDouble spliterator,
+                                            boolean parallel) {
+        return new DoublePipeline.Head<>(spliterator,
+                                         StreamOpFlag.fromCharacteristics(spliterator),
+                                         parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code DoubleStream} from a
+     * {@code Supplier} of {@code Spliterator.OfDouble}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #doubleStream(java.util.Spliterator.OfDouble, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param supplier A {@code Supplier} of a {@code Spliterator.OfDouble}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator.OfDouble}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code DoubleStream}
+     * @see #doubleStream(java.util.Spliterator.OfDouble, boolean)
+     */
+    public static DoubleStream doubleStream(Supplier<? extends Spliterator.OfDouble> supplier,
+                                            int characteristics,
+                                            boolean parallel) {
+        return new DoublePipeline.Head<>(supplier,
+                                         StreamOpFlag.fromCharacteristics(characteristics),
+                                         parallel);
+    }
+}
diff --git a/java/util/stream/StreamTestDataProvider.java b/java/util/stream/StreamTestDataProvider.java
new file mode 100644
index 0000000..cc98529
--- /dev/null
+++ b/java/util/stream/StreamTestDataProvider.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/**
+ * StreamTestDataProvider
+ *
+ * @author Brian Goetz
+ */
+/** TestNG DataProvider for ref-valued streams */
+public class StreamTestDataProvider {
+    private static final Integer[] to0 = new Integer[0];
+    private static final Integer[] to1 = new Integer[1];
+    private static final Integer[] to10 = new Integer[10];
+    private static final Integer[] to100 = new Integer[100];
+    private static final Integer[] to1000 = new Integer[1000];
+    private static final Integer[] reversed = new Integer[100];
+    private static final Integer[] ones = new Integer[100];
+    private static final Integer[] twice = new Integer[200];
+    private static final Integer[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] withNullTestData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        Integer[][] arrays = {to0, to1, to10, to100, to1000};
+        for (Integer[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new Integer[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (int) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final Integer[] ints = (Integer[])data[1];
+                final List<Integer> intsAsList = Arrays.asList(ints);
+
+                list.add(arrayDataDescr("array:" + name, ints));
+                list.add(collectionDataDescr("ArrayList.asList:" + name, intsAsList));
+                list.add(collectionDataDescr("ArrayList:" + name, new ArrayList<>(intsAsList)));
+                list.add(streamDataDescr("DelegatingStream(ArrayList):" + name,
+                                         () -> new ArrayList<>(intsAsList).stream()));
+                List<Integer> aList = new ArrayList<>(intsAsList);
+                if (LambdaTestMode.isNormalMode()) {
+                    // Only include sub-lists for normal test execution mode
+                    // This data is serialization-hostile since the state of the
+                    // deserialized sub-list will be out of sync with the
+                    // enclosing list.
+                    list.add(collectionDataDescr("ArrayList.Sublist:" + name,
+                                                 (ints.length) <= 1 ? aList.subList(0, 0) : aList.subList(1, ints.length / 2)));
+                }
+                list.add(collectionDataDescr("LinkedList:" + name, new LinkedList<>(intsAsList)));
+                list.add(collectionDataDescr("HashSet:" + name, new HashSet<>(intsAsList)));
+                list.add(collectionDataDescr("LinkedHashSet:" + name, new LinkedHashSet<>(intsAsList)));
+                list.add(collectionDataDescr("TreeSet:" + name, new TreeSet<>(intsAsList)));
+                SpinedBuffer<Integer> spinedBuffer = new SpinedBuffer<>();
+                intsAsList.forEach(spinedBuffer);
+                list.add(sbDataDescr("SpinedBuffer:" + name, spinedBuffer));
+
+                // @@@ Add more
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        // Simple combination of numbers and null values, probably excessive but may catch
+        // errors for initialization/termination/sequence
+        // @@@ This is separate from the other data for now until nulls are consitently supported by
+        // all operations
+        {
+            List<Object[]> list = new ArrayList<>();
+            int size = 5;
+            for (int i = 0; i < (1 << size) - 2; i++) {
+                Integer[] content = new Integer[size];
+                for (int e = 0; e < size; e++) {
+                    content[e] = (i & (1 << e)) > 0 ? e + 1 : null;
+                }
+
+                // ORDERED
+                list.add(arrayDataDescr("array:" + i, content));
+                // not ORDERED, DISTINCT
+                list.add(collectionDataDescr("HashSet:" + i, new HashSet<>(Arrays.asList(content))));
+            }
+
+            withNullTestData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final Integer[] ints = (Integer[])data[1];
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(ints)));
+                spliterators.add(splitDescr("arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(ints, 0, ints.length/2)));
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> {
+                                                SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+                                                for (Integer i : ints)
+                                                    sb.accept(i);
+                                                return sb.spliterator();
+                                            }));
+                spliterators.add(splitDescr("Iterators.s(Arrays.s(array).iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(Arrays.asList(ints).iterator(), ints.length, 0)));
+                spliterators.add(splitDescr("Iterators.s(Arrays.s(array).iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(Arrays.asList(ints).iterator(), 0)));
+                // @@@ Add map and collection spliterators when spliterator() is exposed on Collection or Iterable
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+    }
+
+    static <T> Object[] arrayDataDescr(String description, T[] data) {
+        return new Object[] { description, TestData.Factory.ofArray(description, data)};
+    }
+
+    static <T> Object[] streamDataDescr(String description, Supplier<Stream<T>> supplier) {
+        return new Object[] { description, TestData.Factory.ofSupplier(description, supplier)};
+    }
+
+    static <T> Object[] collectionDataDescr(String description, Collection<T> data) {
+        return new Object[] { description, TestData.Factory.ofCollection(description, data)};
+    }
+
+    static <T> Object[] sbDataDescr(String description, SpinedBuffer<T> data) {
+        return new Object[] { description, TestData.Factory.ofSpinedBuffer(description, data)};
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator<T>> ss) {
+        return new Object[] { description, ss };
+    }
+
+    // Return an array of ( String name, StreamTestData<Integer> )
+    @DataProvider(name = "StreamTestData<Integer>")
+    public static Object[][] makeStreamTestData() {
+        return testData;
+    }
+
+    @DataProvider(name = "withNull:StreamTestData<Integer>")
+    public static Object[][] makeStreamWithNullTestData() {
+        return withNullTestData;
+    }
+
+    // returns an array of (String name, Supplier<Spliterator<Integer>>)
+    @DataProvider(name = "Spliterator<Integer>")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
diff --git a/java/util/stream/StreamTestScenario.java b/java/util/stream/StreamTestScenario.java
new file mode 100644
index 0000000..d19c416
--- /dev/null
+++ b/java/util/stream/StreamTestScenario.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * Test scenarios for reference streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum StreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            Stream<U> s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+            s.close();
+        }
+    },
+
+    // Collec to list
+    STREAM_COLLECT(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U t : m.apply(data.stream()).collect(Collectors.toList())) {
+                b.accept(t);
+            }
+        }
+    },
+
+    // To array
+    STREAM_TO_ARRAY(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Object t : m.apply(data.stream()).toArray()) {
+                b.accept((U) t);
+            }
+        }
+    },
+
+    // Wrap as stream, and iterate in pull mode
+    STREAM_ITERATOR(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Iterator<U> seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.next());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Spliterator<U> spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) { }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    // Wrap as parallel stream + sequential
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Spliterator<U> spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) { }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    // Wrap as parallel stream + toArray
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Object t : m.apply(data.parallelStream()).toArray())
+                b.accept((U) t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            Stream<U> s = m.apply(data.parallelStream());
+            Spliterator<U> sp = s.spliterator();
+            Stream<U> ss = StreamSupport.stream(() -> sp,
+                                                StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
+            for (Object t : ss.toArray())
+                b.accept((U) t);
+        }
+    },
+
+    // Wrap as parallel stream + toArray and clear SIZED flag
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            Stream<U> pipe2 = m.apply(pipe1);
+
+            for (Object t : pipe2.toArray())
+                b.accept((U) t);
+        }
+    },
+
+    // Wrap as parallel + collect to list
+    PAR_STREAM_COLLECT_TO_LIST(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U u : m.apply(data.parallelStream()).collect(Collectors.toList()))
+                b.accept(u);
+        }
+    },
+
+    // Wrap sequential as parallel, + collect to list
+    STREAM_TO_PAR_STREAM_COLLECT_TO_LIST(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U u : m.apply(data.stream().parallel()).collect(Collectors.toList()))
+                b.accept(u);
+        }
+    },
+
+    // Wrap parallel as sequential,, + collect
+    PAR_STREAM_TO_STREAM_COLLECT_TO_LIST(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U u : m.apply(data.parallelStream().sequential()).collect(Collectors.toList()))
+                b.accept(u);
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing
+    PAR_STREAM_FOR_EACH(true, false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            m.apply(data.parallelStream()).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+    PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            m.apply(pipe1).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+    ;
+
+    // The set of scenarios that clean the SIZED flag
+    public static final Set<StreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+            EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+    private final boolean isParallel;
+
+    private final boolean isOrdered;
+
+    StreamTestScenario(boolean isParallel) {
+        this(isParallel, true);
+    }
+
+    StreamTestScenario(boolean isParallel, boolean isOrdered) {
+        this.isParallel = isParallel;
+        this.isOrdered = isOrdered;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.REFERENCE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public boolean isOrdered() {
+        return isOrdered;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, b, (Function<S_IN, Stream<U>>) m);
+    }
+
+    abstract <T, U, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m);
+
+}
diff --git a/java/util/stream/Streams.java b/java/util/stream/Streams.java
new file mode 100644
index 0000000..072691a
--- /dev/null
+++ b/java/util/stream/Streams.java
@@ -0,0 +1,896 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * Utility methods for operating on and creating streams.
+ *
+ * <p>Unless otherwise stated, streams are created as sequential streams.  A
+ * sequential stream can be transformed into a parallel stream by calling the
+ * {@code parallel()} method on the created stream.
+ *
+ * @since 1.8
+ */
+final class Streams {
+
+    private Streams() {
+        throw new Error("no instances");
+    }
+
+    /**
+     * An object instance representing no value, that cannot be an actual
+     * data element of a stream.  Used when processing streams that can contain
+     * {@code null} elements to distinguish between a {@code null} value and no
+     * value.
+     */
+    static final Object NONE = new Object();
+
+    /**
+     * An {@code int} range spliterator.
+     */
+    static final class RangeIntSpliterator implements Spliterator.OfInt {
+        // Can never be greater that upTo, this avoids overflow if upper bound
+        // is Integer.MAX_VALUE
+        // All elements are traversed if from == upTo & last == 0
+        private int from;
+        private final int upTo;
+        // 1 if the range is closed and the last element has not been traversed
+        // Otherwise, 0 if the range is open, or is a closed range and all
+        // elements have been traversed
+        private int last;
+
+        RangeIntSpliterator(int from, int upTo, boolean closed) {
+            this(from, upTo, closed ? 1 : 0);
+        }
+
+        private RangeIntSpliterator(int from, int upTo, int last) {
+            this.from = from;
+            this.upTo = upTo;
+            this.last = last;
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            final int i = from;
+            if (i < upTo) {
+                from++;
+                consumer.accept(i);
+                return true;
+            }
+            else if (last > 0) {
+                last = 0;
+                consumer.accept(i);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            int i = from;
+            final int hUpTo = upTo;
+            int hLast = last;
+            from = upTo;
+            last = 0;
+            while (i < hUpTo) {
+                consumer.accept(i++);
+            }
+            if (hLast > 0) {
+                // Last element of closed range
+                consumer.accept(i);
+            }
+        }
+
+        @Override
+        public long estimateSize() {
+            // Ensure ranges of size > Integer.MAX_VALUE report the correct size
+            return ((long) upTo) - from + last;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.IMMUTABLE | Spliterator.NONNULL |
+                   Spliterator.DISTINCT | Spliterator.SORTED;
+        }
+
+        @Override
+        public Comparator<? super Integer> getComparator() {
+            return null;
+        }
+
+        @Override
+        public Spliterator.OfInt trySplit() {
+            long size = estimateSize();
+            return size <= 1
+                   ? null
+                   // Left split always has a half-open range
+                   : new RangeIntSpliterator(from, from = from + splitPoint(size), 0);
+        }
+
+        /**
+         * The spliterator size below which the spliterator will be split
+         * at the mid-point to produce balanced splits. Above this size the
+         * spliterator will be split at a ratio of
+         * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
+         * to produce right-balanced splits.
+         *
+         * <p>Such splitting ensures that for very large ranges that the left
+         * side of the range will more likely be processed at a lower-depth
+         * than a balanced tree at the expense of a higher-depth for the right
+         * side of the range.
+         *
+         * <p>This is optimized for cases such as IntStream.ints() that is
+         * implemented as range of 0 to Integer.MAX_VALUE but is likely to be
+         * augmented with a limit operation that limits the number of elements
+         * to a count lower than this threshold.
+         */
+        private static final int BALANCED_SPLIT_THRESHOLD = 1 << 24;
+
+        /**
+         * The split ratio of the left and right split when the spliterator
+         * size is above BALANCED_SPLIT_THRESHOLD.
+         */
+        private static final int RIGHT_BALANCED_SPLIT_RATIO = 1 << 3;
+
+        private int splitPoint(long size) {
+            int d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
+            // Cast to int is safe since:
+            //   2 <= size < 2^32
+            //   2 <= d <= 8
+            return (int) (size / d);
+        }
+    }
+
+    /**
+     * A {@code long} range spliterator.
+     *
+     * This implementation cannot be used for ranges whose size is greater
+     * than Long.MAX_VALUE
+     */
+    static final class RangeLongSpliterator implements Spliterator.OfLong {
+        // Can never be greater that upTo, this avoids overflow if upper bound
+        // is Long.MAX_VALUE
+        // All elements are traversed if from == upTo & last == 0
+        private long from;
+        private final long upTo;
+        // 1 if the range is closed and the last element has not been traversed
+        // Otherwise, 0 if the range is open, or is a closed range and all
+        // elements have been traversed
+        private int last;
+
+        RangeLongSpliterator(long from, long upTo, boolean closed) {
+            this(from, upTo, closed ? 1 : 0);
+        }
+
+        private RangeLongSpliterator(long from, long upTo, int last) {
+            assert upTo - from + last > 0;
+            this.from = from;
+            this.upTo = upTo;
+            this.last = last;
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            final long i = from;
+            if (i < upTo) {
+                from++;
+                consumer.accept(i);
+                return true;
+            }
+            else if (last > 0) {
+                last = 0;
+                consumer.accept(i);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            long i = from;
+            final long hUpTo = upTo;
+            int hLast = last;
+            from = upTo;
+            last = 0;
+            while (i < hUpTo) {
+                consumer.accept(i++);
+            }
+            if (hLast > 0) {
+                // Last element of closed range
+                consumer.accept(i);
+            }
+        }
+
+        @Override
+        public long estimateSize() {
+            return upTo - from + last;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.IMMUTABLE | Spliterator.NONNULL |
+                   Spliterator.DISTINCT | Spliterator.SORTED;
+        }
+
+        @Override
+        public Comparator<? super Long> getComparator() {
+            return null;
+        }
+
+        @Override
+        public Spliterator.OfLong trySplit() {
+            long size = estimateSize();
+            return size <= 1
+                   ? null
+                   // Left split always has a half-open range
+                   : new RangeLongSpliterator(from, from = from + splitPoint(size), 0);
+        }
+
+        /**
+         * The spliterator size below which the spliterator will be split
+         * at the mid-point to produce balanced splits. Above this size the
+         * spliterator will be split at a ratio of
+         * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
+         * to produce right-balanced splits.
+         *
+         * <p>Such splitting ensures that for very large ranges that the left
+         * side of the range will more likely be processed at a lower-depth
+         * than a balanced tree at the expense of a higher-depth for the right
+         * side of the range.
+         *
+         * <p>This is optimized for cases such as LongStream.longs() that is
+         * implemented as range of 0 to Long.MAX_VALUE but is likely to be
+         * augmented with a limit operation that limits the number of elements
+         * to a count lower than this threshold.
+         */
+        private static final long BALANCED_SPLIT_THRESHOLD = 1 << 24;
+
+        /**
+         * The split ratio of the left and right split when the spliterator
+         * size is above BALANCED_SPLIT_THRESHOLD.
+         */
+        private static final long RIGHT_BALANCED_SPLIT_RATIO = 1 << 3;
+
+        private long splitPoint(long size) {
+            long d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
+            // 2 <= size <= Long.MAX_VALUE
+            return size / d;
+        }
+    }
+
+    private static abstract class AbstractStreamBuilderImpl<T, S extends Spliterator<T>> implements Spliterator<T> {
+        // >= 0 when building, < 0 when built
+        // -1 == no elements
+        // -2 == one element, held by first
+        // -3 == two or more elements, held by buffer
+        int count;
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public S trySplit() {
+            return null;
+        }
+
+        @Override
+        public long estimateSize() {
+            return -count - 1;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.ORDERED | Spliterator.IMMUTABLE;
+        }
+    }
+
+    static final class StreamBuilderImpl<T>
+            extends AbstractStreamBuilderImpl<T, Spliterator<T>>
+            implements Stream.Builder<T> {
+        // The first element in the stream
+        // valid if count == 1
+        T first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer<T> buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        StreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        StreamBuilderImpl(T t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(T t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer<>();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        public Stream.Builder<T> add(T t) {
+            accept(t);
+            return this;
+        }
+
+        @Override
+        public Stream<T> build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.stream(this, false) : StreamSupport.stream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class IntStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Integer, Spliterator.OfInt>
+            implements IntStream.Builder, Spliterator.OfInt {
+        // The first element in the stream
+        // valid if count == 1
+        int first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfInt buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        IntStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        IntStreamBuilderImpl(int t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(int t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfInt();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public IntStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.intStream(this, false) : StreamSupport.intStream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class LongStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Long, Spliterator.OfLong>
+            implements LongStream.Builder, Spliterator.OfLong {
+        // The first element in the stream
+        // valid if count == 1
+        long first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfLong buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        LongStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        LongStreamBuilderImpl(long t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(long t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfLong();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public LongStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.longStream(this, false) : StreamSupport.longStream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(LongConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class DoubleStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Double, Spliterator.OfDouble>
+            implements DoubleStream.Builder, Spliterator.OfDouble {
+        // The first element in the stream
+        // valid if count == 1
+        double first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfDouble buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        DoubleStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        DoubleStreamBuilderImpl(double t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(double t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfDouble();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public DoubleStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.doubleStream(this, false) : StreamSupport.doubleStream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    abstract static class ConcatSpliterator<T, T_SPLITR extends Spliterator<T>>
+            implements Spliterator<T> {
+        protected final T_SPLITR aSpliterator;
+        protected final T_SPLITR bSpliterator;
+        // True when no split has occurred, otherwise false
+        boolean beforeSplit;
+        // Never read after splitting
+        final boolean unsized;
+
+        public ConcatSpliterator(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
+            this.aSpliterator = aSpliterator;
+            this.bSpliterator = bSpliterator;
+            beforeSplit = true;
+            // The spliterator is known to be unsized before splitting if the
+            // sum of the estimates overflows.
+            unsized = aSpliterator.estimateSize() + bSpliterator.estimateSize() < 0;
+        }
+
+        @Override
+        public T_SPLITR trySplit() {
+            @SuppressWarnings("unchecked")
+            T_SPLITR ret = beforeSplit ? aSpliterator : (T_SPLITR) bSpliterator.trySplit();
+            beforeSplit = false;
+            return ret;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> consumer) {
+            boolean hasNext;
+            if (beforeSplit) {
+                hasNext = aSpliterator.tryAdvance(consumer);
+                if (!hasNext) {
+                    beforeSplit = false;
+                    hasNext = bSpliterator.tryAdvance(consumer);
+                }
+            }
+            else
+                hasNext = bSpliterator.tryAdvance(consumer);
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> consumer) {
+            if (beforeSplit)
+                aSpliterator.forEachRemaining(consumer);
+            bSpliterator.forEachRemaining(consumer);
+        }
+
+        @Override
+        public long estimateSize() {
+            if (beforeSplit) {
+                // If one or both estimates are Long.MAX_VALUE then the sum
+                // will either be Long.MAX_VALUE or overflow to a negative value
+                long size = aSpliterator.estimateSize() + bSpliterator.estimateSize();
+                return (size >= 0) ? size : Long.MAX_VALUE;
+            }
+            else {
+                return bSpliterator.estimateSize();
+            }
+        }
+
+        @Override
+        public int characteristics() {
+            if (beforeSplit) {
+                // Concatenation loses DISTINCT and SORTED characteristics
+                return aSpliterator.characteristics() & bSpliterator.characteristics()
+                       & ~(Spliterator.DISTINCT | Spliterator.SORTED
+                           | (unsized ? Spliterator.SIZED | Spliterator.SUBSIZED : 0));
+            }
+            else {
+                return bSpliterator.characteristics();
+            }
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            if (beforeSplit)
+                throw new IllegalStateException();
+            return bSpliterator.getComparator();
+        }
+
+        static class OfRef<T> extends ConcatSpliterator<T, Spliterator<T>> {
+            OfRef(Spliterator<T> aSpliterator, Spliterator<T> bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+
+        private static abstract class OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+                extends ConcatSpliterator<T, T_SPLITR>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+            private OfPrimitive(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS action) {
+                boolean hasNext;
+                if (beforeSplit) {
+                    hasNext = aSpliterator.tryAdvance(action);
+                    if (!hasNext) {
+                        beforeSplit = false;
+                        hasNext = bSpliterator.tryAdvance(action);
+                    }
+                }
+                else
+                    hasNext = bSpliterator.tryAdvance(action);
+                return hasNext;
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS action) {
+                if (beforeSplit)
+                    aSpliterator.forEachRemaining(action);
+                bSpliterator.forEachRemaining(action);
+            }
+        }
+
+        static class OfInt
+                extends ConcatSpliterator.OfPrimitive<Integer, IntConsumer, Spliterator.OfInt>
+                implements Spliterator.OfInt {
+            OfInt(Spliterator.OfInt aSpliterator, Spliterator.OfInt bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+
+        static class OfLong
+                extends ConcatSpliterator.OfPrimitive<Long, LongConsumer, Spliterator.OfLong>
+                implements Spliterator.OfLong {
+            OfLong(Spliterator.OfLong aSpliterator, Spliterator.OfLong bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+
+        static class OfDouble
+                extends ConcatSpliterator.OfPrimitive<Double, DoubleConsumer, Spliterator.OfDouble>
+                implements Spliterator.OfDouble {
+            OfDouble(Spliterator.OfDouble aSpliterator, Spliterator.OfDouble bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+    }
+
+    /**
+     * Given two Runnables, return a Runnable that executes both in sequence,
+     * even if the first throws an exception, and if both throw exceptions, add
+     * any exceptions thrown by the second as suppressed exceptions of the first.
+     */
+    static Runnable composeWithExceptions(Runnable a, Runnable b) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    a.run();
+                }
+                catch (Throwable e1) {
+                    try {
+                        b.run();
+                    }
+                    catch (Throwable e2) {
+                        try {
+                            e1.addSuppressed(e2);
+                        } catch (Throwable ignore) {}
+                    }
+                    throw e1;
+                }
+                b.run();
+            }
+        };
+    }
+
+    /**
+     * Given two streams, return a Runnable that
+     * executes both of their {@link BaseStream#close} methods in sequence,
+     * even if the first throws an exception, and if both throw exceptions, add
+     * any exceptions thrown by the second as suppressed exceptions of the first.
+     */
+    static Runnable composedClose(BaseStream<?, ?> a, BaseStream<?, ?> b) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    a.close();
+                }
+                catch (Throwable e1) {
+                    try {
+                        b.close();
+                    }
+                    catch (Throwable e2) {
+                        try {
+                            e1.addSuppressed(e2);
+                        } catch (Throwable ignore) {}
+                    }
+                    throw e1;
+                }
+                b.close();
+            }
+        };
+    }
+}
diff --git a/java/util/stream/TerminalOp.java b/java/util/stream/TerminalOp.java
new file mode 100644
index 0000000..a6e8ae1
--- /dev/null
+++ b/java/util/stream/TerminalOp.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+
+/**
+ * An operation in a stream pipeline that takes a stream as input and produces
+ * a result or side-effect.  A {@code TerminalOp} has an input type and stream
+ * shape, and a result type.  A {@code TerminalOp} also has a set of
+ * <em>operation flags</em> that describes how the operation processes elements
+ * of the stream (such as short-circuiting or respecting encounter order; see
+ * {@link StreamOpFlag}).
+ *
+ * <p>A {@code TerminalOp} must provide a sequential and parallel implementation
+ * of the operation relative to a given stream source and set of intermediate
+ * operations.
+ *
+ * @param <E_IN> the type of input elements
+ * @param <R>    the type of the result
+ * @since 1.8
+ */
+interface TerminalOp<E_IN, R> {
+    /**
+     * Gets the shape of the input type of this operation.
+     *
+     * @implSpec The default returns {@code StreamShape.REFERENCE}.
+     *
+     * @return StreamShape of the input type of this operation
+     */
+    default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+    /**
+     * Gets the stream flags of the operation.  Terminal operations may set a
+     * limited subset of the stream flags defined in {@link StreamOpFlag}, and
+     * these flags are combined with the previously combined stream and
+     * intermediate operation flags for the pipeline.
+     *
+     * @implSpec The default implementation returns zero.
+     *
+     * @return the stream flags for this operation
+     * @see StreamOpFlag
+     */
+    default int getOpFlags() { return 0; }
+
+    /**
+     * Performs a parallel evaluation of the operation using the specified
+     * {@code PipelineHelper}, which describes the upstream intermediate
+     * operations.
+     *
+     * @implSpec The default performs a sequential evaluation of the operation
+     * using the specified {@code PipelineHelper}.
+     *
+     * @param helper the pipeline helper
+     * @param spliterator the source spliterator
+     * @return the result of the evaluation
+     */
+    default <P_IN> R evaluateParallel(PipelineHelper<E_IN> helper,
+                                      Spliterator<P_IN> spliterator) {
+        if (Tripwire.ENABLED)
+            Tripwire.trip(getClass(), "{0} triggering TerminalOp.evaluateParallel serial default");
+        return evaluateSequential(helper, spliterator);
+    }
+
+    /**
+     * Performs a sequential evaluation of the operation using the specified
+     * {@code PipelineHelper}, which describes the upstream intermediate
+     * operations.
+     *
+     * @param helper the pipeline helper
+     * @param spliterator the source spliterator
+     * @return the result of the evaluation
+     */
+    <P_IN> R evaluateSequential(PipelineHelper<E_IN> helper,
+                                Spliterator<P_IN> spliterator);
+}
diff --git a/java/util/stream/TerminalSink.java b/java/util/stream/TerminalSink.java
new file mode 100644
index 0000000..9808d54
--- /dev/null
+++ b/java/util/stream/TerminalSink.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.function.Supplier;
+
+/**
+ * A {@link Sink} which accumulates state as elements are accepted, and allows
+ * a result to be retrieved after the computation is finished.
+ *
+ * @param <T> the type of elements to be accepted
+ * @param <R> the type of the result
+ *
+ * @since 1.8
+ */
+interface TerminalSink<T, R> extends Sink<T>, Supplier<R> { }
diff --git a/java/util/stream/TestData.java b/java/util/stream/TestData.java
new file mode 100644
index 0000000..c763e84
--- /dev/null
+++ b/java/util/stream/TestData.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.function.Supplier;
+import java.util.function.ToIntFunction;
+
+/** Describes a test data set for use in stream tests */
+public interface TestData<T, S extends BaseStream<T, S>>
+        extends Iterable<T> {
+
+    default int size() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    default Iterator<T> iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    Spliterator<T> spliterator();
+
+    default boolean isOrdered() {
+        return spliterator().hasCharacteristics(Spliterator.ORDERED);
+    }
+
+    StreamShape getShape();
+
+    default <A extends Collection<? super T>> A into(A target) {
+        spliterator().forEachRemaining(target::add);
+        return target;
+    }
+
+    S stream();
+
+    S parallelStream();
+
+    public interface OfRef<T> extends TestData<T, Stream<T>> { }
+
+    public interface OfInt extends TestData<Integer, IntStream> { }
+
+    public interface OfLong extends TestData<Long, LongStream> { }
+
+    public interface OfDouble extends TestData<Double, DoubleStream> { }
+
+    // @@@ Temporary garbage class to avoid triggering bugs with lambdas in static methods in interfaces
+    public static class Factory {
+        public static <T> OfRef<T> ofArray(String name, T[] array) {
+            return new AbstractTestData.RefTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                      Arrays::spliterator, a -> a.length);
+        }
+
+        public static <T> OfRef<T> ofCollection(String name, Collection<T> collection) {
+            return new AbstractTestData.RefTestData<>(name, collection, Collection::stream, Collection::parallelStream,
+                                                      Collection::spliterator, Collection::size);
+        }
+
+        public static <T> OfRef<T> ofSpinedBuffer(String name, SpinedBuffer<T> buffer) {
+            return new AbstractTestData.RefTestData<>(name, buffer,
+                                                      b -> StreamSupport.stream(b.spliterator(), false),
+                                                      b -> StreamSupport.stream(b.spliterator(), true),
+                                                      SpinedBuffer::spliterator,
+                                                      b -> (int) b.count());
+        }
+
+        public static <T> OfRef<T> ofSupplier(String name, Supplier<Stream<T>> supplier) {
+            return new AbstractTestData.RefTestData<>(name, supplier,
+                                                      Supplier::get,
+                                                      s -> s.get().parallel(),
+                                                      s -> s.get().spliterator(),
+                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static <T> OfRef<T> ofRefNode(String name, Node<T> node) {
+            return new AbstractTestData.RefTestData<>(name, node,
+                                                      n -> StreamSupport.stream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED, false),
+                                                      n -> StreamSupport.stream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED, true),
+                                                      Node::spliterator,
+                                                      n -> (int) n.count());
+        }
+
+        // int factories
+        public static <T> OfInt ofArray(String name, int[] array) {
+            return new AbstractTestData.IntTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                      Arrays::spliterator, a -> a.length);
+        }
+
+        public static OfInt ofSpinedBuffer(String name, SpinedBuffer.OfInt buffer) {
+            return new AbstractTestData.IntTestData<>(name, buffer,
+                                                      b -> StreamSupport.intStream(b.spliterator(), false),
+                                                      b -> StreamSupport.intStream(b.spliterator(), true),
+                                                      SpinedBuffer.OfInt::spliterator,
+                                                      b -> (int) b.count());
+        }
+
+        public static OfInt ofIntSupplier(String name, Supplier<IntStream> supplier) {
+            return new AbstractTestData.IntTestData<>(name, supplier,
+                                                      Supplier::get,
+                                                      s -> s.get().parallel(),
+                                                      s -> s.get().spliterator(),
+                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static OfInt ofNode(String name, Node.OfInt node) {
+            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+            return new AbstractTestData.IntTestData<>(name, node,
+                                                      n -> StreamSupport.intStream(n::spliterator, characteristics, false),
+                                                      n -> StreamSupport.intStream(n::spliterator, characteristics, true),
+                                                      Node.OfInt::spliterator,
+                                                      n -> (int) n.count());
+        }
+
+        // long factories
+        public static <T> OfLong ofArray(String name, long[] array) {
+            return new AbstractTestData.LongTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                       Arrays::spliterator, a -> a.length);
+        }
+
+        public static OfLong ofSpinedBuffer(String name, SpinedBuffer.OfLong buffer) {
+            return new AbstractTestData.LongTestData<>(name, buffer,
+                                                      b -> StreamSupport.longStream(b.spliterator(), false),
+                                                      b -> StreamSupport.longStream(b.spliterator(), true),
+                                                      SpinedBuffer.OfLong::spliterator,
+                                                      b -> (int) b.count());
+        }
+
+        public static OfLong ofLongSupplier(String name, Supplier<LongStream> supplier) {
+            return new AbstractTestData.LongTestData<>(name, supplier,
+                                                      Supplier::get,
+                                                      s -> s.get().parallel(),
+                                                      s -> s.get().spliterator(),
+                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static OfLong ofNode(String name, Node.OfLong node) {
+            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+            return new AbstractTestData.LongTestData<>(name, node,
+                                                      n -> StreamSupport.longStream(n::spliterator, characteristics, false),
+                                                      n -> StreamSupport.longStream(n::spliterator, characteristics, true),
+                                                      Node.OfLong::spliterator,
+                                                      n -> (int) n.count());
+        }
+
+        // double factories
+        public static <T> OfDouble ofArray(String name, double[] array) {
+            return new AbstractTestData.DoubleTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                         Arrays::spliterator, a -> a.length);
+        }
+
+        public static OfDouble ofSpinedBuffer(String name, SpinedBuffer.OfDouble buffer) {
+            return new AbstractTestData.DoubleTestData<>(name, buffer,
+                                                         b -> StreamSupport.doubleStream(b.spliterator(), false),
+                                                         b -> StreamSupport.doubleStream(b.spliterator(), true),
+                                                         SpinedBuffer.OfDouble::spliterator,
+                                                         b -> (int) b.count());
+        }
+
+        public static OfDouble ofDoubleSupplier(String name, Supplier<DoubleStream> supplier) {
+            return new AbstractTestData.DoubleTestData<>(name, supplier,
+                                                         Supplier::get,
+                                                         s -> s.get().parallel(),
+                                                         s -> s.get().spliterator(),
+                                                         s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static OfDouble ofNode(String name, Node.OfDouble node) {
+            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+            return new AbstractTestData.DoubleTestData<>(name, node,
+                                                         n -> StreamSupport.doubleStream(n::spliterator, characteristics, false),
+                                                         n -> StreamSupport.doubleStream(n::spliterator, characteristics, true),
+                                                         Node.OfDouble::spliterator,
+                                                         n -> (int) n.count());
+        }
+    }
+
+
+    abstract class AbstractTestData<T, S extends BaseStream<T, S>,
+            T_STATE,
+                                    T_SPLITR extends Spliterator<T>>
+            implements TestData<T, S> {
+        private final String name;
+        private final StreamShape shape;
+        protected final T_STATE state;
+        private final ToIntFunction<T_STATE> sizeFn;
+        private final Function<T_STATE, S> streamFn;
+        private final Function<T_STATE, S> parStreamFn;
+        private final Function<T_STATE, T_SPLITR> splitrFn;
+
+        AbstractTestData(String name,
+                         StreamShape shape,
+                         T_STATE state,
+                         Function<T_STATE, S> streamFn,
+                         Function<T_STATE, S> parStreamFn,
+                         Function<T_STATE, T_SPLITR> splitrFn,
+                         ToIntFunction<T_STATE> sizeFn) {
+            this.name = name;
+            this.shape = shape;
+            this.state = state;
+            this.streamFn = streamFn;
+            this.parStreamFn = parStreamFn;
+            this.splitrFn = splitrFn;
+            this.sizeFn = sizeFn;
+        }
+
+        @Override
+        public StreamShape getShape() {
+            return shape;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + "[" + name + "]";
+        }
+
+        @Override
+        public int size() {
+            return sizeFn.applyAsInt(state);
+        }
+
+        @Override
+        public T_SPLITR spliterator() {
+            return splitrFn.apply(state);
+        }
+
+        @Override
+        public S stream() {
+            return streamFn.apply(state);
+        }
+
+        @Override
+        public S parallelStream() {
+            return parStreamFn.apply(state);
+        }
+
+        public static class RefTestData<T, I>
+                extends AbstractTestData<T, Stream<T>, I, Spliterator<T>>
+                implements TestData.OfRef<T> {
+
+            protected RefTestData(String name,
+                                  I state,
+                                  Function<I, Stream<T>> streamFn,
+                                  Function<I, Stream<T>> parStreamFn,
+                                  Function<I, Spliterator<T>> splitrFn,
+                                  ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.REFERENCE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+        }
+
+        static class IntTestData<I>
+                extends AbstractTestData<Integer, IntStream, I, Spliterator.OfInt>
+                implements TestData.OfInt {
+
+            protected IntTestData(String name,
+                                  I state,
+                                  Function<I, IntStream> streamFn,
+                                  Function<I, IntStream> parStreamFn,
+                                  Function<I, Spliterator.OfInt> splitrFn,
+                                  ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.INT_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+            @Override
+            public PrimitiveIterator.OfInt iterator() {
+                return Spliterators.iterator(spliterator());
+            }
+
+            @Override
+            public <A extends Collection<? super Integer>> A into(A target) {
+                spliterator().forEachRemaining((IntConsumer) target::add);
+                return target;
+            }
+        }
+
+        static class LongTestData<I>
+                extends AbstractTestData<Long, LongStream, I, Spliterator.OfLong>
+                implements TestData.OfLong {
+
+            protected LongTestData(String name,
+                                   I state,
+                                   Function<I, LongStream> streamFn,
+                                   Function<I, LongStream> parStreamFn,
+                                   Function<I, Spliterator.OfLong> splitrFn,
+                                   ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.LONG_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+            @Override
+            public PrimitiveIterator.OfLong iterator() {
+                return Spliterators.iterator(spliterator());
+            }
+
+            @Override
+            public <A extends Collection<? super Long>> A into(A target) {
+                spliterator().forEachRemaining((LongConsumer) target::add);
+                return target;
+            }
+        }
+
+        static class DoubleTestData<I>
+                extends AbstractTestData<Double, DoubleStream, I, Spliterator.OfDouble>
+                implements OfDouble {
+
+            protected DoubleTestData(String name,
+                                     I state,
+                                     Function<I, DoubleStream> streamFn,
+                                     Function<I, DoubleStream> parStreamFn,
+                                     Function<I, Spliterator.OfDouble> splitrFn,
+                                     ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.DOUBLE_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+            @Override
+            public PrimitiveIterator.OfDouble iterator() {
+                return Spliterators.iterator(spliterator());
+            }
+
+            @Override
+            public <A extends Collection<? super Double>> A into(A target) {
+                spliterator().forEachRemaining((DoubleConsumer) target::add);
+                return target;
+            }
+        }
+    }
+}
diff --git a/java/util/stream/TestFlagExpectedOp.java b/java/util/stream/TestFlagExpectedOp.java
new file mode 100644
index 0000000..c59a185
--- /dev/null
+++ b/java/util/stream/TestFlagExpectedOp.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+
+import java.util.EnumSet;
+
+class TestFlagExpectedOp<T> extends FlagDeclaringOp<T> {
+
+    static class Builder<T> {
+        final int flags;
+        StreamShape shape = StreamShape.REFERENCE;
+
+        EnumSet<StreamOpFlag> known = EnumSet.noneOf(StreamOpFlag.class);
+        EnumSet<StreamOpFlag> preserve = EnumSet.noneOf(StreamOpFlag.class);
+        EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+        Builder(int flags) {
+            this.flags = flags;
+        }
+
+        Builder<T> known(EnumSet<StreamOpFlag> known) {
+            this.known = known;
+            return this;
+        }
+
+        Builder<T> preserve(EnumSet<StreamOpFlag> preserve) {
+            this.preserve = preserve;
+            return this;
+        }
+
+        Builder<T> notKnown(EnumSet<StreamOpFlag> notKnown) {
+            this.notKnown = notKnown;
+            return this;
+        }
+
+        Builder<T> shape(StreamShape shape) {
+            this.shape = shape;
+            return this;
+        }
+
+        TestFlagExpectedOp<T> build() {
+            return new TestFlagExpectedOp<>(flags, known, preserve, notKnown, shape);
+        }
+    }
+
+    final EnumSet<StreamOpFlag> known;
+    final EnumSet<StreamOpFlag> preserve;
+    final EnumSet<StreamOpFlag> notKnown;
+    final StreamShape shape;
+
+    TestFlagExpectedOp(int flags,
+                       EnumSet<StreamOpFlag> known,
+                       EnumSet<StreamOpFlag> preserve,
+                       EnumSet<StreamOpFlag> notKnown) {
+        this(flags, known, preserve, notKnown, StreamShape.REFERENCE);
+    }
+
+    TestFlagExpectedOp(int flags,
+                       EnumSet<StreamOpFlag> known,
+                       EnumSet<StreamOpFlag> preserve,
+                       EnumSet<StreamOpFlag> notKnown,
+                       StreamShape shape) {
+        super(flags);
+        this.known = known;
+        this.preserve = preserve;
+        this.notKnown = notKnown;
+        this.shape = shape;
+    }
+
+    @Override
+    public StreamShape outputShape() {
+        return shape;
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return shape;
+    }
+
+    @Override
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public Sink<T> opWrapSink(int flags, boolean parallel, Sink upstream) {
+        assertFlags(flags);
+        return upstream;
+    }
+
+    private void assertFlags(int flags) {
+        for (StreamOpFlag f : known) {
+            Assert.assertTrue(f.isKnown(flags),
+                              String.format("Flag %s is not known, but should be known.", f.toString()));
+        }
+
+        for (StreamOpFlag f : preserve) {
+            Assert.assertTrue(f.isPreserved(flags),
+                              String.format("Flag %s is not preserved, but should be preserved.", f.toString()));
+        }
+
+        for (StreamOpFlag f : notKnown) {
+            Assert.assertFalse(f.isKnown(flags),
+                               String.format("Flag %s is known, but should be not known.", f.toString()));
+        }
+    }
+}
diff --git a/java/util/stream/Tripwire.java b/java/util/stream/Tripwire.java
new file mode 100644
index 0000000..c6558b9
--- /dev/null
+++ b/java/util/stream/Tripwire.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import sun.util.logging.PlatformLogger;
+
+/**
+ * Utility class for detecting inadvertent uses of boxing in
+ * {@code java.util.stream} classes.  The detection is turned on or off based on
+ * whether the system property {@code org.openjdk.java.util.stream.tripwire} is
+ * considered {@code true} according to {@link Boolean#getBoolean(String)}.
+ * This should normally be turned off for production use.
+ *
+ * @apiNote
+ * Typical usage would be for boxing code to do:
+ * <pre>{@code
+ *     if (Tripwire.ENABLED)
+ *         Tripwire.trip(getClass(), "{0} calling Sink.OfInt.accept(Integer)");
+ * }</pre>
+ *
+ * @since 1.8
+ */
+final class Tripwire {
+    private static final String TRIPWIRE_PROPERTY = "org.openjdk.java.util.stream.tripwire";
+
+    /** Should debugging checks be enabled? */
+    static final boolean ENABLED = AccessController.doPrivileged(
+            (PrivilegedAction<Boolean>) () -> Boolean.getBoolean(TRIPWIRE_PROPERTY));
+
+    private Tripwire() { }
+
+    /**
+     * Produces a log warning, using {@code PlatformLogger.getLogger(className)},
+     * using the supplied message.  The class name of {@code trippingClass} will
+     * be used as the first parameter to the message.
+     *
+     * @param trippingClass Name of the class generating the message
+     * @param msg A message format string of the type expected by
+     * {@link PlatformLogger}
+     */
+    static void trip(Class<?> trippingClass, String msg) {
+        PlatformLogger.getLogger(trippingClass.getName()).warning(msg, trippingClass.getName());
+    }
+}
diff --git a/java/util/stream/package-info.java b/java/util/stream/package-info.java
new file mode 100644
index 0000000..016c86d
--- /dev/null
+++ b/java/util/stream/package-info.java
@@ -0,0 +1,740 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Classes to support functional-style operations on streams of elements, such
+ * as map-reduce transformations on collections.  For example:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(b -> b.getColor() == RED)
+ *                      .mapToInt(b -> b.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * <p>Here we use {@code widgets}, a {@code Collection<Widget>},
+ * as a source for a stream, and then perform a filter-map-reduce on the stream
+ * to obtain the sum of the weights of the red widgets.  (Summation is an
+ * example of a <a href="package-summary.html#Reduction">reduction</a>
+ * operation.)
+ *
+ * <p>The key abstraction introduced in this package is <em>stream</em>.  The
+ * classes {@link java.util.stream.Stream}, {@link java.util.stream.IntStream},
+ * {@link java.util.stream.LongStream}, and {@link java.util.stream.DoubleStream}
+ * are streams over objects and the primitive {@code int}, {@code long} and
+ * {@code double} types.  Streams differ from collections in several ways:
+ *
+ * <ul>
+ *     <li>No storage.  A stream is not a data structure that stores elements;
+ *     instead, it conveys elements from a source such as a data structure,
+ *     an array, a generator function, or an I/O channel, through a pipeline of
+ *     computational operations.</li>
+ *     <li>Functional in nature.  An operation on a stream produces a result,
+ *     but does not modify its source.  For example, filtering a {@code Stream}
+ *     obtained from a collection produces a new {@code Stream} without the
+ *     filtered elements, rather than removing elements from the source
+ *     collection.</li>
+ *     <li>Laziness-seeking.  Many stream operations, such as filtering, mapping,
+ *     or duplicate removal, can be implemented lazily, exposing opportunities
+ *     for optimization.  For example, "find the first {@code String} with
+ *     three consecutive vowels" need not examine all the input strings.
+ *     Stream operations are divided into intermediate ({@code Stream}-producing)
+ *     operations and terminal (value- or side-effect-producing) operations.
+ *     Intermediate operations are always lazy.</li>
+ *     <li>Possibly unbounded.  While collections have a finite size, streams
+ *     need not.  Short-circuiting operations such as {@code limit(n)} or
+ *     {@code findFirst()} can allow computations on infinite streams to
+ *     complete in finite time.</li>
+ *     <li>Consumable. The elements of a stream are only visited once during
+ *     the life of a stream. Like an {@link java.util.Iterator}, a new stream
+ *     must be generated to revisit the same elements of the source.
+ *     </li>
+ * </ul>
+ *
+ * Streams can be obtained in a number of ways. Some examples include:
+ * <ul>
+ *     <li>From a {@link java.util.Collection} via the {@code stream()} and
+ *     {@code parallelStream()} methods;</li>
+ *     <li>From an array via {@link java.util.Arrays#stream(Object[])};</li>
+ *     <li>From static factory methods on the stream classes, such as
+ *     {@link java.util.stream.Stream#of(Object[])},
+ *     {@link java.util.stream.IntStream#range(int, int)}
+ *     or {@link java.util.stream.Stream#iterate(Object, UnaryOperator)};</li>
+ *     <li>The lines of a file can be obtained from {@link java.io.BufferedReader#lines()};</li>
+ *     <li>Streams of file paths can be obtained from methods in {@link java.nio.file.Files};</li>
+ *     <li>Streams of random numbers can be obtained from {@link java.util.Random#ints()};</li>
+ *     <li>Numerous other stream-bearing methods in the JDK, including
+ *     {@link java.util.BitSet#stream()},
+ *     {@link java.util.regex.Pattern#splitAsStream(java.lang.CharSequence)},
+ *     and {@link java.util.jar.JarFile#stream()}.</li>
+ * </ul>
+ *
+ * <p>Additional stream sources can be provided by third-party libraries using
+ * <a href="package-summary.html#StreamSources">these techniques</a>.
+ *
+ * <h2><a name="StreamOps">Stream operations and pipelines</a></h2>
+ *
+ * <p>Stream operations are divided into <em>intermediate</em> and
+ * <em>terminal</em> operations, and are combined to form <em>stream
+ * pipelines</em>.  A stream pipeline consists of a source (such as a
+ * {@code Collection}, an array, a generator function, or an I/O channel);
+ * followed by zero or more intermediate operations such as
+ * {@code Stream.filter} or {@code Stream.map}; and a terminal operation such
+ * as {@code Stream.forEach} or {@code Stream.reduce}.
+ *
+ * <p>Intermediate operations return a new stream.  They are always
+ * <em>lazy</em>; executing an intermediate operation such as
+ * {@code filter()} does not actually perform any filtering, but instead
+ * creates a new stream that, when traversed, contains the elements of
+ * the initial stream that match the given predicate.  Traversal
+ * of the pipeline source does not begin until the terminal operation of the
+ * pipeline is executed.
+ *
+ * <p>Terminal operations, such as {@code Stream.forEach} or
+ * {@code IntStream.sum}, may traverse the stream to produce a result or a
+ * side-effect. After the terminal operation is performed, the stream pipeline
+ * is considered consumed, and can no longer be used; if you need to traverse
+ * the same data source again, you must return to the data source to get a new
+ * stream.  In almost all cases, terminal operations are <em>eager</em>,
+ * completing their traversal of the data source and processing of the pipeline
+ * before returning.  Only the terminal operations {@code iterator()} and
+ * {@code spliterator()} are not; these are provided as an "escape hatch" to enable
+ * arbitrary client-controlled pipeline traversals in the event that the
+ * existing operations are not sufficient to the task.
+ *
+ * <p> Processing streams lazily allows for significant efficiencies; in a
+ * pipeline such as the filter-map-sum example above, filtering, mapping, and
+ * summing can be fused into a single pass on the data, with minimal
+ * intermediate state. Laziness also allows avoiding examining all the data
+ * when it is not necessary; for operations such as "find the first string
+ * longer than 1000 characters", it is only necessary to examine just enough
+ * strings to find one that has the desired characteristics without examining
+ * all of the strings available from the source. (This behavior becomes even
+ * more important when the input stream is infinite and not merely large.)
+ *
+ * <p>Intermediate operations are further divided into <em>stateless</em>
+ * and <em>stateful</em> operations. Stateless operations, such as {@code filter}
+ * and {@code map}, retain no state from previously seen element when processing
+ * a new element -- each element can be processed
+ * independently of operations on other elements.  Stateful operations, such as
+ * {@code distinct} and {@code sorted}, may incorporate state from previously
+ * seen elements when processing new elements.
+ *
+ * <p>Stateful operations may need to process the entire input
+ * before producing a result.  For example, one cannot produce any results from
+ * sorting a stream until one has seen all elements of the stream.  As a result,
+ * under parallel computation, some pipelines containing stateful intermediate
+ * operations may require multiple passes on the data or may need to buffer
+ * significant data.  Pipelines containing exclusively stateless intermediate
+ * operations can be processed in a single pass, whether sequential or parallel,
+ * with minimal data buffering.
+ *
+ * <p>Further, some operations are deemed <em>short-circuiting</em> operations.
+ * An intermediate operation is short-circuiting if, when presented with
+ * infinite input, it may produce a finite stream as a result.  A terminal
+ * operation is short-circuiting if, when presented with infinite input, it may
+ * terminate in finite time.  Having a short-circuiting operation in the pipeline
+ * is a necessary, but not sufficient, condition for the processing of an infinite
+ * stream to terminate normally in finite time.
+ *
+ * <h3>Parallelism</h3>
+ *
+ * <p>Processing elements with an explicit {@code for-}loop is inherently serial.
+ * Streams facilitate parallel execution by reframing the computation as a pipeline of
+ * aggregate operations, rather than as imperative operations on each individual
+ * element.  All streams operations can execute either in serial or in parallel.
+ * The stream implementations in the JDK create serial streams unless parallelism is
+ * explicitly requested.  For example, {@code Collection} has methods
+ * {@link java.util.Collection#stream} and {@link java.util.Collection#parallelStream},
+ * which produce sequential and parallel streams respectively; other
+ * stream-bearing methods such as {@link java.util.stream.IntStream#range(int, int)}
+ * produce sequential streams but these streams can be efficiently parallelized by
+ * invoking their {@link java.util.stream.BaseStream#parallel()} method.
+ * To execute the prior "sum of weights of widgets" query in parallel, we would
+ * do:
+ *
+ * <pre>{@code
+ *     int sumOfWeights = widgets.}<code><b>parallelStream()</b></code>{@code
+ *                               .filter(b -> b.getColor() == RED)
+ *                               .mapToInt(b -> b.getWeight())
+ *                               .sum();
+ * }</pre>
+ *
+ * <p>The only difference between the serial and parallel versions of this
+ * example is the creation of the initial stream, using "{@code parallelStream()}"
+ * instead of "{@code stream()}".  When the terminal operation is initiated,
+ * the stream pipeline is executed sequentially or in parallel depending on the
+ * orientation of the stream on which it is invoked.  Whether a stream will execute in serial or
+ * parallel can be determined with the {@code isParallel()} method, and the
+ * orientation of a stream can be modified with the
+ * {@link java.util.stream.BaseStream#sequential()} and
+ * {@link java.util.stream.BaseStream#parallel()} operations.  When the terminal
+ * operation is initiated, the stream pipeline is executed sequentially or in
+ * parallel depending on the mode of the stream on which it is invoked.
+ *
+ * <p>Except for operations identified as explicitly nondeterministic, such
+ * as {@code findAny()}, whether a stream executes sequentially or in parallel
+ * should not change the result of the computation.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, which are often lambda expressions.  To preserve correct behavior,
+ * these <em>behavioral parameters</em> must be <em>non-interfering</em>, and in
+ * most cases must be <em>stateless</em>.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.
+ *
+ * <h3><a name="NonInterference">Non-interference</a></h3>
+ *
+ * Streams enable you to execute possibly-parallel aggregate operations over a
+ * variety of data sources, including even non-thread-safe collections such as
+ * {@code ArrayList}. This is possible only if we can prevent
+ * <em>interference</em> with the data source during the execution of a stream
+ * pipeline.  Except for the escape-hatch operations {@code iterator()} and
+ * {@code spliterator()}, execution begins when the terminal operation is
+ * invoked, and ends when the terminal operation completes.  For most data
+ * sources, preventing interference means ensuring that the data source is
+ * <em>not modified at all</em> during the execution of the stream pipeline.
+ * The notable exception to this are streams whose sources are concurrent
+ * collections, which are specifically designed to handle concurrent modification.
+ * Concurrent stream sources are those whose {@code Spliterator} reports the
+ * {@code CONCURRENT} characteristic.
+ *
+ * <p>Accordingly, behavioral parameters in stream pipelines whose source might
+ * not be concurrent should never modify the stream's data source.
+ * A behavioral parameter is said to <em>interfere</em> with a non-concurrent
+ * data source if it modifies, or causes to be
+ * modified, the stream's data source.  The need for non-interference applies
+ * to all pipelines, not just parallel ones.  Unless the stream source is
+ * concurrent, modifying a stream's data source during execution of a stream
+ * pipeline can cause exceptions, incorrect answers, or nonconformant behavior.
+ *
+ * For well-behaved stream sources, the source can be modified before the
+ * terminal operation commences and those modifications will be reflected in
+ * the covered elements.  For example, consider the following code:
+ *
+ * <pre>{@code
+ *     List<String> l = new ArrayList(Arrays.asList("one", "two"));
+ *     Stream<String> sl = l.stream();
+ *     l.add("three");
+ *     String s = sl.collect(joining(" "));
+ * }</pre>
+ *
+ * First a list is created consisting of two strings: "one"; and "two". Then a
+ * stream is created from that list. Next the list is modified by adding a third
+ * string: "three". Finally the elements of the stream are collected and joined
+ * together. Since the list was modified before the terminal {@code collect}
+ * operation commenced the result will be a string of "one two three". All the
+ * streams returned from JDK collections, and most other JDK classes,
+ * are well-behaved in this manner; for streams generated by other libraries, see
+ * <a href="package-summary.html#StreamSources">Low-level stream
+ * construction</a> for requirements for building well-behaved streams.
+ *
+ * <h3><a name="Statelessness">Stateless behaviors</a></h3>
+ *
+ * Stream pipeline results may be nondeterministic or incorrect if the behavioral
+ * parameters to the stream operations are <em>stateful</em>.  A stateful lambda
+ * (or other object implementing the appropriate functional interface) is one
+ * whose result depends on any state which might change during the execution
+ * of the stream pipeline.  An example of a stateful lambda is the parameter
+ * to {@code map()} in:
+ *
+ * <pre>{@code
+ *     Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
+ *     stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
+ * }</pre>
+ *
+ * Here, if the mapping operation is performed in parallel, the results for the
+ * same input could vary from run to run, due to thread scheduling differences,
+ * whereas, with a stateless lambda expression the results would always be the
+ * same.
+ *
+ * <p>Note also that attempting to access mutable state from behavioral parameters
+ * presents you with a bad choice with respect to safety and performance; if
+ * you do not synchronize access to that state, you have a data race and
+ * therefore your code is broken, but if you do synchronize access to that
+ * state, you risk having contention undermine the parallelism you are seeking
+ * to benefit from.  The best approach is to avoid stateful behavioral
+ * parameters to stream operations entirely; there is usually a way to
+ * restructure the stream pipeline to avoid statefulness.
+ *
+ * <h3>Side-effects</h3>
+ *
+ * Side-effects in behavioral parameters to stream operations are, in general,
+ * discouraged, as they can often lead to unwitting violations of the
+ * statelessness requirement, as well as other thread-safety hazards.
+ *
+ * <p>If the behavioral parameters do have side-effects, unless explicitly
+ * stated, there are no guarantees as to the
+ * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>visibility</i></a>
+ * of those side-effects to other threads, nor are there any guarantees that
+ * different operations on the "same" element within the same stream pipeline
+ * are executed in the same thread.  Further, the ordering of those effects
+ * may be surprising.  Even when a pipeline is constrained to produce a
+ * <em>result</em> that is consistent with the encounter order of the stream
+ * source (for example, {@code IntStream.range(0,5).parallel().map(x -> x*2).toArray()}
+ * must produce {@code [0, 2, 4, 6, 8]}), no guarantees are made as to the order
+ * in which the mapper function is applied to individual elements, or in what
+ * thread any behavioral parameter is executed for a given element.
+ *
+ * <p>Many computations where one might be tempted to use side effects can be more
+ * safely and efficiently expressed without side-effects, such as using
+ * <a href="package-summary.html#Reduction">reduction</a> instead of mutable
+ * accumulators. However, side-effects such as using {@code println()} for debugging
+ * purposes are usually harmless.  A small number of stream operations, such as
+ * {@code forEach()} and {@code peek()}, can operate only via side-effects;
+ * these should be used with care.
+ *
+ * <p>As an example of how to transform a stream pipeline that inappropriately
+ * uses side-effects to one that does not, the following code searches a stream
+ * of strings for those matching a given regular expression, and puts the
+ * matches in a list.
+ *
+ * <pre>{@code
+ *     ArrayList<String> results = new ArrayList<>();
+ *     stream.filter(s -> pattern.matcher(s).matches())
+ *           .forEach(s -> results.add(s));  // Unnecessary use of side-effects!
+ * }</pre>
+ *
+ * This code unnecessarily uses side-effects.  If executed in parallel, the
+ * non-thread-safety of {@code ArrayList} would cause incorrect results, and
+ * adding needed synchronization would cause contention, undermining the
+ * benefit of parallelism.  Furthermore, using side-effects here is completely
+ * unnecessary; the {@code forEach()} can simply be replaced with a reduction
+ * operation that is safer, more efficient, and more amenable to
+ * parallelization:
+ *
+ * <pre>{@code
+ *     List<String>results =
+ *         stream.filter(s -> pattern.matcher(s).matches())
+ *               .collect(Collectors.toList());  // No side-effects!
+ * }</pre>
+ *
+ * <h3><a name="Ordering">Ordering</a></h3>
+ *
+ * <p>Streams may or may not have a defined <em>encounter order</em>.  Whether
+ * or not a stream has an encounter order depends on the source and the
+ * intermediate operations.  Certain stream sources (such as {@code List} or
+ * arrays) are intrinsically ordered, whereas others (such as {@code HashSet})
+ * are not.  Some intermediate operations, such as {@code sorted()}, may impose
+ * an encounter order on an otherwise unordered stream, and others may render an
+ * ordered stream unordered, such as {@link java.util.stream.BaseStream#unordered()}.
+ * Further, some terminal operations may ignore encounter order, such as
+ * {@code forEach()}.
+ *
+ * <p>If a stream is ordered, most operations are constrained to operate on the
+ * elements in their encounter order; if the source of a stream is a {@code List}
+ * containing {@code [1, 2, 3]}, then the result of executing {@code map(x -> x*2)}
+ * must be {@code [2, 4, 6]}.  However, if the source has no defined encounter
+ * order, then any permutation of the values {@code [2, 4, 6]} would be a valid
+ * result.
+ *
+ * <p>For sequential streams, the presence or absence of an encounter order does
+ * not affect performance, only determinism.  If a stream is ordered, repeated
+ * execution of identical stream pipelines on an identical source will produce
+ * an identical result; if it is not ordered, repeated execution might produce
+ * different results.
+ *
+ * <p>For parallel streams, relaxing the ordering constraint can sometimes enable
+ * more efficient execution.  Certain aggregate operations,
+ * such as filtering duplicates ({@code distinct()}) or grouped reductions
+ * ({@code Collectors.groupingBy()}) can be implemented more efficiently if ordering of elements
+ * is not relevant.  Similarly, operations that are intrinsically tied to encounter order,
+ * such as {@code limit()}, may require
+ * buffering to ensure proper ordering, undermining the benefit of parallelism.
+ * In cases where the stream has an encounter order, but the user does not
+ * particularly <em>care</em> about that encounter order, explicitly de-ordering
+ * the stream with {@link java.util.stream.BaseStream#unordered() unordered()} may
+ * improve parallel performance for some stateful or terminal operations.
+ * However, most stream pipelines, such as the "sum of weight of blocks" example
+ * above, still parallelize efficiently even under ordering constraints.
+ *
+ * <h2><a name="Reduction">Reduction operations</a></h2>
+ *
+ * A <em>reduction</em> operation (also called a <em>fold</em>) takes a sequence
+ * of input elements and combines them into a single summary result by repeated
+ * application of a combining operation, such as finding the sum or maximum of
+ * a set of numbers, or accumulating elements into a list.  The streams classes have
+ * multiple forms of general reduction operations, called
+ * {@link java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduce()}
+ * and {@link java.util.stream.Stream#collect(java.util.stream.Collector) collect()},
+ * as well as multiple specialized reduction forms such as
+ * {@link java.util.stream.IntStream#sum() sum()}, {@link java.util.stream.IntStream#max() max()},
+ * or {@link java.util.stream.IntStream#count() count()}.
+ *
+ * <p>Of course, such operations can be readily implemented as simple sequential
+ * loops, as in:
+ * <pre>{@code
+ *    int sum = 0;
+ *    for (int x : numbers) {
+ *       sum += x;
+ *    }
+ * }</pre>
+ * However, there are good reasons to prefer a reduce operation
+ * over a mutative accumulation such as the above.  Not only is a reduction
+ * "more abstract" -- it operates on the stream as a whole rather than individual
+ * elements -- but a properly constructed reduce operation is inherently
+ * parallelizable, so long as the function(s) used to process the elements
+ * are <a href="package-summary.html#Associativity">associative</a> and
+ * <a href="package-summary.html#NonInterfering">stateless</a>.
+ * For example, given a stream of numbers for which we want to find the sum, we
+ * can write:
+ * <pre>{@code
+ *    int sum = numbers.stream().reduce(0, (x,y) -> x+y);
+ * }</pre>
+ * or:
+ * <pre>{@code
+ *    int sum = numbers.stream().reduce(0, Integer::sum);
+ * }</pre>
+ *
+ * <p>These reduction operations can run safely in parallel with almost no
+ * modification:
+ * <pre>{@code
+ *    int sum = numbers.parallelStream().reduce(0, Integer::sum);
+ * }</pre>
+ *
+ * <p>Reduction parallellizes well because the implementation
+ * can operate on subsets of the data in parallel, and then combine the
+ * intermediate results to get the final correct answer.  (Even if the language
+ * had a "parallel for-each" construct, the mutative accumulation approach would
+ * still required the developer to provide
+ * thread-safe updates to the shared accumulating variable {@code sum}, and
+ * the required synchronization would then likely eliminate any performance gain from
+ * parallelism.)  Using {@code reduce()} instead removes all of the
+ * burden of parallelizing the reduction operation, and the library can provide
+ * an efficient parallel implementation with no additional synchronization
+ * required.
+ *
+ * <p>The "widgets" examples shown earlier shows how reduction combines with
+ * other operations to replace for loops with bulk operations.  If {@code widgets}
+ * is a collection of {@code Widget} objects, which have a {@code getWeight} method,
+ * we can find the heaviest widget with:
+ * <pre>{@code
+ *     OptionalInt heaviest = widgets.parallelStream()
+ *                                   .mapToInt(Widget::getWeight)
+ *                                   .max();
+ * }</pre>
+ *
+ * <p>In its more general form, a {@code reduce} operation on elements of type
+ * {@code <T>} yielding a result of type {@code <U>} requires three parameters:
+ * <pre>{@code
+ * <U> U reduce(U identity,
+ *              BiFunction<U, ? super T, U> accumulator,
+ *              BinaryOperator<U> combiner);
+ * }</pre>
+ * Here, the <em>identity</em> element is both an initial seed value for the reduction
+ * and a default result if there are no input elements. The <em>accumulator</em>
+ * function takes a partial result and the next element, and produces a new
+ * partial result. The <em>combiner</em> function combines two partial results
+ * to produce a new partial result.  (The combiner is necessary in parallel
+ * reductions, where the input is partitioned, a partial accumulation computed
+ * for each partition, and then the partial results are combined to produce a
+ * final result.)
+ *
+ * <p>More formally, the {@code identity} value must be an <em>identity</em> for
+ * the combiner function. This means that for all {@code u},
+ * {@code combiner.apply(identity, u)} is equal to {@code u}. Additionally, the
+ * {@code combiner} function must be <a href="package-summary.html#Associativity">associative</a> and
+ * must be compatible with the {@code accumulator} function: for all {@code u}
+ * and {@code t}, {@code combiner.apply(u, accumulator.apply(identity, t))} must
+ * be {@code equals()} to {@code accumulator.apply(u, t)}.
+ *
+ * <p>The three-argument form is a generalization of the two-argument form,
+ * incorporating a mapping step into the accumulation step.  We could
+ * re-cast the simple sum-of-weights example using the more general form as
+ * follows:
+ * <pre>{@code
+ *     int sumOfWeights = widgets.stream()
+ *                               .reduce(0,
+ *                                       (sum, b) -> sum + b.getWeight())
+ *                                       Integer::sum);
+ * }</pre>
+ * though the explicit map-reduce form is more readable and therefore should
+ * usually be preferred. The generalized form is provided for cases where
+ * significant work can be optimized away by combining mapping and reducing
+ * into a single function.
+ *
+ * <h3><a name="MutableReduction">Mutable reduction</a></h3>
+ *
+ * A <em>mutable reduction operation</em> accumulates input elements into a
+ * mutable result container, such as a {@code Collection} or {@code StringBuilder},
+ * as it processes the elements in the stream.
+ *
+ * <p>If we wanted to take a stream of strings and concatenate them into a
+ * single long string, we <em>could</em> achieve this with ordinary reduction:
+ * <pre>{@code
+ *     String concatenated = strings.reduce("", String::concat)
+ * }</pre>
+ *
+ * <p>We would get the desired result, and it would even work in parallel.  However,
+ * we might not be happy about the performance!  Such an implementation would do
+ * a great deal of string copying, and the run time would be <em>O(n^2)</em> in
+ * the number of characters.  A more performant approach would be to accumulate
+ * the results into a {@link java.lang.StringBuilder}, which is a mutable
+ * container for accumulating strings.  We can use the same technique to
+ * parallelize mutable reduction as we do with ordinary reduction.
+ *
+ * <p>The mutable reduction operation is called
+ * {@link java.util.stream.Stream#collect(Collector) collect()},
+ * as it collects together the desired results into a result container such
+ * as a {@code Collection}.
+ * A {@code collect} operation requires three functions:
+ * a supplier function to construct new instances of the result container, an
+ * accumulator function to incorporate an input element into a result
+ * container, and a combining function to merge the contents of one result
+ * container into another.  The form of this is very similar to the general
+ * form of ordinary reduction:
+ * <pre>{@code
+ * <R> R collect(Supplier<R> supplier,
+ *               BiConsumer<R, ? super T> accumulator,
+ *               BiConsumer<R, R> combiner);
+ * }</pre>
+ * <p>As with {@code reduce()}, a benefit of expressing {@code collect} in this
+ * abstract way is that it is directly amenable to parallelization: we can
+ * accumulate partial results in parallel and then combine them, so long as the
+ * accumulation and combining functions satisfy the appropriate requirements.
+ * For example, to collect the String representations of the elements in a
+ * stream into an {@code ArrayList}, we could write the obvious sequential
+ * for-each form:
+ * <pre>{@code
+ *     ArrayList<String> strings = new ArrayList<>();
+ *     for (T element : stream) {
+ *         strings.add(element.toString());
+ *     }
+ * }</pre>
+ * Or we could use a parallelizable collect form:
+ * <pre>{@code
+ *     ArrayList<String> strings = stream.collect(() -> new ArrayList<>(),
+ *                                                (c, e) -> c.add(e.toString()),
+ *                                                (c1, c2) -> c1.addAll(c2));
+ * }</pre>
+ * or, pulling the mapping operation out of the accumulator function, we could
+ * express it more succinctly as:
+ * <pre>{@code
+ *     List<String> strings = stream.map(Object::toString)
+ *                                  .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+ * }</pre>
+ * Here, our supplier is just the {@link java.util.ArrayList#ArrayList()
+ * ArrayList constructor}, the accumulator adds the stringified element to an
+ * {@code ArrayList}, and the combiner simply uses {@link java.util.ArrayList#addAll addAll}
+ * to copy the strings from one container into the other.
+ *
+ * <p>The three aspects of {@code collect} -- supplier, accumulator, and
+ * combiner -- are tightly coupled.  We can use the abstraction of a
+ * {@link java.util.stream.Collector} to capture all three aspects.  The
+ * above example for collecting strings into a {@code List} can be rewritten
+ * using a standard {@code Collector} as:
+ * <pre>{@code
+ *     List<String> strings = stream.map(Object::toString)
+ *                                  .collect(Collectors.toList());
+ * }</pre>
+ *
+ * <p>Packaging mutable reductions into a Collector has another advantage:
+ * composability.  The class {@link java.util.stream.Collectors} contains a
+ * number of predefined factories for collectors, including combinators
+ * that transform one collector into another.  For example, suppose we have a
+ * collector that computes the sum of the salaries of a stream of
+ * employees, as follows:
+ *
+ * <pre>{@code
+ *     Collector<Employee, ?, Integer> summingSalaries
+ *         = Collectors.summingInt(Employee::getSalary);
+ * }</pre>
+ *
+ * (The {@code ?} for the second type parameter merely indicates that we don't
+ * care about the intermediate representation used by this collector.)
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse {@code summingSalaries} using
+ * {@link java.util.stream.Collectors#groupingBy(java.util.function.Function, java.util.stream.Collector) groupingBy}:
+ *
+ * <pre>{@code
+ *     Map<Department, Integer> salariesByDept
+ *         = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,
+ *                                                            summingSalaries));
+ * }</pre>
+ *
+ * <p>As with the regular reduction operation, {@code collect()} operations can
+ * only be parallelized if appropriate conditions are met.  For any partially
+ * accumulated result, combining it with an empty result container must
+ * produce an equivalent result.  That is, for a partially accumulated result
+ * {@code p} that is the result of any series of accumulator and combiner
+ * invocations, {@code p} must be equivalent to
+ * {@code combiner.apply(p, supplier.get())}.
+ *
+ * <p>Further, however the computation is split, it must produce an equivalent
+ * result.  For any input elements {@code t1} and {@code t2}, the results
+ * {@code r1} and {@code r2} in the computation below must be equivalent:
+ * <pre>{@code
+ *     A a1 = supplier.get();
+ *     accumulator.accept(a1, t1);
+ *     accumulator.accept(a1, t2);
+ *     R r1 = finisher.apply(a1);  // result without splitting
+ *
+ *     A a2 = supplier.get();
+ *     accumulator.accept(a2, t1);
+ *     A a3 = supplier.get();
+ *     accumulator.accept(a3, t2);
+ *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
+ * }</pre>
+ *
+ * <p>Here, equivalence generally means according to {@link java.lang.Object#equals(Object)}.
+ * but in some cases equivalence may be relaxed to account for differences in
+ * order.
+ *
+ * <h3><a name="ConcurrentReduction">Reduction, concurrency, and ordering</a></h3>
+ *
+ * With some complex reduction operations, for example a {@code collect()} that
+ * produces a {@code Map}, such as:
+ * <pre>{@code
+ *     Map<Buyer, List<Transaction>> salesByBuyer
+ *         = txns.parallelStream()
+ *               .collect(Collectors.groupingBy(Transaction::getBuyer));
+ * }</pre>
+ * it may actually be counterproductive to perform the operation in parallel.
+ * This is because the combining step (merging one {@code Map} into another by
+ * key) can be expensive for some {@code Map} implementations.
+ *
+ * <p>Suppose, however, that the result container used in this reduction
+ * was a concurrently modifiable collection -- such as a
+ * {@link java.util.concurrent.ConcurrentHashMap}. In that case, the parallel
+ * invocations of the accumulator could actually deposit their results
+ * concurrently into the same shared result container, eliminating the need for
+ * the combiner to merge distinct result containers. This potentially provides
+ * a boost to the parallel execution performance. We call this a
+ * <em>concurrent</em> reduction.
+ *
+ * <p>A {@link java.util.stream.Collector} that supports concurrent reduction is
+ * marked with the {@link java.util.stream.Collector.Characteristics#CONCURRENT}
+ * characteristic.  However, a concurrent collection also has a downside.  If
+ * multiple threads are depositing results concurrently into a shared container,
+ * the order in which results are deposited is non-deterministic. Consequently,
+ * a concurrent reduction is only possible if ordering is not important for the
+ * stream being processed. The {@link java.util.stream.Stream#collect(Collector)}
+ * implementation will only perform a concurrent reduction if
+ * <ul>
+ * <li>The stream is parallel;</li>
+ * <li>The collector has the
+ * {@link java.util.stream.Collector.Characteristics#CONCURRENT} characteristic,
+ * and;</li>
+ * <li>Either the stream is unordered, or the collector has the
+ * {@link java.util.stream.Collector.Characteristics#UNORDERED} characteristic.
+ * </ul>
+ * You can ensure the stream is unordered by using the
+ * {@link java.util.stream.BaseStream#unordered()} method.  For example:
+ * <pre>{@code
+ *     Map<Buyer, List<Transaction>> salesByBuyer
+ *         = txns.parallelStream()
+ *               .unordered()
+ *               .collect(groupingByConcurrent(Transaction::getBuyer));
+ * }</pre>
+ * (where {@link java.util.stream.Collectors#groupingByConcurrent} is the
+ * concurrent equivalent of {@code groupingBy}).
+ *
+ * <p>Note that if it is important that the elements for a given key appear in
+ * the order they appear in the source, then we cannot use a concurrent
+ * reduction, as ordering is one of the casualties of concurrent insertion.
+ * We would then be constrained to implement either a sequential reduction or
+ * a merge-based parallel reduction.
+ *
+ * <h3><a name="Associativity">Associativity</a></h3>
+ *
+ * An operator or function {@code op} is <em>associative</em> if the following
+ * holds:
+ * <pre>{@code
+ *     (a op b) op c == a op (b op c)
+ * }</pre>
+ * The importance of this to parallel evaluation can be seen if we expand this
+ * to four terms:
+ * <pre>{@code
+ *     a op b op c op d == (a op b) op (c op d)
+ * }</pre>
+ * So we can evaluate {@code (a op b)} in parallel with {@code (c op d)}, and
+ * then invoke {@code op} on the results.
+ *
+ * <p>Examples of associative operations include numeric addition, min, and
+ * max, and string concatenation.
+ *
+ * <h2><a name="StreamSources">Low-level stream construction</a></h2>
+ *
+ * So far, all the stream examples have used methods like
+ * {@link java.util.Collection#stream()} or {@link java.util.Arrays#stream(Object[])}
+ * to obtain a stream.  How are those stream-bearing methods implemented?
+ *
+ * <p>The class {@link java.util.stream.StreamSupport} has a number of
+ * low-level methods for creating a stream, all using some form of a
+ * {@link java.util.Spliterator}. A spliterator is the parallel analogue of an
+ * {@link java.util.Iterator}; it describes a (possibly infinite) collection of
+ * elements, with support for sequentially advancing, bulk traversal, and
+ * splitting off some portion of the input into another spliterator which can
+ * be processed in parallel.  At the lowest level, all streams are driven by a
+ * spliterator.
+ *
+ * <p>There are a number of implementation choices in implementing a
+ * spliterator, nearly all of which are tradeoffs between simplicity of
+ * implementation and runtime performance of streams using that spliterator.
+ * The simplest, but least performant, way to create a spliterator is to
+ * create one from an iterator using
+ * {@link java.util.Spliterators#spliteratorUnknownSize(java.util.Iterator, int)}.
+ * While such a spliterator will work, it will likely offer poor parallel
+ * performance, since we have lost sizing information (how big is the
+ * underlying data set), as well as being constrained to a simplistic
+ * splitting algorithm.
+ *
+ * <p>A higher-quality spliterator will provide balanced and known-size
+ * splits, accurate sizing information, and a number of other
+ * {@link java.util.Spliterator#characteristics() characteristics} of the
+ * spliterator or data that can be used by implementations to optimize
+ * execution.
+ *
+ * <p>Spliterators for mutable data sources have an additional challenge;
+ * timing of binding to the data, since the data could change between the time
+ * the spliterator is created and the time the stream pipeline is executed.
+ * Ideally, a spliterator for a stream would report a characteristic of
+
+ * {@code IMMUTABLE} or {@code CONCURRENT}; if not it should be
+ * <a href="../Spliterator.html#binding"><em>late-binding</em></a>. If a source
+ * cannot directly supply a recommended spliterator, it may indirectly supply
+ * a spliterator using a {@code Supplier}, and construct a stream via the
+ * {@code Supplier}-accepting versions of
+ * {@link java.util.stream.StreamSupport#stream(Supplier, int, boolean) stream()}.
+ * The spliterator is obtained from the supplier only after the terminal
+ * operation of the stream pipeline commences.
+ *
+ * <p>These requirements significantly reduce the scope of potential
+ * interference between mutations of the stream source and execution of stream
+ * pipelines. Streams based on spliterators with the desired characteristics,
+ * or those using the Supplier-based factory forms, are immune to
+ * modifications of the data source prior to commencement of the terminal
+ * operation (provided the behavioral parameters to the stream operations meet
+ * the required criteria for non-interference and statelessness).  See
+ * <a href="package-summary.html#NonInterference">Non-Interference</a>
+ * for more details.
+ *
+ * @since 1.8
+ */
+package java.util.stream;
+
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
diff --git a/java/util/zip/Adler32.java b/java/util/zip/Adler32.java
new file mode 100644
index 0000000..de279f9
--- /dev/null
+++ b/java/util/zip/Adler32.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.nio.ByteBuffer;
+import sun.nio.ch.DirectBuffer;
+
+/**
+ * A class that can be used to compute the Adler-32 checksum of a data
+ * stream. An Adler-32 checksum is almost as reliable as a CRC-32 but
+ * can be computed much faster.
+ *
+ * <p> Passing a {@code null} argument to a method in this class will cause
+ * a {@link NullPointerException} to be thrown.
+ *
+ * @see         Checksum
+ * @author      David Connelly
+ */
+public
+class Adler32 implements Checksum {
+
+    private int adler = 1;
+
+    /**
+     * Creates a new Adler32 object.
+     */
+    public Adler32() {
+    }
+
+    /**
+     * Updates the checksum with the specified byte (the low eight
+     * bits of the argument b).
+     *
+     * @param b the byte to update the checksum with
+     */
+    public void update(int b) {
+        adler = update(adler, b);
+    }
+
+    /**
+     * Updates the checksum with the specified array of bytes.
+     *
+     * @throws  ArrayIndexOutOfBoundsException
+     *          if {@code off} is negative, or {@code len} is negative,
+     *          or {@code off+len} is greater than the length of the
+     *          array {@code b}
+     */
+    public void update(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        adler = updateBytes(adler, b, off, len);
+    }
+
+    /**
+     * Updates the checksum with the specified array of bytes.
+     *
+     * @param b the byte array to update the checksum with
+     */
+    public void update(byte[] b) {
+        adler = updateBytes(adler, b, 0, b.length);
+    }
+
+
+    /**
+     * Updates the checksum with the bytes from the specified buffer.
+     *
+     * The checksum is updated using
+     * buffer.{@link java.nio.Buffer#remaining() remaining()}
+     * bytes starting at
+     * buffer.{@link java.nio.Buffer#position() position()}
+     * Upon return, the buffer's position will be updated to its
+     * limit; its limit will not have been changed.
+     *
+     * @param buffer the ByteBuffer to update the checksum with
+     * @since 1.8
+     */
+    public void update(ByteBuffer buffer) {
+        int pos = buffer.position();
+        int limit = buffer.limit();
+        assert (pos <= limit);
+        int rem = limit - pos;
+        if (rem <= 0)
+            return;
+        if (buffer instanceof DirectBuffer) {
+            adler = updateByteBuffer(adler, ((DirectBuffer)buffer).address(), pos, rem);
+        } else if (buffer.hasArray()) {
+            adler = updateBytes(adler, buffer.array(), pos + buffer.arrayOffset(), rem);
+        } else {
+            byte[] b = new byte[rem];
+            buffer.get(b);
+            adler = updateBytes(adler, b, 0, b.length);
+        }
+        buffer.position(limit);
+    }
+
+    /**
+     * Resets the checksum to initial value.
+     */
+    public void reset() {
+        adler = 1;
+    }
+
+    /**
+     * Returns the checksum value.
+     */
+    public long getValue() {
+        return (long)adler & 0xffffffffL;
+    }
+
+    private native static int update(int adler, int b);
+    private native static int updateBytes(int adler, byte[] b, int off,
+                                          int len);
+    private native static int updateByteBuffer(int adler, long addr,
+                                               int off, int len);
+}
diff --git a/java/util/zip/CRC32.java b/java/util/zip/CRC32.java
new file mode 100644
index 0000000..0f55579
--- /dev/null
+++ b/java/util/zip/CRC32.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.nio.ByteBuffer;
+import sun.nio.ch.DirectBuffer;
+
+/**
+ * A class that can be used to compute the CRC-32 of a data stream.
+ *
+ * <p> Passing a {@code null} argument to a method in this class will cause
+ * a {@link NullPointerException} to be thrown.
+ *
+ * @see         Checksum
+ * @author      David Connelly
+ */
+public
+class CRC32 implements Checksum {
+    private int crc;
+
+    /**
+     * Creates a new CRC32 object.
+     */
+    public CRC32() {
+    }
+
+
+    /**
+     * Updates the CRC-32 checksum with the specified byte (the low
+     * eight bits of the argument b).
+     *
+     * @param b the byte to update the checksum with
+     */
+    public void update(int b) {
+        crc = update(crc, b);
+    }
+
+    /**
+     * Updates the CRC-32 checksum with the specified array of bytes.
+     *
+     * @throws  ArrayIndexOutOfBoundsException
+     *          if {@code off} is negative, or {@code len} is negative,
+     *          or {@code off+len} is greater than the length of the
+     *          array {@code b}
+     */
+    public void update(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        crc = updateBytes(crc, b, off, len);
+    }
+
+    /**
+     * Updates the CRC-32 checksum with the specified array of bytes.
+     *
+     * @param b the array of bytes to update the checksum with
+     */
+    public void update(byte[] b) {
+        crc = updateBytes(crc, b, 0, b.length);
+    }
+
+    /**
+     * Updates the checksum with the bytes from the specified buffer.
+     *
+     * The checksum is updated using
+     * buffer.{@link java.nio.Buffer#remaining() remaining()}
+     * bytes starting at
+     * buffer.{@link java.nio.Buffer#position() position()}
+     * Upon return, the buffer's position will
+     * be updated to its limit; its limit will not have been changed.
+     *
+     * @param buffer the ByteBuffer to update the checksum with
+     * @since 1.8
+     */
+    public void update(ByteBuffer buffer) {
+        int pos = buffer.position();
+        int limit = buffer.limit();
+        assert (pos <= limit);
+        int rem = limit - pos;
+        if (rem <= 0)
+            return;
+        if (buffer instanceof DirectBuffer) {
+            crc = updateByteBuffer(crc, ((DirectBuffer)buffer).address(), pos, rem);
+        } else if (buffer.hasArray()) {
+            crc = updateBytes(crc, buffer.array(), pos + buffer.arrayOffset(), rem);
+        } else {
+            byte[] b = new byte[rem];
+            buffer.get(b);
+            crc = updateBytes(crc, b, 0, b.length);
+        }
+        buffer.position(limit);
+    }
+
+    /**
+     * Resets CRC-32 to initial value.
+     */
+    public void reset() {
+        crc = 0;
+    }
+
+    /**
+     * Returns CRC-32 value.
+     */
+    public long getValue() {
+        return (long)crc & 0xffffffffL;
+    }
+
+    private native static int update(int crc, int b);
+    private native static int updateBytes(int crc, byte[] b, int off, int len);
+
+    private native static int updateByteBuffer(int adler, long addr,
+                                               int off, int len);
+}
diff --git a/java/util/zip/CheckedInputStream.java b/java/util/zip/CheckedInputStream.java
new file mode 100644
index 0000000..e1e5249
--- /dev/null
+++ b/java/util/zip/CheckedInputStream.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * An input stream that also maintains a checksum of the data being read.
+ * The checksum can then be used to verify the integrity of the input data.
+ *
+ * @see         Checksum
+ * @author      David Connelly
+ */
+public
+class CheckedInputStream extends FilterInputStream {
+    private Checksum cksum;
+
+    /**
+     * Creates an input stream using the specified Checksum.
+     * @param in the input stream
+     * @param cksum the Checksum
+     */
+    public CheckedInputStream(InputStream in, Checksum cksum) {
+        super(in);
+        this.cksum = cksum;
+    }
+
+    /**
+     * Reads a byte. Will block if no input is available.
+     * @return the byte read, or -1 if the end of the stream is reached.
+     * @exception IOException if an I/O error has occurred
+     */
+    public int read() throws IOException {
+        int b = in.read();
+        if (b != -1) {
+            cksum.update(b);
+        }
+        return b;
+    }
+
+    /**
+     * Reads into an array of bytes. If <code>len</code> is not zero, the method
+     * blocks until some input is available; otherwise, no
+     * bytes are read and <code>0</code> is returned.
+     * @param buf the buffer into which the data is read
+     * @param off the start offset in the destination array <code>b</code>
+     * @param len the maximum number of bytes read
+     * @return    the actual number of bytes read, or -1 if the end
+     *            of the stream is reached.
+     * @exception  NullPointerException If <code>buf</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>buf.length - off</code>
+     * @exception IOException if an I/O error has occurred
+     */
+    public int read(byte[] buf, int off, int len) throws IOException {
+        len = in.read(buf, off, len);
+        if (len != -1) {
+            cksum.update(buf, off, len);
+        }
+        return len;
+    }
+
+    /**
+     * Skips specified number of bytes of input.
+     * @param n the number of bytes to skip
+     * @return the actual number of bytes skipped
+     * @exception IOException if an I/O error has occurred
+     */
+    public long skip(long n) throws IOException {
+        byte[] buf = new byte[512];
+        long total = 0;
+        while (total < n) {
+            long len = n - total;
+            len = read(buf, 0, len < buf.length ? (int)len : buf.length);
+            if (len == -1) {
+                return total;
+            }
+            total += len;
+        }
+        return total;
+    }
+
+    /**
+     * Returns the Checksum for this input stream.
+     * @return the Checksum value
+     */
+    public Checksum getChecksum() {
+        return cksum;
+    }
+}
diff --git a/java/util/zip/CheckedOutputStream.java b/java/util/zip/CheckedOutputStream.java
new file mode 100644
index 0000000..698b941
--- /dev/null
+++ b/java/util/zip/CheckedOutputStream.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * An output stream that also maintains a checksum of the data being
+ * written. The checksum can then be used to verify the integrity of
+ * the output data.
+ *
+ * @see         Checksum
+ * @author      David Connelly
+ */
+public
+class CheckedOutputStream extends FilterOutputStream {
+    private Checksum cksum;
+
+    /**
+     * Creates an output stream with the specified Checksum.
+     * @param out the output stream
+     * @param cksum the checksum
+     */
+    public CheckedOutputStream(OutputStream out, Checksum cksum) {
+        super(out);
+        this.cksum = cksum;
+    }
+
+    /**
+     * Writes a byte. Will block until the byte is actually written.
+     * @param b the byte to be written
+     * @exception IOException if an I/O error has occurred
+     */
+    public void write(int b) throws IOException {
+        out.write(b);
+        cksum.update(b);
+    }
+
+    /**
+     * Writes an array of bytes. Will block until the bytes are
+     * actually written.
+     * @param b the data to be written
+     * @param off the start offset of the data
+     * @param len the number of bytes to be written
+     * @exception IOException if an I/O error has occurred
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        out.write(b, off, len);
+        cksum.update(b, off, len);
+    }
+
+    /**
+     * Returns the Checksum for this output stream.
+     * @return the Checksum
+     */
+    public Checksum getChecksum() {
+        return cksum;
+    }
+}
diff --git a/java/util/zip/Checksum.java b/java/util/zip/Checksum.java
new file mode 100644
index 0000000..0369c53
--- /dev/null
+++ b/java/util/zip/Checksum.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/**
+ * An interface representing a data checksum.
+ *
+ * @author      David Connelly
+ */
+public
+interface Checksum {
+    /**
+     * Updates the current checksum with the specified byte.
+     *
+     * @param b the byte to update the checksum with
+     */
+    public void update(int b);
+
+    /**
+     * Updates the current checksum with the specified array of bytes.
+     * @param b the byte array to update the checksum with
+     * @param off the start offset of the data
+     * @param len the number of bytes to use for the update
+     */
+    public void update(byte[] b, int off, int len);
+
+    /**
+     * Returns the current checksum value.
+     * @return the current checksum value
+     */
+    public long getValue();
+
+    /**
+     * Resets the checksum to its initial value.
+     */
+    public void reset();
+}
diff --git a/java/util/zip/DataFormatException.java b/java/util/zip/DataFormatException.java
new file mode 100644
index 0000000..77adbe9
--- /dev/null
+++ b/java/util/zip/DataFormatException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/**
+ * Signals that a data format error has occurred.
+ *
+ * @author      David Connelly
+ */
+public
+class DataFormatException extends Exception {
+    private static final long serialVersionUID = 2219632870893641452L;
+
+    /**
+     * Constructs a DataFormatException with no detail message.
+     */
+    public DataFormatException() {
+        super();
+    }
+
+    /**
+     * Constructs a DataFormatException with the specified detail message.
+     * A detail message is a String that describes this particular exception.
+     * @param s the String containing a detail message
+     */
+    public DataFormatException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/zip/Deflater.java b/java/util/zip/Deflater.java
new file mode 100644
index 0000000..5c7dffd
--- /dev/null
+++ b/java/util/zip/Deflater.java
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.CloseGuard;
+
+/**
+ * This class provides support for general purpose compression using the
+ * popular ZLIB compression library. The ZLIB compression library was
+ * initially developed as part of the PNG graphics standard and is not
+ * protected by patents. It is fully described in the specifications at
+ * the <a href="package-summary.html#package_description">java.util.zip
+ * package description</a>.
+ *
+ * <p>The following code fragment demonstrates a trivial compression
+ * and decompression of a string using <tt>Deflater</tt> and
+ * <tt>Inflater</tt>.
+ *
+ * <blockquote><pre>
+ * try {
+ *     // Encode a String into bytes
+ *     String inputString = "blahblahblah";
+ *     byte[] input = inputString.getBytes("UTF-8");
+ *
+ *     // Compress the bytes
+ *     byte[] output = new byte[100];
+ *     Deflater compresser = new Deflater();
+ *     compresser.setInput(input);
+ *     compresser.finish();
+ *     int compressedDataLength = compresser.deflate(output);
+ *     compresser.end();
+ *
+ *     // Decompress the bytes
+ *     Inflater decompresser = new Inflater();
+ *     decompresser.setInput(output, 0, compressedDataLength);
+ *     byte[] result = new byte[100];
+ *     int resultLength = decompresser.inflate(result);
+ *     decompresser.end();
+ *
+ *     // Decode the bytes into a String
+ *     String outputString = new String(result, 0, resultLength, "UTF-8");
+ * } catch(java.io.UnsupportedEncodingException ex) {
+ *     // handle
+ * } catch (java.util.zip.DataFormatException ex) {
+ *     // handle
+ * }
+ * </pre></blockquote>
+ *
+ * @see         Inflater
+ * @author      David Connelly
+ */
+public
+class Deflater {
+
+    // Android-added: @ReachabilitySensitive
+    // Finalization clears zsRef, and thus can't be allowed to occur early.
+    // Unlike some other CloseGuard uses, the spec allows clients to rely on finalization
+    // here.  Thus dropping a deflater without calling end() should work correctly.
+    // It thus does not suffice to just rely on the CloseGuard annotation.
+    @ReachabilitySensitive
+    private final ZStreamRef zsRef;
+    private byte[] buf = new byte[0];
+    private int off, len;
+    private int level, strategy;
+    private boolean setParams;
+    private boolean finish, finished;
+    private long bytesRead;
+    private long bytesWritten;
+
+    // Android-added: CloseGuard support.
+    @ReachabilitySensitive
+    private final CloseGuard guard = CloseGuard.get();
+
+    /**
+     * Compression method for the deflate algorithm (the only one currently
+     * supported).
+     */
+    public static final int DEFLATED = 8;
+
+    /**
+     * Compression level for no compression.
+     */
+    public static final int NO_COMPRESSION = 0;
+
+    /**
+     * Compression level for fastest compression.
+     */
+    public static final int BEST_SPEED = 1;
+
+    /**
+     * Compression level for best compression.
+     */
+    public static final int BEST_COMPRESSION = 9;
+
+    /**
+     * Default compression level.
+     */
+    public static final int DEFAULT_COMPRESSION = -1;
+
+    /**
+     * Compression strategy best used for data consisting mostly of small
+     * values with a somewhat random distribution. Forces more Huffman coding
+     * and less string matching.
+     */
+    public static final int FILTERED = 1;
+
+    /**
+     * Compression strategy for Huffman coding only.
+     */
+    public static final int HUFFMAN_ONLY = 2;
+
+    /**
+     * Default compression strategy.
+     */
+    public static final int DEFAULT_STRATEGY = 0;
+
+    /**
+     * Compression flush mode used to achieve best compression result.
+     *
+     * @see Deflater#deflate(byte[], int, int, int)
+     * @since 1.7
+     */
+    public static final int NO_FLUSH = 0;
+
+    /**
+     * Compression flush mode used to flush out all pending output; may
+     * degrade compression for some compression algorithms.
+     *
+     * @see Deflater#deflate(byte[], int, int, int)
+     * @since 1.7
+     */
+    public static final int SYNC_FLUSH = 2;
+
+    /**
+     * Compression flush mode used to flush out all pending output and
+     * reset the deflater. Using this mode too often can seriously degrade
+     * compression.
+     *
+     * @see Deflater#deflate(byte[], int, int, int)
+     * @since 1.7
+     */
+    public static final int FULL_FLUSH = 3;
+
+    // Android-removed: initIDs handled in register method.
+    /*
+    static {
+        /* Zip library is loaded from System.initializeSystemClass *
+        initIDs();
+    }
+    */
+
+    /**
+     * Creates a new compressor using the specified compression level.
+     * If 'nowrap' is true then the ZLIB header and checksum fields will
+     * not be used in order to support the compression format used in
+     * both GZIP and PKZIP.
+     * @param level the compression level (0-9)
+     * @param nowrap if true then use GZIP compatible compression
+     */
+    public Deflater(int level, boolean nowrap) {
+        this.level = level;
+        this.strategy = DEFAULT_STRATEGY;
+        this.zsRef = new ZStreamRef(init(level, DEFAULT_STRATEGY, nowrap));
+        // Android-added: CloseGuard support.
+        guard.open("end");
+    }
+
+    /**
+     * Creates a new compressor using the specified compression level.
+     * Compressed data will be generated in ZLIB format.
+     * @param level the compression level (0-9)
+     */
+    public Deflater(int level) {
+        this(level, false);
+    }
+
+    /**
+     * Creates a new compressor with the default compression level.
+     * Compressed data will be generated in ZLIB format.
+     */
+    public Deflater() {
+        this(DEFAULT_COMPRESSION, false);
+    }
+
+    /**
+     * Sets input data for compression. This should be called whenever
+     * needsInput() returns true indicating that more input data is required.
+     * @param b the input data bytes
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @see Deflater#needsInput
+     */
+    public void setInput(byte[] b, int off, int len) {
+        if (b== null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            this.buf = b;
+            this.off = off;
+            this.len = len;
+        }
+    }
+
+    /**
+     * Sets input data for compression. This should be called whenever
+     * needsInput() returns true indicating that more input data is required.
+     * @param b the input data bytes
+     * @see Deflater#needsInput
+     */
+    public void setInput(byte[] b) {
+        setInput(b, 0, b.length);
+    }
+
+    /**
+     * Sets preset dictionary for compression. A preset dictionary is used
+     * when the history buffer can be predetermined. When the data is later
+     * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
+     * in order to get the Adler-32 value of the dictionary required for
+     * decompression.
+     * @param b the dictionary data bytes
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @see Inflater#inflate
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            setDictionary(zsRef.address(), b, off, len);
+        }
+    }
+
+    /**
+     * Sets preset dictionary for compression. A preset dictionary is used
+     * when the history buffer can be predetermined. When the data is later
+     * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
+     * in order to get the Adler-32 value of the dictionary required for
+     * decompression.
+     * @param b the dictionary data bytes
+     * @see Inflater#inflate
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] b) {
+        setDictionary(b, 0, b.length);
+    }
+
+    /**
+     * Sets the compression strategy to the specified value.
+     *
+     * <p> If the compression strategy is changed, the next invocation
+     * of {@code deflate} will compress the input available so far with
+     * the old strategy (and may be flushed); the new strategy will take
+     * effect only after that invocation.
+     *
+     * @param strategy the new compression strategy
+     * @exception IllegalArgumentException if the compression strategy is
+     *                                     invalid
+     */
+    public void setStrategy(int strategy) {
+        switch (strategy) {
+          case DEFAULT_STRATEGY:
+          case FILTERED:
+          case HUFFMAN_ONLY:
+            break;
+          default:
+            throw new IllegalArgumentException();
+        }
+        synchronized (zsRef) {
+            if (this.strategy != strategy) {
+                this.strategy = strategy;
+                setParams = true;
+            }
+        }
+    }
+
+    /**
+     * Sets the compression level to the specified value.
+     *
+     * <p> If the compression level is changed, the next invocation
+     * of {@code deflate} will compress the input available so far
+     * with the old level (and may be flushed); the new level will
+     * take effect only after that invocation.
+     *
+     * @param level the new compression level (0-9)
+     * @exception IllegalArgumentException if the compression level is invalid
+     */
+    public void setLevel(int level) {
+        if ((level < 0 || level > 9) && level != DEFAULT_COMPRESSION) {
+            throw new IllegalArgumentException("invalid compression level");
+        }
+        synchronized (zsRef) {
+            if (this.level != level) {
+                this.level = level;
+                setParams = true;
+            }
+        }
+    }
+
+    /**
+     * Returns true if the input data buffer is empty and setInput()
+     * should be called in order to provide more input.
+     * @return true if the input data buffer is empty and setInput()
+     * should be called in order to provide more input
+     */
+    public boolean needsInput() {
+        synchronized (zsRef) {
+            return len <= 0;
+        }
+    }
+
+    /**
+     * When called, indicates that compression should end with the current
+     * contents of the input buffer.
+     */
+    public void finish() {
+        synchronized (zsRef) {
+            finish = true;
+        }
+    }
+
+    /**
+     * Returns true if the end of the compressed data output stream has
+     * been reached.
+     * @return true if the end of the compressed data output stream has
+     * been reached
+     */
+    public boolean finished() {
+        synchronized (zsRef) {
+            return finished;
+        }
+    }
+
+    /**
+     * Compresses the input data and fills specified buffer with compressed
+     * data. Returns actual number of bytes of compressed data. A return value
+     * of 0 indicates that {@link #needsInput() needsInput} should be called
+     * in order to determine if more input data is required.
+     *
+     * <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
+     * An invocation of this method of the form {@code deflater.deflate(b, off, len)}
+     * yields the same result as the invocation of
+     * {@code deflater.deflate(b, off, len, Deflater.NO_FLUSH)}.
+     *
+     * @param b the buffer for the compressed data
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes of compressed data
+     * @return the actual number of bytes of compressed data written to the
+     *         output buffer
+     */
+    public int deflate(byte[] b, int off, int len) {
+        return deflate(b, off, len, NO_FLUSH);
+    }
+
+    /**
+     * Compresses the input data and fills specified buffer with compressed
+     * data. Returns actual number of bytes of compressed data. A return value
+     * of 0 indicates that {@link #needsInput() needsInput} should be called
+     * in order to determine if more input data is required.
+     *
+     * <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
+     * An invocation of this method of the form {@code deflater.deflate(b)}
+     * yields the same result as the invocation of
+     * {@code deflater.deflate(b, 0, b.length, Deflater.NO_FLUSH)}.
+     *
+     * @param b the buffer for the compressed data
+     * @return the actual number of bytes of compressed data written to the
+     *         output buffer
+     */
+    public int deflate(byte[] b) {
+        return deflate(b, 0, b.length, NO_FLUSH);
+    }
+
+    /**
+     * Compresses the input data and fills the specified buffer with compressed
+     * data. Returns actual number of bytes of data compressed.
+     *
+     * <p>Compression flush mode is one of the following three modes:
+     *
+     * <ul>
+     * <li>{@link #NO_FLUSH}: allows the deflater to decide how much data
+     * to accumulate, before producing output, in order to achieve the best
+     * compression (should be used in normal use scenario). A return value
+     * of 0 in this flush mode indicates that {@link #needsInput()} should
+     * be called in order to determine if more input data is required.
+     *
+     * <li>{@link #SYNC_FLUSH}: all pending output in the deflater is flushed,
+     * to the specified output buffer, so that an inflater that works on
+     * compressed data can get all input data available so far (In particular
+     * the {@link #needsInput()} returns {@code true} after this invocation
+     * if enough output space is provided). Flushing with {@link #SYNC_FLUSH}
+     * may degrade compression for some compression algorithms and so it
+     * should be used only when necessary.
+     *
+     * <li>{@link #FULL_FLUSH}: all pending output is flushed out as with
+     * {@link #SYNC_FLUSH}. The compression state is reset so that the inflater
+     * that works on the compressed output data can restart from this point
+     * if previous compressed data has been damaged or if random access is
+     * desired. Using {@link #FULL_FLUSH} too often can seriously degrade
+     * compression.
+     * </ul>
+     *
+     * <p>In the case of {@link #FULL_FLUSH} or {@link #SYNC_FLUSH}, if
+     * the return value is {@code len}, the space available in output
+     * buffer {@code b}, this method should be invoked again with the same
+     * {@code flush} parameter and more output space.
+     *
+     * @param b the buffer for the compressed data
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes of compressed data
+     * @param flush the compression flush mode
+     * @return the actual number of bytes of compressed data written to
+     *         the output buffer
+     *
+     * @throws IllegalArgumentException if the flush mode is invalid
+     * @since 1.7
+     */
+    public int deflate(byte[] b, int off, int len, int flush) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            if (flush == NO_FLUSH || flush == SYNC_FLUSH ||
+                flush == FULL_FLUSH) {
+                int thisLen = this.len;
+                int n = deflateBytes(zsRef.address(), b, off, len, flush);
+                bytesWritten += n;
+                bytesRead += (thisLen - this.len);
+                return n;
+            }
+            throw new IllegalArgumentException();
+        }
+    }
+
+    /**
+     * Returns the ADLER-32 value of the uncompressed data.
+     * @return the ADLER-32 value of the uncompressed data
+     */
+    public int getAdler() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return getAdler(zsRef.address());
+        }
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes input so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of uncompressed bytes input so far
+     */
+    public int getTotalIn() {
+        return (int) getBytesRead();
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes input so far.
+     *
+     * @return the total (non-negative) number of uncompressed bytes input so far
+     * @since 1.5
+     */
+    public long getBytesRead() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesRead;
+        }
+    }
+
+    /**
+     * Returns the total number of compressed bytes output so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of compressed bytes output so far
+     */
+    public int getTotalOut() {
+        return (int) getBytesWritten();
+    }
+
+    /**
+     * Returns the total number of compressed bytes output so far.
+     *
+     * @return the total (non-negative) number of compressed bytes output so far
+     * @since 1.5
+     */
+    public long getBytesWritten() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesWritten;
+        }
+    }
+
+    /**
+     * Resets deflater so that a new set of input data can be processed.
+     * Keeps current compression level and strategy settings.
+     */
+    public void reset() {
+        synchronized (zsRef) {
+            ensureOpen();
+            reset(zsRef.address());
+            finish = false;
+            finished = false;
+            off = len = 0;
+            bytesRead = bytesWritten = 0;
+        }
+    }
+
+    /**
+     * Closes the compressor and discards any unprocessed input.
+     * This method should be called when the compressor is no longer
+     * being used, but will also be called automatically by the
+     * finalize() method. Once this method is called, the behavior
+     * of the Deflater object is undefined.
+     */
+    public void end() {
+        synchronized (zsRef) {
+            // Android-added: CloseGuard support.
+            guard.close();
+            long addr = zsRef.address();
+            zsRef.clear();
+            if (addr != 0) {
+                end(addr);
+                buf = null;
+            }
+        }
+    }
+
+    /**
+     * Closes the compressor when garbage is collected.
+     */
+    protected void finalize() {
+        // Android-added: CloseGuard support.
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+        end();
+    }
+
+    private void ensureOpen() {
+        assert Thread.holdsLock(zsRef);
+        if (zsRef.address() == 0)
+            throw new NullPointerException("Deflater has been closed");
+    }
+
+    // Android-changed: initIDs handled in register method.
+    // private native static void initIDs();
+    private native static long init(int level, int strategy, boolean nowrap);
+    private native static void setDictionary(long addr, byte[] b, int off, int len);
+    private native int deflateBytes(long addr, byte[] b, int off, int len,
+                                    int flush);
+    private native static int getAdler(long addr);
+    private native static void reset(long addr);
+    private native static void end(long addr);
+}
diff --git a/java/util/zip/DeflaterInputStream.java b/java/util/zip/DeflaterInputStream.java
new file mode 100644
index 0000000..c3f7802
--- /dev/null
+++ b/java/util/zip/DeflaterInputStream.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Implements an input stream filter for compressing data in the "deflate"
+ * compression format.
+ *
+ * @since       1.6
+ * @author      David R Tribble ([email protected])
+ *
+ * @see DeflaterOutputStream
+ * @see InflaterOutputStream
+ * @see InflaterInputStream
+ */
+
+public class DeflaterInputStream extends FilterInputStream {
+    /** Compressor for this stream. */
+    protected final Deflater def;
+
+    /** Input buffer for reading compressed data. */
+    protected final byte[] buf;
+
+    /** Temporary read buffer. */
+    private byte[] rbuf = new byte[1];
+
+    /** Default compressor is used. */
+    private boolean usesDefaultDeflater = false;
+
+    /** End of the underlying input stream has been reached. */
+    private boolean reachEOF = false;
+
+    /**
+     * Check to make sure that this stream has not been closed.
+     */
+    private void ensureOpen() throws IOException {
+        if (in == null) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new input stream with a default compressor and buffer
+     * size.
+     *
+     * @param in input stream to read the uncompressed data to
+     * @throws NullPointerException if {@code in} is null
+     */
+    public DeflaterInputStream(InputStream in) {
+        this(in, new Deflater());
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Creates a new input stream with the specified compressor and a
+     * default buffer size.
+     *
+     * @param in input stream to read the uncompressed data to
+     * @param defl compressor ("deflater") for this stream
+     * @throws NullPointerException if {@code in} or {@code defl} is null
+     */
+    public DeflaterInputStream(InputStream in, Deflater defl) {
+        this(in, defl, 512);
+    }
+
+    /**
+     * Creates a new input stream with the specified compressor and buffer
+     * size.
+     *
+     * @param in input stream to read the uncompressed data to
+     * @param defl compressor ("deflater") for this stream
+     * @param bufLen compression buffer size
+     * @throws IllegalArgumentException if {@code bufLen <= 0}
+     * @throws NullPointerException if {@code in} or {@code defl} is null
+     */
+    public DeflaterInputStream(InputStream in, Deflater defl, int bufLen) {
+        super(in);
+
+        // Sanity checks
+        if (in == null)
+            throw new NullPointerException("Null input");
+        if (defl == null)
+            throw new NullPointerException("Null deflater");
+        if (bufLen < 1)
+            throw new IllegalArgumentException("Buffer size < 1");
+
+        // Initialize
+        def = defl;
+        buf = new byte[bufLen];
+    }
+
+    /**
+     * Closes this input stream and its underlying input stream, discarding
+     * any pending uncompressed data.
+     *
+     * @throws IOException if an I/O error occurs
+     */
+    public void close() throws IOException {
+        if (in != null) {
+            try {
+                // Clean up
+                if (usesDefaultDeflater) {
+                    def.end();
+                }
+
+                in.close();
+            } finally {
+                in = null;
+            }
+        }
+    }
+
+    /**
+     * Reads a single byte of compressed data from the input stream.
+     * This method will block until some input can be read and compressed.
+     *
+     * @return a single byte of compressed data, or -1 if the end of the
+     * uncompressed input stream is reached
+     * @throws IOException if an I/O error occurs or if this stream is
+     * already closed
+     */
+    public int read() throws IOException {
+        // Read a single byte of compressed data
+        int len = read(rbuf, 0, 1);
+        if (len <= 0)
+            return -1;
+        return (rbuf[0] & 0xFF);
+    }
+
+    /**
+     * Reads compressed data into a byte array.
+     * This method will block until some input can be read and compressed.
+     *
+     * @param b buffer into which the data is read
+     * @param off starting offset of the data within {@code b}
+     * @param len maximum number of compressed bytes to read into {@code b}
+     * @return the actual number of bytes read, or -1 if the end of the
+     * uncompressed input stream is reached
+     * @throws IndexOutOfBoundsException  if {@code len > b.length - off}
+     * @throws IOException if an I/O error occurs or if this input stream is
+     * already closed
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        // Sanity checks
+        ensureOpen();
+        if (b == null) {
+            throw new NullPointerException("Null buffer for read");
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        // Read and compress (deflate) input data bytes
+        int cnt = 0;
+        while (len > 0 && !def.finished()) {
+            int n;
+
+            // Read data from the input stream
+            if (def.needsInput()) {
+                n = in.read(buf, 0, buf.length);
+                if (n < 0) {
+                    // End of the input stream reached
+                    def.finish();
+                } else if (n > 0) {
+                    def.setInput(buf, 0, n);
+                }
+            }
+
+            // Compress the input data, filling the read buffer
+            n = def.deflate(b, off, len);
+            cnt += n;
+            off += n;
+            len -= n;
+        }
+        // BEGIN Android-changed: Return more accurate value from available().
+        // Set reachEOF eagerly when the Deflater has finished, and not just when the number of
+        // bytes is zero so that available is more accurate.
+        // See http://b/111589691
+        /*
+        if (cnt == 0 && def.finished()) {
+            reachEOF = true;
+            cnt = -1;
+        }
+        */
+        if (def.finished()) {
+            reachEOF = true;
+            if (cnt == 0) {
+                cnt = -1;
+            }
+        }
+        // END Android-changed: Return more accurate value from available().
+
+        return cnt;
+    }
+
+    /**
+     * Skips over and discards data from the input stream.
+     * This method may block until the specified number of bytes are read and
+     * skipped. <em>Note:</em> While {@code n} is given as a {@code long},
+     * the maximum number of bytes which can be skipped is
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @param n number of bytes to be skipped
+     * @return the actual number of bytes skipped
+     * @throws IOException if an I/O error occurs or if this stream is
+     * already closed
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0) {
+            throw new IllegalArgumentException("negative skip length");
+        }
+        ensureOpen();
+
+        // Skip bytes by repeatedly decompressing small blocks
+        if (rbuf.length < 512)
+            rbuf = new byte[512];
+
+        int total = (int)Math.min(n, Integer.MAX_VALUE);
+        long cnt = 0;
+        while (total > 0) {
+            // Read a small block of uncompressed bytes
+            int len = read(rbuf, 0, (total <= rbuf.length ? total : rbuf.length));
+
+            if (len < 0) {
+                break;
+            }
+            cnt += len;
+            total -= len;
+        }
+        return cnt;
+    }
+
+    /**
+     * Returns 0 after EOF has been reached, otherwise always return 1.
+     * <p>
+     * Programs should not count on this method to return the actual number
+     * of bytes that could be read without blocking
+     * @return zero after the end of the underlying input stream has been
+     * reached, otherwise always returns 1
+     * @throws IOException if an I/O error occurs or if this stream is
+     * already closed
+     */
+    public int available() throws IOException {
+        ensureOpen();
+        if (reachEOF) {
+            return 0;
+        }
+        return 1;
+    }
+
+    /**
+     * Always returns {@code false} because this input stream does not support
+     * the {@link #mark mark()} and {@link #reset reset()} methods.
+     *
+     * @return false, always
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * <i>This operation is not supported</i>.
+     *
+     * @param limit maximum bytes that can be read before invalidating the position marker
+     */
+    public void mark(int limit) {
+        // Operation not supported
+    }
+
+    /**
+     * <i>This operation is not supported</i>.
+     *
+     * @throws IOException always thrown
+     */
+    public void reset() throws IOException {
+        throw new IOException("mark/reset not supported");
+    }
+}
diff --git a/java/util/zip/DeflaterOutputStream.java b/java/util/zip/DeflaterOutputStream.java
new file mode 100644
index 0000000..7821737
--- /dev/null
+++ b/java/util/zip/DeflaterOutputStream.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterOutputStream;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This class implements an output stream filter for compressing data in
+ * the "deflate" compression format. It is also used as the basis for other
+ * types of compression filters, such as GZIPOutputStream.
+ *
+ * @see         Deflater
+ * @author      David Connelly
+ */
+public
+class DeflaterOutputStream extends FilterOutputStream {
+    /**
+     * Compressor for this stream.
+     */
+    protected Deflater def;
+
+    /**
+     * Output buffer for writing compressed data.
+     */
+    protected byte[] buf;
+
+    /**
+     * Indicates that the stream has been closed.
+     */
+
+    private boolean closed = false;
+
+    private final boolean syncFlush;
+
+    /**
+     * Creates a new output stream with the specified compressor,
+     * buffer size and flush mode.
+
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     * @param size the output buffer size
+     * @param syncFlush
+     *        if {@code true} the {@link #flush()} method of this
+     *        instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @throws IllegalArgumentException if {@code size <= 0}
+     *
+     * @since 1.7
+     */
+    public DeflaterOutputStream(OutputStream out,
+                                Deflater def,
+                                int size,
+                                boolean syncFlush) {
+        super(out);
+        if (out == null || def == null) {
+            throw new NullPointerException();
+        } else if (size <= 0) {
+            throw new IllegalArgumentException("buffer size <= 0");
+        }
+        this.def = def;
+        this.buf = new byte[size];
+        this.syncFlush = syncFlush;
+    }
+
+
+    /**
+     * Creates a new output stream with the specified compressor and
+     * buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 4-argument constructor DeflaterOutputStream(out, def, size, false).
+     *
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     * @param size the output buffer size
+     * @exception IllegalArgumentException if {@code size <= 0}
+     */
+    public DeflaterOutputStream(OutputStream out, Deflater def, int size) {
+        this(out, def, size, false);
+    }
+
+    /**
+     * Creates a new output stream with the specified compressor, flush
+     * mode and a default buffer size.
+     *
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     * @param syncFlush
+     *        if {@code true} the {@link #flush()} method of this
+     *        instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @since 1.7
+     */
+    public DeflaterOutputStream(OutputStream out,
+                                Deflater def,
+                                boolean syncFlush) {
+        this(out, def, 512, syncFlush);
+    }
+
+
+    /**
+     * Creates a new output stream with the specified compressor and
+     * a default buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 3-argument constructor DeflaterOutputStream(out, def, false).
+     *
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     */
+    public DeflaterOutputStream(OutputStream out, Deflater def) {
+        this(out, def, 512, false);
+    }
+
+    boolean usesDefaultDeflater = false;
+
+
+    /**
+     * Creates a new output stream with a default compressor, a default
+     * buffer size and the specified flush mode.
+     *
+     * @param out the output stream
+     * @param syncFlush
+     *        if {@code true} the {@link #flush()} method of this
+     *        instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @since 1.7
+     */
+    public DeflaterOutputStream(OutputStream out, boolean syncFlush) {
+        this(out, new Deflater(), 512, syncFlush);
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Creates a new output stream with a default compressor and buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 2-argument constructor DeflaterOutputStream(out, false).
+     *
+     * @param out the output stream
+     */
+    public DeflaterOutputStream(OutputStream out) {
+        this(out, false);
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Writes a byte to the compressed output stream. This method will
+     * block until the byte can be written.
+     * @param b the byte to be written
+     * @exception IOException if an I/O error has occurred
+     */
+    public void write(int b) throws IOException {
+        byte[] buf = new byte[1];
+        buf[0] = (byte)(b & 0xff);
+        write(buf, 0, 1);
+    }
+
+    /**
+     * Writes an array of bytes to the compressed output stream. This
+     * method will block until all the bytes are written.
+     * @param b the data to be written
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @exception IOException if an I/O error has occurred
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        if (def.finished()) {
+            throw new IOException("write beyond end of stream");
+        }
+        if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+        if (!def.finished()) {
+            def.setInput(b, off, len);
+            while (!def.needsInput()) {
+                deflate();
+            }
+        }
+    }
+
+    /**
+     * Finishes writing compressed data to the output stream without closing
+     * the underlying stream. Use this method when applying multiple filters
+     * in succession to the same output stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void finish() throws IOException {
+        if (!def.finished()) {
+            def.finish();
+            while (!def.finished()) {
+                deflate();
+            }
+        }
+    }
+
+    /**
+     * Writes remaining compressed data to the output stream and closes the
+     * underlying stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            finish();
+            if (usesDefaultDeflater)
+                def.end();
+            out.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Writes next block of compressed data to the output stream.
+     * @throws IOException if an I/O error has occurred
+     */
+    protected void deflate() throws IOException {
+        // Android-changed: Output all available compressed data (b/4005091).
+        // See http://b/111496419 for more details.
+        // int len = def.deflate(buf, 0, buf.length);
+        // if (len > 0) {
+        //     out.write(buf, 0, len);
+        // }
+        int len = 0;
+        while ((len = def.deflate(buf, 0, buf.length)) > 0) {
+          out.write(buf, 0, len);
+        }
+    }
+
+    /**
+     * Flushes the compressed output stream.
+     *
+     * If {@link #DeflaterOutputStream(OutputStream, Deflater, int, boolean)
+     * syncFlush} is {@code true} when this compressed output stream is
+     * constructed, this method first flushes the underlying {@code compressor}
+     * with the flush mode {@link Deflater#SYNC_FLUSH} to force
+     * all pending data to be flushed out to the output stream and then
+     * flushes the output stream. Otherwise this method only flushes the
+     * output stream without flushing the {@code compressor}.
+     *
+     * @throws IOException if an I/O error has occurred
+     *
+     * @since 1.7
+     */
+    public void flush() throws IOException {
+        if (syncFlush && !def.finished()) {
+            int len = 0;
+            while ((len = def.deflate(buf, 0, buf.length, Deflater.SYNC_FLUSH)) > 0)
+            {
+                out.write(buf, 0, len);
+                if (len < buf.length)
+                    break;
+            }
+        }
+        out.flush();
+    }
+}
diff --git a/java/util/zip/GZIPInputStream.java b/java/util/zip/GZIPInputStream.java
new file mode 100644
index 0000000..109454c
--- /dev/null
+++ b/java/util/zip/GZIPInputStream.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.SequenceInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+
+/**
+ * This class implements a stream filter for reading compressed data in
+ * the GZIP file format.
+ *
+ * @see         InflaterInputStream
+ * @author      David Connelly
+ *
+ */
+public
+class GZIPInputStream extends InflaterInputStream {
+    /**
+     * CRC-32 for uncompressed data.
+     */
+    protected CRC32 crc = new CRC32();
+
+    /**
+     * Indicates end of input stream.
+     */
+    protected boolean eos;
+
+    private boolean closed = false;
+
+    /**
+     * Check to make sure that this stream has not been closed
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new input stream with the specified buffer size.
+     * @param in the input stream
+     * @param size the input buffer size
+     *
+     * @exception ZipException if a GZIP format error has occurred or the
+     *                         compression method used is unsupported
+     * @exception IOException if an I/O error has occurred
+     * @exception IllegalArgumentException if {@code size <= 0}
+     */
+    public GZIPInputStream(InputStream in, int size) throws IOException {
+        super(in, new Inflater(true), size);
+        // Android-removed: Unconditionally close external inflaters (b/26462400)
+        // usesDefaultInflater = true;
+        // BEGIN Android-changed: Do not rely on finalization to inf.end().
+        // readHeader(in);
+        try {
+            readHeader(in);
+        } catch (Exception e) {
+            inf.end();
+            throw e;
+        }
+        // END Android-changed: Do not rely on finalization to inf.end().
+    }
+
+    /**
+     * Creates a new input stream with a default buffer size.
+     * @param in the input stream
+     *
+     * @exception ZipException if a GZIP format error has occurred or the
+     *                         compression method used is unsupported
+     * @exception IOException if an I/O error has occurred
+     */
+    public GZIPInputStream(InputStream in) throws IOException {
+        this(in, 512);
+    }
+
+    /**
+     * Reads uncompressed data into an array of bytes. If <code>len</code> is not
+     * zero, the method will block until some input can be decompressed; otherwise,
+     * no bytes are read and <code>0</code> is returned.
+     * @param buf the buffer into which the data is read
+     * @param off the start offset in the destination array <code>b</code>
+     * @param len the maximum number of bytes read
+     * @return  the actual number of bytes read, or -1 if the end of the
+     *          compressed input stream is reached
+     *
+     * @exception  NullPointerException If <code>buf</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>buf.length - off</code>
+     * @exception ZipException if the compressed input data is corrupt.
+     * @exception IOException if an I/O error has occurred.
+     *
+     */
+    public int read(byte[] buf, int off, int len) throws IOException {
+        ensureOpen();
+        if (eos) {
+            return -1;
+        }
+        int n = super.read(buf, off, len);
+        if (n == -1) {
+            if (readTrailer())
+                eos = true;
+            else
+                return this.read(buf, off, len);
+        } else {
+            crc.update(buf, off, n);
+        }
+        return n;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources associated
+     * with the stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            super.close();
+            eos = true;
+            closed = true;
+        }
+    }
+
+    /**
+     * GZIP header magic number.
+     */
+    public final static int GZIP_MAGIC = 0x8b1f;
+
+    /*
+     * File header flags.
+     */
+    private final static int FTEXT      = 1;    // Extra text
+    private final static int FHCRC      = 2;    // Header CRC
+    private final static int FEXTRA     = 4;    // Extra field
+    private final static int FNAME      = 8;    // File name
+    private final static int FCOMMENT   = 16;   // File comment
+
+    /*
+     * Reads GZIP member header and returns the total byte number
+     * of this member header.
+     */
+    private int readHeader(InputStream this_in) throws IOException {
+        CheckedInputStream in = new CheckedInputStream(this_in, crc);
+        crc.reset();
+        // Check header magic
+        if (readUShort(in) != GZIP_MAGIC) {
+            throw new ZipException("Not in GZIP format");
+        }
+        // Check compression method
+        if (readUByte(in) != 8) {
+            throw new ZipException("Unsupported compression method");
+        }
+        // Read flags
+        int flg = readUByte(in);
+        // Skip MTIME, XFL, and OS fields
+        skipBytes(in, 6);
+        int n = 2 + 2 + 6;
+        // Skip optional extra field
+        if ((flg & FEXTRA) == FEXTRA) {
+            int m = readUShort(in);
+            skipBytes(in, m);
+            n += m + 2;
+        }
+        // Skip optional file name
+        if ((flg & FNAME) == FNAME) {
+            do {
+                n++;
+            } while (readUByte(in) != 0);
+        }
+        // Skip optional file comment
+        if ((flg & FCOMMENT) == FCOMMENT) {
+            do {
+                n++;
+            } while (readUByte(in) != 0);
+        }
+        // Check optional header CRC
+        if ((flg & FHCRC) == FHCRC) {
+            int v = (int)crc.getValue() & 0xffff;
+            if (readUShort(in) != v) {
+                throw new ZipException("Corrupt GZIP header");
+            }
+            n += 2;
+        }
+        crc.reset();
+        return n;
+    }
+
+    /*
+     * Reads GZIP member trailer and returns true if the eos
+     * reached, false if there are more (concatenated gzip
+     * data set)
+     */
+    private boolean readTrailer() throws IOException {
+        InputStream in = this.in;
+        int n = inf.getRemaining();
+        if (n > 0) {
+            in = new SequenceInputStream(
+                        new ByteArrayInputStream(buf, len - n, n),
+                        new FilterInputStream(in) {
+                            public void close() throws IOException {}
+                        });
+        }
+        // Uses left-to-right evaluation order
+        if ((readUInt(in) != crc.getValue()) ||
+            // rfc1952; ISIZE is the input size modulo 2^32
+            (readUInt(in) != (inf.getBytesWritten() & 0xffffffffL)))
+            throw new ZipException("Corrupt GZIP trailer");
+
+        // If there are more bytes available in "in" or
+        // the leftover in the "inf" is > 26 bytes:
+        // this.trailer(8) + next.header.min(10) + next.trailer(8)
+        // try concatenated case
+        if (this.in.available() > 0 || n > 26) {
+            int m = 8;                  // this.trailer
+            try {
+                m += readHeader(in);    // next.header
+            } catch (IOException ze) {
+                return true;  // ignore any malformed, do nothing
+            }
+            inf.reset();
+            if (n > m)
+                inf.setInput(buf, len - n + m, n - m);
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * Reads unsigned integer in Intel byte order.
+     */
+    private long readUInt(InputStream in) throws IOException {
+        long s = readUShort(in);
+        return ((long)readUShort(in) << 16) | s;
+    }
+
+    /*
+     * Reads unsigned short in Intel byte order.
+     */
+    private int readUShort(InputStream in) throws IOException {
+        int b = readUByte(in);
+        return (readUByte(in) << 8) | b;
+    }
+
+    /*
+     * Reads unsigned byte.
+     */
+    private int readUByte(InputStream in) throws IOException {
+        int b = in.read();
+        if (b == -1) {
+            throw new EOFException();
+        }
+        if (b < -1 || b > 255) {
+            // Report on this.in, not argument in; see read{Header, Trailer}.
+            throw new IOException(this.in.getClass().getName()
+                + ".read() returned value out of range -1..255: " + b);
+        }
+        return b;
+    }
+
+    private byte[] tmpbuf = new byte[128];
+
+    /*
+     * Skips bytes of input data blocking until all bytes are skipped.
+     * Does not assume that the input stream is capable of seeking.
+     */
+    private void skipBytes(InputStream in, int n) throws IOException {
+        while (n > 0) {
+            int len = in.read(tmpbuf, 0, n < tmpbuf.length ? n : tmpbuf.length);
+            if (len == -1) {
+                throw new EOFException();
+            }
+            n -= len;
+        }
+    }
+}
diff --git a/java/util/zip/GZIPOutputStream.java b/java/util/zip/GZIPOutputStream.java
new file mode 100644
index 0000000..2c1cd40
--- /dev/null
+++ b/java/util/zip/GZIPOutputStream.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * This class implements a stream filter for writing compressed data in
+ * the GZIP file format.
+ * @author      David Connelly
+ *
+ */
+public
+class GZIPOutputStream extends DeflaterOutputStream {
+    /**
+     * CRC-32 of uncompressed data.
+     */
+    protected CRC32 crc = new CRC32();
+
+    /*
+     * GZIP header magic number.
+     */
+    private final static int GZIP_MAGIC = 0x8b1f;
+
+    /*
+     * Trailer size in bytes.
+     *
+     */
+    private final static int TRAILER_SIZE = 8;
+
+    /**
+     * Creates a new output stream with the specified buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 3-argument constructor GZIPOutputStream(out, size, false).
+     *
+     * @param out the output stream
+     * @param size the output buffer size
+     * @exception IOException If an I/O error has occurred.
+     * @exception IllegalArgumentException if {@code size <= 0}
+     */
+    public GZIPOutputStream(OutputStream out, int size) throws IOException {
+        this(out, size, false);
+    }
+
+    /**
+     * Creates a new output stream with the specified buffer size and
+     * flush mode.
+     *
+     * @param out the output stream
+     * @param size the output buffer size
+     * @param syncFlush
+     *        if {@code true} invocation of the inherited
+     *        {@link DeflaterOutputStream#flush() flush()} method of
+     *        this instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     * @exception IOException If an I/O error has occurred.
+     * @exception IllegalArgumentException if {@code size <= 0}
+     *
+     * @since 1.7
+     */
+    public GZIPOutputStream(OutputStream out, int size, boolean syncFlush)
+        throws IOException
+    {
+        super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true),
+              size,
+              syncFlush);
+        usesDefaultDeflater = true;
+        writeHeader();
+        crc.reset();
+    }
+
+
+    /**
+     * Creates a new output stream with a default buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 2-argument constructor GZIPOutputStream(out, false).
+     *
+     * @param out the output stream
+     * @exception IOException If an I/O error has occurred.
+     */
+    public GZIPOutputStream(OutputStream out) throws IOException {
+        this(out, 512, false);
+    }
+
+    /**
+     * Creates a new output stream with a default buffer size and
+     * the specified flush mode.
+     *
+     * @param out the output stream
+     * @param syncFlush
+     *        if {@code true} invocation of the inherited
+     *        {@link DeflaterOutputStream#flush() flush()} method of
+     *        this instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @exception IOException If an I/O error has occurred.
+     *
+     * @since 1.7
+     */
+    public GZIPOutputStream(OutputStream out, boolean syncFlush)
+        throws IOException
+    {
+        this(out, 512, syncFlush);
+    }
+
+    /**
+     * Writes array of bytes to the compressed output stream. This method
+     * will block until all the bytes are written.
+     * @param buf the data to be written
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @exception IOException If an I/O error has occurred.
+     */
+    public synchronized void write(byte[] buf, int off, int len)
+        throws IOException
+    {
+        super.write(buf, off, len);
+        crc.update(buf, off, len);
+    }
+
+    /**
+     * Finishes writing compressed data to the output stream without closing
+     * the underlying stream. Use this method when applying multiple filters
+     * in succession to the same output stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void finish() throws IOException {
+        if (!def.finished()) {
+            def.finish();
+            while (!def.finished()) {
+                int len = def.deflate(buf, 0, buf.length);
+                if (def.finished() && len <= buf.length - TRAILER_SIZE) {
+                    // last deflater buffer. Fit trailer at the end
+                    writeTrailer(buf, len);
+                    len = len + TRAILER_SIZE;
+                    out.write(buf, 0, len);
+                    return;
+                }
+                if (len > 0)
+                    out.write(buf, 0, len);
+            }
+            // if we can't fit the trailer at the end of the last
+            // deflater buffer, we write it separately
+            byte[] trailer = new byte[TRAILER_SIZE];
+            writeTrailer(trailer, 0);
+            out.write(trailer);
+        }
+    }
+
+    /*
+     * Writes GZIP member header.
+     */
+    private void writeHeader() throws IOException {
+        out.write(new byte[] {
+                      (byte) GZIP_MAGIC,        // Magic number (short)
+                      (byte)(GZIP_MAGIC >> 8),  // Magic number (short)
+                      Deflater.DEFLATED,        // Compression method (CM)
+                      0,                        // Flags (FLG)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Extra flags (XFLG)
+                      0                         // Operating system (OS)
+                  });
+    }
+
+    /*
+     * Writes GZIP member trailer to a byte array, starting at a given
+     * offset.
+     */
+    private void writeTrailer(byte[] buf, int offset) throws IOException {
+        writeInt((int)crc.getValue(), buf, offset); // CRC-32 of uncompr. data
+        writeInt(def.getTotalIn(), buf, offset + 4); // Number of uncompr. bytes
+    }
+
+    /*
+     * Writes integer in Intel byte order to a byte array, starting at a
+     * given offset.
+     */
+    private void writeInt(int i, byte[] buf, int offset) throws IOException {
+        writeShort(i & 0xffff, buf, offset);
+        writeShort((i >> 16) & 0xffff, buf, offset + 2);
+    }
+
+    /*
+     * Writes short integer in Intel byte order to a byte array, starting
+     * at a given offset
+     */
+    private void writeShort(int s, byte[] buf, int offset) throws IOException {
+        buf[offset] = (byte)(s & 0xff);
+        buf[offset + 1] = (byte)((s >> 8) & 0xff);
+    }
+}
diff --git a/java/util/zip/Inflater.java b/java/util/zip/Inflater.java
new file mode 100644
index 0000000..eb8754e
--- /dev/null
+++ b/java/util/zip/Inflater.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.CloseGuard;
+
+/**
+ * This class provides support for general purpose decompression using the
+ * popular ZLIB compression library. The ZLIB compression library was
+ * initially developed as part of the PNG graphics standard and is not
+ * protected by patents. It is fully described in the specifications at
+ * the <a href="package-summary.html#package_description">java.util.zip
+ * package description</a>.
+ *
+ * <p>The following code fragment demonstrates a trivial compression
+ * and decompression of a string using <tt>Deflater</tt> and
+ * <tt>Inflater</tt>.
+ *
+ * <blockquote><pre>
+ * try {
+ *     // Encode a String into bytes
+ *     String inputString = "blahblahblah\u20AC\u20AC";
+ *     byte[] input = inputString.getBytes("UTF-8");
+ *
+ *     // Compress the bytes
+ *     byte[] output = new byte[100];
+ *     Deflater compresser = new Deflater();
+ *     compresser.setInput(input);
+ *     compresser.finish();
+ *     int compressedDataLength = compresser.deflate(output);
+ *
+ *     // Decompress the bytes
+ *     Inflater decompresser = new Inflater();
+ *     decompresser.setInput(output, 0, compressedDataLength);
+ *     byte[] result = new byte[100];
+ *     int resultLength = decompresser.inflate(result);
+ *     decompresser.end();
+ *
+ *     // Decode the bytes into a String
+ *     String outputString = new String(result, 0, resultLength, "UTF-8");
+ * } catch(java.io.UnsupportedEncodingException ex) {
+ *     // handle
+ * } catch (java.util.zip.DataFormatException ex) {
+ *     // handle
+ * }
+ * </pre></blockquote>
+ *
+ * @see         Deflater
+ * @author      David Connelly
+ *
+ */
+public
+class Inflater {
+
+    // Android-added: @ReachabilitySensitive
+    // Finalization clears zsRef, and thus can't be allowed to occur early.
+    // Unlike some other CloseGuard uses, the spec allows clients to rely on finalization
+    // here.  Thus dropping a deflater without calling end() should work correctly.
+    // It thus does not suffice to just rely on the CloseGuard annotation.
+    @ReachabilitySensitive
+    private final ZStreamRef zsRef;
+    private byte[] buf = defaultBuf;
+    private int off, len;
+    private boolean finished;
+    private boolean needDict;
+    private long bytesRead;
+    private long bytesWritten;
+
+    // Android-added: CloseGuard support.
+    @ReachabilitySensitive
+    private final CloseGuard guard = CloseGuard.get();
+
+    private static final byte[] defaultBuf = new byte[0];
+
+    // Android-removed: initIDs handled in register method.
+    /*
+    static {
+        /* Zip library is loaded from System.initializeSystemClass *
+        initIDs();
+    }
+    */
+
+    /**
+     * Creates a new decompressor. If the parameter 'nowrap' is true then
+     * the ZLIB header and checksum fields will not be used. This provides
+     * compatibility with the compression format used by both GZIP and PKZIP.
+     * <p>
+     * Note: When using the 'nowrap' option it is also necessary to provide
+     * an extra "dummy" byte as input. This is required by the ZLIB native
+     * library in order to support certain optimizations.
+     *
+     * @param nowrap if true then support GZIP compatible compression
+     */
+    public Inflater(boolean nowrap) {
+        zsRef = new ZStreamRef(init(nowrap));
+        // Android-added: CloseGuard support.
+        guard.open("end");
+    }
+
+    /**
+     * Creates a new decompressor.
+     */
+    public Inflater() {
+        this(false);
+    }
+
+    /**
+     * Sets input data for decompression. Should be called whenever
+     * needsInput() returns true indicating that more input data is
+     * required.
+     * @param b the input data bytes
+     * @param off the start offset of the input data
+     * @param len the length of the input data
+     * @see Inflater#needsInput
+     */
+    public void setInput(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            this.buf = b;
+            this.off = off;
+            this.len = len;
+        }
+    }
+
+    /**
+     * Sets input data for decompression. Should be called whenever
+     * needsInput() returns true indicating that more input data is
+     * required.
+     * @param b the input data bytes
+     * @see Inflater#needsInput
+     */
+    public void setInput(byte[] b) {
+        setInput(b, 0, b.length);
+    }
+
+    /**
+     * Sets the preset dictionary to the given array of bytes. Should be
+     * called when inflate() returns 0 and needsDictionary() returns true
+     * indicating that a preset dictionary is required. The method getAdler()
+     * can be used to get the Adler-32 value of the dictionary needed.
+     * @param b the dictionary data bytes
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @see Inflater#needsDictionary
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            setDictionary(zsRef.address(), b, off, len);
+            needDict = false;
+        }
+    }
+
+    /**
+     * Sets the preset dictionary to the given array of bytes. Should be
+     * called when inflate() returns 0 and needsDictionary() returns true
+     * indicating that a preset dictionary is required. The method getAdler()
+     * can be used to get the Adler-32 value of the dictionary needed.
+     * @param b the dictionary data bytes
+     * @see Inflater#needsDictionary
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] b) {
+        setDictionary(b, 0, b.length);
+    }
+
+    /**
+     * Returns the total number of bytes remaining in the input buffer.
+     * This can be used to find out what bytes still remain in the input
+     * buffer after decompression has finished.
+     * @return the total number of bytes remaining in the input buffer
+     */
+    public int getRemaining() {
+        synchronized (zsRef) {
+            return len;
+        }
+    }
+
+    /**
+     * Returns true if no data remains in the input buffer. This can
+     * be used to determine if #setInput should be called in order
+     * to provide more input.
+     * @return true if no data remains in the input buffer
+     */
+    public boolean needsInput() {
+        synchronized (zsRef) {
+            return len <= 0;
+        }
+    }
+
+    /**
+     * Returns true if a preset dictionary is needed for decompression.
+     * @return true if a preset dictionary is needed for decompression
+     * @see Inflater#setDictionary
+     */
+    public boolean needsDictionary() {
+        synchronized (zsRef) {
+            return needDict;
+        }
+    }
+
+    /**
+     * Returns true if the end of the compressed data stream has been
+     * reached.
+     * @return true if the end of the compressed data stream has been
+     * reached
+     */
+    public boolean finished() {
+        synchronized (zsRef) {
+            return finished;
+        }
+    }
+
+    /**
+     * Uncompresses bytes into specified buffer. Returns actual number
+     * of bytes uncompressed. A return value of 0 indicates that
+     * needsInput() or needsDictionary() should be called in order to
+     * determine if more input data or a preset dictionary is required.
+     * In the latter case, getAdler() can be used to get the Adler-32
+     * value of the dictionary required.
+     * @param b the buffer for the uncompressed data
+     * @param off the start offset of the data
+     * @param len the maximum number of uncompressed bytes
+     * @return the actual number of uncompressed bytes
+     * @exception DataFormatException if the compressed data format is invalid
+     * @see Inflater#needsInput
+     * @see Inflater#needsDictionary
+     */
+    public int inflate(byte[] b, int off, int len)
+        throws DataFormatException
+    {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            int thisLen = this.len;
+            int n = inflateBytes(zsRef.address(), b, off, len);
+            bytesWritten += n;
+            bytesRead += (thisLen - this.len);
+            return n;
+        }
+    }
+
+    /**
+     * Uncompresses bytes into specified buffer. Returns actual number
+     * of bytes uncompressed. A return value of 0 indicates that
+     * needsInput() or needsDictionary() should be called in order to
+     * determine if more input data or a preset dictionary is required.
+     * In the latter case, getAdler() can be used to get the Adler-32
+     * value of the dictionary required.
+     * @param b the buffer for the uncompressed data
+     * @return the actual number of uncompressed bytes
+     * @exception DataFormatException if the compressed data format is invalid
+     * @see Inflater#needsInput
+     * @see Inflater#needsDictionary
+     */
+    public int inflate(byte[] b) throws DataFormatException {
+        return inflate(b, 0, b.length);
+    }
+
+    /**
+     * Returns the ADLER-32 value of the uncompressed data.
+     * @return the ADLER-32 value of the uncompressed data
+     */
+    public int getAdler() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return getAdler(zsRef.address());
+        }
+    }
+
+    /**
+     * Returns the total number of compressed bytes input so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of compressed bytes input so far
+     */
+    public int getTotalIn() {
+        return (int) getBytesRead();
+    }
+
+    /**
+     * Returns the total number of compressed bytes input so far.
+     *
+     * @return the total (non-negative) number of compressed bytes input so far
+     * @since 1.5
+     */
+    public long getBytesRead() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesRead;
+        }
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes output so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of uncompressed bytes output so far
+     */
+    public int getTotalOut() {
+        return (int) getBytesWritten();
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes output so far.
+     *
+     * @return the total (non-negative) number of uncompressed bytes output so far
+     * @since 1.5
+     */
+    public long getBytesWritten() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesWritten;
+        }
+    }
+
+    /**
+     * Resets inflater so that a new set of input data can be processed.
+     */
+    public void reset() {
+        synchronized (zsRef) {
+            ensureOpen();
+            reset(zsRef.address());
+            buf = defaultBuf;
+            finished = false;
+            needDict = false;
+            off = len = 0;
+            bytesRead = bytesWritten = 0;
+        }
+    }
+
+    /**
+     * Closes the decompressor and discards any unprocessed input.
+     * This method should be called when the decompressor is no longer
+     * being used, but will also be called automatically by the finalize()
+     * method. Once this method is called, the behavior of the Inflater
+     * object is undefined.
+     */
+    public void end() {
+        synchronized (zsRef) {
+            // Android-added: CloseGuard support.
+            guard.close();
+
+            long addr = zsRef.address();
+            zsRef.clear();
+            if (addr != 0) {
+                end(addr);
+                buf = null;
+            }
+        }
+    }
+
+    /**
+     * Closes the decompressor when garbage is collected.
+     */
+    protected void finalize() {
+        // Android-added: CloseGuard support.
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+
+        end();
+    }
+
+    private void ensureOpen () {
+        assert Thread.holdsLock(zsRef);
+        if (zsRef.address() == 0)
+            throw new NullPointerException("Inflater has been closed");
+    }
+
+    boolean ended() {
+        synchronized (zsRef) {
+            return zsRef.address() == 0;
+        }
+    }
+
+    // Android-changed: initIDs handled in register method.
+    // private native static void initIDs();
+    private native static long init(boolean nowrap);
+    private native static void setDictionary(long addr, byte[] b, int off,
+                                             int len);
+    private native int inflateBytes(long addr, byte[] b, int off, int len)
+            throws DataFormatException;
+    private native static int getAdler(long addr);
+    private native static void reset(long addr);
+    private native static void end(long addr);
+}
diff --git a/java/util/zip/InflaterInputStream.java b/java/util/zip/InflaterInputStream.java
new file mode 100644
index 0000000..b65adbe
--- /dev/null
+++ b/java/util/zip/InflaterInputStream.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+
+/**
+ * This class implements a stream filter for uncompressing data in the
+ * "deflate" compression format. It is also used as the basis for other
+ * decompression filters, such as GZIPInputStream.
+ *
+ * @see         Inflater
+ * @author      David Connelly
+ */
+public
+class InflaterInputStream extends FilterInputStream {
+    /**
+     * Decompressor for this stream.
+     */
+    protected Inflater inf;
+
+    /**
+     * Input buffer for decompression.
+     */
+    protected byte[] buf;
+
+    /**
+     * Length of input buffer.
+     */
+    protected int len;
+
+    // Android-changed: Make closed accessible to subclasses.
+    // This was made protected because it needed to be accessed by
+    // StrictJarFile.ZipInflaterInputStream. Unfortunately, it was not marked as @hide and so it
+    // inadvertently became part of the public API. It will be marked as @removed to remove it from
+    // the public API in a future release of Android. See http://b/111592689 for more information.
+    // private boolean closed = false;
+    /**
+     * Indicates whether the {@link #close()} method has been called, internal use only.
+     *
+     * @deprecated This field will be removed from a future version of Android and should not be
+     * used. Subclasses that access this field need to be modified to keep track of their own
+     * closed state by overriding close().
+     */
+    @Deprecated
+    protected boolean closed = false;
+
+    // this flag is set to true after EOF has reached
+    private boolean reachEOF = false;
+
+    /**
+     * Check to make sure that this stream has not been closed
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+
+    /**
+     * Creates a new input stream with the specified decompressor and
+     * buffer size.
+     * @param in the input stream
+     * @param inf the decompressor ("inflater")
+     * @param size the input buffer size
+     * @exception IllegalArgumentException if {@code size <= 0}
+     */
+    public InflaterInputStream(InputStream in, Inflater inf, int size) {
+        super(in);
+        if (in == null || inf == null) {
+            throw new NullPointerException();
+        } else if (size <= 0) {
+            throw new IllegalArgumentException("buffer size <= 0");
+        }
+        this.inf = inf;
+        buf = new byte[size];
+    }
+
+    /**
+     * Creates a new input stream with the specified decompressor and a
+     * default buffer size.
+     * @param in the input stream
+     * @param inf the decompressor ("inflater")
+     */
+    public InflaterInputStream(InputStream in, Inflater inf) {
+        this(in, inf, 512);
+    }
+
+    // Android-changed: Unconditionally close external inflaters (b/26462400)
+    // See http://b/111630946 for more details.
+    // boolean usesDefaultInflater = false;
+
+    /**
+     * Creates a new input stream with a default decompressor and buffer size.
+     * @param in the input stream
+     */
+    public InflaterInputStream(InputStream in) {
+        this(in, new Inflater());
+        // Android-changed: Unconditionally close external inflaters (b/26462400)
+        // usesDefaultInflater = true;
+    }
+
+    private byte[] singleByteBuf = new byte[1];
+
+    /**
+     * Reads a byte of uncompressed data. This method will block until
+     * enough input is available for decompression.
+     * @return the byte read, or -1 if end of compressed input is reached
+     * @exception IOException if an I/O error has occurred
+     */
+    public int read() throws IOException {
+        ensureOpen();
+        return read(singleByteBuf, 0, 1) == -1 ? -1 : Byte.toUnsignedInt(singleByteBuf[0]);
+    }
+
+    /**
+     * Reads uncompressed data into an array of bytes. If <code>len</code> is not
+     * zero, the method will block until some input can be decompressed; otherwise,
+     * no bytes are read and <code>0</code> is returned.
+     * @param b the buffer into which the data is read
+     * @param off the start offset in the destination array <code>b</code>
+     * @param len the maximum number of bytes read
+     * @return the actual number of bytes read, or -1 if the end of the
+     *         compressed input is reached or a preset dictionary is needed
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception ZipException if a ZIP format error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        ensureOpen();
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+        try {
+            int n;
+            while ((n = inf.inflate(b, off, len)) == 0) {
+                if (inf.finished() || inf.needsDictionary()) {
+                    reachEOF = true;
+                    return -1;
+                }
+                if (inf.needsInput()) {
+                    fill();
+                }
+            }
+            return n;
+        } catch (DataFormatException e) {
+            String s = e.getMessage();
+            throw new ZipException(s != null ? s : "Invalid ZLIB data format");
+        }
+    }
+
+    /**
+     * Returns 0 after EOF has been reached, otherwise always return 1.
+     * <p>
+     * Programs should not count on this method to return the actual number
+     * of bytes that could be read without blocking.
+     *
+     * @return     1 before EOF and 0 after EOF.
+     * @exception  IOException  if an I/O error occurs.
+     *
+     */
+    public int available() throws IOException {
+        ensureOpen();
+        if (reachEOF) {
+            return 0;
+        // BEGIN Android-added: Return more accurate value from available().
+        // Integrates change http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/dbcf47bfb044 made as part
+        // of https://bugs.openjdk.java.net/browse/JDK-7031075.
+        } else if (inf.finished()) {
+            // the end of the compressed data stream has been reached
+            reachEOF = true;
+            return 0;
+        // END Android-added: Return more accurate value from available().
+        } else {
+            return 1;
+        }
+    }
+
+    private byte[] b = new byte[512];
+
+    /**
+     * Skips specified number of bytes of uncompressed data.
+     * @param n the number of bytes to skip
+     * @return the actual number of bytes skipped.
+     * @exception IOException if an I/O error has occurred
+     * @exception IllegalArgumentException if {@code n < 0}
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0) {
+            throw new IllegalArgumentException("negative skip length");
+        }
+        ensureOpen();
+        int max = (int)Math.min(n, Integer.MAX_VALUE);
+        int total = 0;
+        while (total < max) {
+            int len = max - total;
+            if (len > b.length) {
+                len = b.length;
+            }
+            len = read(b, 0, len);
+            if (len == -1) {
+                reachEOF = true;
+                break;
+            }
+            total += len;
+        }
+        return total;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources associated
+     * with the stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            // Android-changed: Unconditionally close external inflaters (b/26462400)
+            //if (usesDefaultInflater)
+            inf.end();
+            in.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Fills input buffer with more data to decompress.
+     * @exception IOException if an I/O error has occurred
+     */
+    protected void fill() throws IOException {
+        ensureOpen();
+        len = in.read(buf, 0, buf.length);
+        if (len == -1) {
+            throw new EOFException("Unexpected end of ZLIB input stream");
+        }
+        inf.setInput(buf, 0, len);
+    }
+
+    /**
+     * Tests if this input stream supports the <code>mark</code> and
+     * <code>reset</code> methods. The <code>markSupported</code>
+     * method of <code>InflaterInputStream</code> returns
+     * <code>false</code>.
+     *
+     * @return  a <code>boolean</code> indicating if this stream type supports
+     *          the <code>mark</code> and <code>reset</code> methods.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.InputStream#reset()
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * Marks the current position in this input stream.
+     *
+     * <p> The <code>mark</code> method of <code>InflaterInputStream</code>
+     * does nothing.
+     *
+     * @param   readlimit   the maximum limit of bytes that can be read before
+     *                      the mark position becomes invalid.
+     * @see     java.io.InputStream#reset()
+     */
+    public synchronized void mark(int readlimit) {
+    }
+
+    /**
+     * Repositions this stream to the position at the time the
+     * <code>mark</code> method was last called on this input stream.
+     *
+     * <p> The method <code>reset</code> for class
+     * <code>InflaterInputStream</code> does nothing except throw an
+     * <code>IOException</code>.
+     *
+     * @exception  IOException  if this method is invoked.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.IOException
+     */
+    public synchronized void reset() throws IOException {
+        throw new IOException("mark/reset not supported");
+    }
+}
diff --git a/java/util/zip/InflaterOutputStream.java b/java/util/zip/InflaterOutputStream.java
new file mode 100644
index 0000000..02900c7
--- /dev/null
+++ b/java/util/zip/InflaterOutputStream.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Implements an output stream filter for uncompressing data stored in the
+ * "deflate" compression format.
+ *
+ * @since       1.6
+ * @author      David R Tribble ([email protected])
+ *
+ * @see InflaterInputStream
+ * @see DeflaterInputStream
+ * @see DeflaterOutputStream
+ */
+
+public class InflaterOutputStream extends FilterOutputStream {
+    /** Decompressor for this stream. */
+    protected final Inflater inf;
+
+    /** Output buffer for writing uncompressed data. */
+    protected final byte[] buf;
+
+    /** Temporary write buffer. */
+    private final byte[] wbuf = new byte[1];
+
+    /** Default decompressor is used. */
+    private boolean usesDefaultInflater = false;
+
+    /** true iff {@link #close()} has been called. */
+    private boolean closed = false;
+
+    /**
+     * Checks to make sure that this stream has not been closed.
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new output stream with a default decompressor and buffer
+     * size.
+     *
+     * @param out output stream to write the uncompressed data to
+     * @throws NullPointerException if {@code out} is null
+     */
+    public InflaterOutputStream(OutputStream out) {
+        this(out, new Inflater());
+        usesDefaultInflater = true;
+    }
+
+    /**
+     * Creates a new output stream with the specified decompressor and a
+     * default buffer size.
+     *
+     * @param out output stream to write the uncompressed data to
+     * @param infl decompressor ("inflater") for this stream
+     * @throws NullPointerException if {@code out} or {@code infl} is null
+     */
+    public InflaterOutputStream(OutputStream out, Inflater infl) {
+        this(out, infl, 512);
+    }
+
+    /**
+     * Creates a new output stream with the specified decompressor and
+     * buffer size.
+     *
+     * @param out output stream to write the uncompressed data to
+     * @param infl decompressor ("inflater") for this stream
+     * @param bufLen decompression buffer size
+     * @throws IllegalArgumentException if {@code bufLen <= 0}
+     * @throws NullPointerException if {@code out} or {@code infl} is null
+     */
+    public InflaterOutputStream(OutputStream out, Inflater infl, int bufLen) {
+        super(out);
+
+        // Sanity checks
+        if (out == null)
+            throw new NullPointerException("Null output");
+        if (infl == null)
+            throw new NullPointerException("Null inflater");
+        if (bufLen <= 0)
+            throw new IllegalArgumentException("Buffer size < 1");
+
+        // Initialize
+        inf = infl;
+        buf = new byte[bufLen];
+    }
+
+    /**
+     * Writes any remaining uncompressed data to the output stream and closes
+     * the underlying output stream.
+     *
+     * @throws IOException if an I/O error occurs
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            // Complete the uncompressed output
+            try {
+                finish();
+            } finally {
+                out.close();
+                closed = true;
+            }
+        }
+    }
+
+    /**
+     * Flushes this output stream, forcing any pending buffered output bytes to be
+     * written.
+     *
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     */
+    public void flush() throws IOException {
+        ensureOpen();
+
+        // Finish decompressing and writing pending output data
+        if (!inf.finished()) {
+            try {
+                while (!inf.finished()  &&  !inf.needsInput()) {
+                    int n;
+
+                    // Decompress pending output data
+                    n = inf.inflate(buf, 0, buf.length);
+                    if (n < 1) {
+                        break;
+                    }
+
+                    // Write the uncompressed output data block
+                    out.write(buf, 0, n);
+                }
+                super.flush();
+            } catch (DataFormatException ex) {
+                // Improperly formatted compressed (ZIP) data
+                String msg = ex.getMessage();
+                if (msg == null) {
+                    msg = "Invalid ZLIB data format";
+                }
+                throw new ZipException(msg);
+            }
+        }
+    }
+
+    /**
+     * Finishes writing uncompressed data to the output stream without closing
+     * the underlying stream.  Use this method when applying multiple filters in
+     * succession to the same output stream.
+     *
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     */
+    public void finish() throws IOException {
+        ensureOpen();
+
+        // Finish decompressing and writing pending output data
+        flush();
+        if (usesDefaultInflater) {
+            inf.end();
+        }
+    }
+
+    /**
+     * Writes a byte to the uncompressed output stream.
+     *
+     * @param b a single byte of compressed data to decompress and write to
+     * the output stream
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     * @throws ZipException if a compression (ZIP) format error occurs
+     */
+    public void write(int b) throws IOException {
+        // Write a single byte of data
+        wbuf[0] = (byte) b;
+        write(wbuf, 0, 1);
+    }
+
+    /**
+     * Writes an array of bytes to the uncompressed output stream.
+     *
+     * @param b buffer containing compressed data to decompress and write to
+     * the output stream
+     * @param off starting offset of the compressed data within {@code b}
+     * @param len number of bytes to decompress from {@code b}
+     * @throws IndexOutOfBoundsException if {@code off < 0}, or if
+     * {@code len < 0}, or if {@code len > b.length - off}
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     * @throws NullPointerException if {@code b} is null
+     * @throws ZipException if a compression (ZIP) format error occurs
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        // Sanity checks
+        ensureOpen();
+        if (b == null) {
+            throw new NullPointerException("Null buffer for read");
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+
+        // Write uncompressed data to the output stream
+        try {
+            for (;;) {
+                int n;
+
+                // Fill the decompressor buffer with output data
+                if (inf.needsInput()) {
+                    int part;
+
+                    if (len < 1) {
+                        break;
+                    }
+
+                    part = (len < 512 ? len : 512);
+                    inf.setInput(b, off, part);
+                    off += part;
+                    len -= part;
+                }
+
+                // Decompress and write blocks of output data
+                do {
+                    n = inf.inflate(buf, 0, buf.length);
+                    if (n > 0) {
+                        out.write(buf, 0, n);
+                    }
+                } while (n > 0);
+
+                // Check the decompressor
+                if (inf.finished()) {
+                    break;
+                }
+                if (inf.needsDictionary()) {
+                    throw new ZipException("ZLIB dictionary missing");
+                }
+            }
+        } catch (DataFormatException ex) {
+            // Improperly formatted compressed (ZIP) data
+            String msg = ex.getMessage();
+            if (msg == null) {
+                msg = "Invalid ZLIB data format";
+            }
+            throw new ZipException(msg);
+        }
+    }
+}
diff --git a/java/util/zip/ZStreamRef.java b/java/util/zip/ZStreamRef.java
new file mode 100644
index 0000000..09b2f30
--- /dev/null
+++ b/java/util/zip/ZStreamRef.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/**
+ * A reference to the native zlib's z_stream structure.
+ */
+
+class ZStreamRef {
+
+    private volatile long address;
+    ZStreamRef (long address) {
+        this.address = address;
+    }
+
+    long address() {
+        return address;
+    }
+
+    void clear() {
+        address = 0;
+    }
+}
diff --git a/java/util/zip/ZipCoder.java b/java/util/zip/ZipCoder.java
new file mode 100644
index 0000000..b920b82
--- /dev/null
+++ b/java/util/zip/ZipCoder.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.util.Arrays;
+import sun.nio.cs.ArrayDecoder;
+import sun.nio.cs.ArrayEncoder;
+
+/**
+ * Utility class for zipfile name and comment decoding and encoding
+ */
+
+final class ZipCoder {
+
+    String toString(byte[] ba, int length) {
+        CharsetDecoder cd = decoder().reset();
+        int len = (int)(length * cd.maxCharsPerByte());
+        char[] ca = new char[len];
+        if (len == 0)
+            return new String(ca);
+        // UTF-8 only for now. Other ArrayDeocder only handles
+        // CodingErrorAction.REPLACE mode. ZipCoder uses
+        // REPORT mode.
+        if (isUTF8 && cd instanceof ArrayDecoder) {
+            int clen = ((ArrayDecoder)cd).decode(ba, 0, length, ca);
+            if (clen == -1)    // malformed
+                throw new IllegalArgumentException("MALFORMED");
+            return new String(ca, 0, clen);
+        }
+        ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);
+        CharBuffer cb = CharBuffer.wrap(ca);
+        CoderResult cr = cd.decode(bb, cb, true);
+        if (!cr.isUnderflow())
+            throw new IllegalArgumentException(cr.toString());
+        cr = cd.flush(cb);
+        if (!cr.isUnderflow())
+            throw new IllegalArgumentException(cr.toString());
+        return new String(ca, 0, cb.position());
+    }
+
+    String toString(byte[] ba) {
+        return toString(ba, ba.length);
+    }
+
+    byte[] getBytes(String s) {
+        CharsetEncoder ce = encoder().reset();
+        char[] ca = s.toCharArray();
+        int len = (int)(ca.length * ce.maxBytesPerChar());
+        byte[] ba = new byte[len];
+        if (len == 0)
+            return ba;
+        // UTF-8 only for now. Other ArrayDeocder only handles
+        // CodingErrorAction.REPLACE mode.
+        if (isUTF8 && ce instanceof ArrayEncoder) {
+            int blen = ((ArrayEncoder)ce).encode(ca, 0, ca.length, ba);
+            if (blen == -1)    // malformed
+                throw new IllegalArgumentException("MALFORMED");
+            return Arrays.copyOf(ba, blen);
+        }
+        ByteBuffer bb = ByteBuffer.wrap(ba);
+        CharBuffer cb = CharBuffer.wrap(ca);
+        CoderResult cr = ce.encode(cb, bb, true);
+        if (!cr.isUnderflow())
+            throw new IllegalArgumentException(cr.toString());
+        cr = ce.flush(bb);
+        if (!cr.isUnderflow())
+            throw new IllegalArgumentException(cr.toString());
+        if (bb.position() == ba.length)  // defensive copy?
+            return ba;
+        else
+            return Arrays.copyOf(ba, bb.position());
+    }
+
+    // assume invoked only if "this" is not utf8
+    byte[] getBytesUTF8(String s) {
+        if (isUTF8)
+            return getBytes(s);
+        if (utf8 == null)
+            utf8 = new ZipCoder(StandardCharsets.UTF_8);
+        return utf8.getBytes(s);
+    }
+
+
+    String toStringUTF8(byte[] ba, int len) {
+        if (isUTF8)
+            return toString(ba, len);
+        if (utf8 == null)
+            utf8 = new ZipCoder(StandardCharsets.UTF_8);
+        return utf8.toString(ba, len);
+    }
+
+    boolean isUTF8() {
+        return isUTF8;
+    }
+
+    private Charset cs;
+    private CharsetDecoder dec;
+    private CharsetEncoder enc;
+    private boolean isUTF8;
+    private ZipCoder utf8;
+
+    private ZipCoder(Charset cs) {
+        this.cs = cs;
+        this.isUTF8 = cs.name().equals(StandardCharsets.UTF_8.name());
+    }
+
+    static ZipCoder get(Charset charset) {
+        return new ZipCoder(charset);
+    }
+
+    private CharsetDecoder decoder() {
+        if (dec == null) {
+            dec = cs.newDecoder()
+              .onMalformedInput(CodingErrorAction.REPORT)
+              .onUnmappableCharacter(CodingErrorAction.REPORT);
+        }
+        return dec;
+    }
+
+    private CharsetEncoder encoder() {
+        if (enc == null) {
+            enc = cs.newEncoder()
+              .onMalformedInput(CodingErrorAction.REPORT)
+              .onUnmappableCharacter(CodingErrorAction.REPORT);
+        }
+        return enc;
+    }
+}
diff --git a/java/util/zip/ZipConstants.java b/java/util/zip/ZipConstants.java
new file mode 100644
index 0000000..db7f500
--- /dev/null
+++ b/java/util/zip/ZipConstants.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/*
+ * This interface defines the constants that are used by the classes
+ * which manipulate ZIP files.
+ *
+ * @author      David Connelly
+ */
+interface ZipConstants {
+    /*
+     * Header signatures
+     */
+    static long LOCSIG = 0x04034b50L;   // "PK\003\004"
+    static long EXTSIG = 0x08074b50L;   // "PK\007\008"
+    static long CENSIG = 0x02014b50L;   // "PK\001\002"
+    static long ENDSIG = 0x06054b50L;   // "PK\005\006"
+
+    /*
+     * Header sizes in bytes (including signatures)
+     */
+    static final int LOCHDR = 30;       // LOC header size
+    static final int EXTHDR = 16;       // EXT header size
+    static final int CENHDR = 46;       // CEN header size
+    static final int ENDHDR = 22;       // END header size
+
+    /*
+     * Local file (LOC) header field offsets
+     */
+    static final int LOCVER = 4;        // version needed to extract
+    static final int LOCFLG = 6;        // general purpose bit flag
+    static final int LOCHOW = 8;        // compression method
+    static final int LOCTIM = 10;       // modification time
+    static final int LOCCRC = 14;       // uncompressed file crc-32 value
+    static final int LOCSIZ = 18;       // compressed size
+    static final int LOCLEN = 22;       // uncompressed size
+    static final int LOCNAM = 26;       // filename length
+    static final int LOCEXT = 28;       // extra field length
+
+    /*
+     * Extra local (EXT) header field offsets
+     */
+    static final int EXTCRC = 4;        // uncompressed file crc-32 value
+    static final int EXTSIZ = 8;        // compressed size
+    static final int EXTLEN = 12;       // uncompressed size
+
+    /*
+     * Central directory (CEN) header field offsets
+     */
+    static final int CENVEM = 4;        // version made by
+    static final int CENVER = 6;        // version needed to extract
+    static final int CENFLG = 8;        // encrypt, decrypt flags
+    static final int CENHOW = 10;       // compression method
+    static final int CENTIM = 12;       // modification time
+    static final int CENCRC = 16;       // uncompressed file crc-32 value
+    static final int CENSIZ = 20;       // compressed size
+    static final int CENLEN = 24;       // uncompressed size
+    static final int CENNAM = 28;       // filename length
+    static final int CENEXT = 30;       // extra field length
+    static final int CENCOM = 32;       // comment length
+    static final int CENDSK = 34;       // disk number start
+    static final int CENATT = 36;       // internal file attributes
+    static final int CENATX = 38;       // external file attributes
+    static final int CENOFF = 42;       // LOC header offset
+
+    /*
+     * End of central directory (END) header field offsets
+     */
+    static final int ENDSUB = 8;        // number of entries on this disk
+    static final int ENDTOT = 10;       // total number of entries
+    static final int ENDSIZ = 12;       // central directory size in bytes
+    static final int ENDOFF = 16;       // offset of first CEN header
+    static final int ENDCOM = 20;       // zip file comment length
+}
diff --git a/java/util/zip/ZipConstants64.java b/java/util/zip/ZipConstants64.java
new file mode 100644
index 0000000..5d45f77
--- /dev/null
+++ b/java/util/zip/ZipConstants64.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/*
+ * This class defines the constants that are used by the classes
+ * which manipulate Zip64 files.
+ */
+
+class ZipConstants64 {
+
+    /*
+     * ZIP64 constants
+     */
+    static final long ZIP64_ENDSIG = 0x06064b50L;  // "PK\006\006"
+    static final long ZIP64_LOCSIG = 0x07064b50L;  // "PK\006\007"
+    static final int  ZIP64_ENDHDR = 56;           // ZIP64 end header size
+    static final int  ZIP64_LOCHDR = 20;           // ZIP64 end loc header size
+    static final int  ZIP64_EXTHDR = 24;           // EXT header size
+    static final int  ZIP64_EXTID  = 0x0001;       // Extra field Zip64 header ID
+
+    static final int  ZIP64_MAGICCOUNT = 0xFFFF;
+    static final long ZIP64_MAGICVAL = 0xFFFFFFFFL;
+
+    /*
+     * Zip64 End of central directory (END) header field offsets
+     */
+    static final int  ZIP64_ENDLEN = 4;       // size of zip64 end of central dir
+    static final int  ZIP64_ENDVEM = 12;      // version made by
+    static final int  ZIP64_ENDVER = 14;      // version needed to extract
+    static final int  ZIP64_ENDNMD = 16;      // number of this disk
+    static final int  ZIP64_ENDDSK = 20;      // disk number of start
+    static final int  ZIP64_ENDTOD = 24;      // total number of entries on this disk
+    static final int  ZIP64_ENDTOT = 32;      // total number of entries
+    static final int  ZIP64_ENDSIZ = 40;      // central directory size in bytes
+    static final int  ZIP64_ENDOFF = 48;      // offset of first CEN header
+    static final int  ZIP64_ENDEXT = 56;      // zip64 extensible data sector
+
+    /*
+     * Zip64 End of central directory locator field offsets
+     */
+    static final int  ZIP64_LOCDSK = 4;       // disk number start
+    static final int  ZIP64_LOCOFF = 8;       // offset of zip64 end
+    static final int  ZIP64_LOCTOT = 16;      // total number of disks
+
+    /*
+     * Zip64 Extra local (EXT) header field offsets
+     */
+    static final int  ZIP64_EXTCRC = 4;       // uncompressed file crc-32 value
+    static final int  ZIP64_EXTSIZ = 8;       // compressed size, 8-byte
+    static final int  ZIP64_EXTLEN = 16;      // uncompressed size, 8-byte
+
+    /*
+     * Language encoding flag EFS
+     */
+    static final int EFS = 0x800;       // If this bit is set the filename and
+                                        // comment fields for this file must be
+                                        // encoded using UTF-8.
+
+    /*
+     * Constants below are defined here (instead of in ZipConstants)
+     * to avoid being exposed as public fields of ZipFile, ZipEntry,
+     * ZipInputStream and ZipOutputstream.
+     */
+
+    /*
+     * Extra field header ID
+     */
+    static final int  EXTID_ZIP64 = 0x0001;    // Zip64
+    static final int  EXTID_NTFS  = 0x000a;    // NTFS
+    static final int  EXTID_UNIX  = 0x000d;    // UNIX
+    static final int  EXTID_EXTT  = 0x5455;    // Info-ZIP Extended Timestamp
+
+    /*
+     * EXTT timestamp flags
+     */
+    static final int  EXTT_FLAG_LMT = 0x1;       // LastModifiedTime
+    static final int  EXTT_FLAG_LAT = 0x2;       // LastAccessTime
+    static final int  EXTT_FLAT_CT  = 0x4;       // CreationTime
+
+    private ZipConstants64() {}
+}
diff --git a/java/util/zip/ZipEntry.annotated.java b/java/util/zip/ZipEntry.annotated.java
new file mode 100644
index 0000000..66b3616
--- /dev/null
+++ b/java/util/zip/ZipEntry.annotated.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.zip;
+
+import java.nio.file.attribute.FileTime;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ZipEntry implements java.lang.Cloneable {
+
+public ZipEntry(java.lang.String name, java.lang.String comment, long crc, long compressedSize, long size, int compressionMethod, int xdostime, byte[] extra, long dataOffset) { throw new RuntimeException("Stub!"); }
+
+public ZipEntry(java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public ZipEntry(java.util.zip.ZipEntry e) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public long getDataOffset() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
+public void setTime(long time) { throw new RuntimeException("Stub!"); }
+
+public long getTime() { throw new RuntimeException("Stub!"); }
+
+public java.util.zip.ZipEntry setLastModifiedTime(java.nio.file.attribute.FileTime time) { throw new RuntimeException("Stub!"); }
+
+public java.nio.file.attribute.FileTime getLastModifiedTime() { throw new RuntimeException("Stub!"); }
+
+public java.util.zip.ZipEntry setLastAccessTime(java.nio.file.attribute.FileTime time) { throw new RuntimeException("Stub!"); }
+
+public java.nio.file.attribute.FileTime getLastAccessTime() { throw new RuntimeException("Stub!"); }
+
+public java.util.zip.ZipEntry setCreationTime(java.nio.file.attribute.FileTime time) { throw new RuntimeException("Stub!"); }
+
+public java.nio.file.attribute.FileTime getCreationTime() { throw new RuntimeException("Stub!"); }
+
+public void setSize(long size) { throw new RuntimeException("Stub!"); }
+
+public long getSize() { throw new RuntimeException("Stub!"); }
+
+public long getCompressedSize() { throw new RuntimeException("Stub!"); }
+
+public void setCompressedSize(long csize) { throw new RuntimeException("Stub!"); }
+
+public void setCrc(long crc) { throw new RuntimeException("Stub!"); }
+
+public long getCrc() { throw new RuntimeException("Stub!"); }
+
+public void setMethod(int method) { throw new RuntimeException("Stub!"); }
+
+public int getMethod() { throw new RuntimeException("Stub!"); }
+
+public void setExtra(byte[] extra) { throw new RuntimeException("Stub!"); }
+
+public byte[] getExtra() { throw new RuntimeException("Stub!"); }
+
+public void setComment(java.lang.String comment) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getComment() { throw new RuntimeException("Stub!"); }
+
+public boolean isDirectory() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public static final int CENATT = 36; // 0x24
+
+public static final int CENATX = 38; // 0x26
+
+public static final int CENCOM = 32; // 0x20
+
+public static final int CENCRC = 16; // 0x10
+
+public static final int CENDSK = 34; // 0x22
+
+public static final int CENEXT = 30; // 0x1e
+
+public static final int CENFLG = 8; // 0x8
+
+public static final int CENHDR = 46; // 0x2e
+
+public static final int CENHOW = 10; // 0xa
+
+public static final int CENLEN = 24; // 0x18
+
+public static final int CENNAM = 28; // 0x1c
+
+public static final int CENOFF = 42; // 0x2a
+
+public static final long CENSIG = 33639248L; // 0x2014b50L
+
+public static final int CENSIZ = 20; // 0x14
+
+public static final int CENTIM = 12; // 0xc
+
+public static final int CENVEM = 4; // 0x4
+
+public static final int CENVER = 6; // 0x6
+
+public static final int DEFLATED = 8; // 0x8
+
+public static final int ENDCOM = 20; // 0x14
+
+public static final int ENDHDR = 22; // 0x16
+
+public static final int ENDOFF = 16; // 0x10
+
+public static final long ENDSIG = 101010256L; // 0x6054b50L
+
+public static final int ENDSIZ = 12; // 0xc
+
+public static final int ENDSUB = 8; // 0x8
+
+public static final int ENDTOT = 10; // 0xa
+
+public static final int EXTCRC = 4; // 0x4
+
+public static final int EXTHDR = 16; // 0x10
+
+public static final int EXTLEN = 12; // 0xc
+
+public static final long EXTSIG = 134695760L; // 0x8074b50L
+
+public static final int EXTSIZ = 8; // 0x8
+
+public static final int LOCCRC = 14; // 0xe
+
+public static final int LOCEXT = 28; // 0x1c
+
+public static final int LOCFLG = 6; // 0x6
+
+public static final int LOCHDR = 30; // 0x1e
+
+public static final int LOCHOW = 8; // 0x8
+
+public static final int LOCLEN = 22; // 0x16
+
+public static final int LOCNAM = 26; // 0x1a
+
+public static final long LOCSIG = 67324752L; // 0x4034b50L
+
+public static final int LOCSIZ = 18; // 0x12
+
+public static final int LOCTIM = 10; // 0xa
+
+public static final int LOCVER = 4; // 0x4
+
+public static final int STORED = 0; // 0x0
+
+public static final long UPPER_DOSTIME_BOUND = 4036608000000L; // 0x3abd8960000L
+}
+
diff --git a/java/util/zip/ZipEntry.java b/java/util/zip/ZipEntry.java
new file mode 100644
index 0000000..0de6756
--- /dev/null
+++ b/java/util/zip/ZipEntry.java
@@ -0,0 +1,636 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import static java.util.zip.ZipUtils.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.attribute.FileTime;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import static java.util.zip.ZipConstants64.*;
+
+/**
+ * This class is used to represent a ZIP file entry.
+ *
+ * @author      David Connelly
+ */
+public
+class ZipEntry implements ZipConstants, Cloneable {
+    String name;        // entry name
+    long xdostime = -1; // last modification time (in extended DOS time,
+                        // where milliseconds lost in conversion might
+                        // be encoded into the upper half)
+    FileTime mtime;     // last modification time, from extra field data
+    FileTime atime;     // last access time, from extra field data
+    FileTime ctime;     // creation time, from extra field data
+    long crc = -1;      // crc-32 of entry data
+    long size = -1;     // uncompressed size of entry data
+    long csize = -1;    // compressed size of entry data
+    int method = -1;    // compression method
+    int flag = 0;       // general purpose flag
+    byte[] extra;       // optional extra field data for entry
+    String comment;     // optional comment string for entry
+    // Android-added: Add dataOffset for internal use.
+    // Used by android.util.jar.StrictJarFile from frameworks.
+    long dataOffset;
+
+    /**
+     * Compression method for uncompressed entries.
+     */
+    public static final int STORED = 0;
+
+    /**
+     * Compression method for compressed (deflated) entries.
+     */
+    public static final int DEFLATED = 8;
+
+    /**
+     * DOS time constant for representing timestamps before 1980.
+     */
+    static final long DOSTIME_BEFORE_1980 = (1 << 21) | (1 << 16);
+
+    /**
+     * Approximately 128 years, in milliseconds (ignoring leap years etc).
+     *
+     * This establish an approximate high-bound value for DOS times in
+     * milliseconds since epoch, used to enable an efficient but
+     * sufficient bounds check to avoid generating extended last modified
+     * time entries.
+     *
+     * Calculating the exact number is locale dependent, would require loading
+     * TimeZone data eagerly, and would make little practical sense. Since DOS
+     * times theoretically go to 2107 - with compatibility not guaranteed
+     * after 2099 - setting this to a time that is before but near 2099
+     * should be sufficient.
+     * @hide
+     */
+    // Android-changed: Make UPPER_DOSTIME_BOUND public hidden for testing purposes.
+    public static final long UPPER_DOSTIME_BOUND =
+            128L * 365 * 24 * 60 * 60 * 1000;
+
+    // Android-added: New constructor for use by StrictJarFile native code.
+    /** @hide */
+    public ZipEntry(String name, String comment, long crc, long compressedSize,
+            long size, int compressionMethod, int xdostime, byte[] extra,
+            long dataOffset) {
+        this.name = name;
+        this.comment = comment;
+        this.crc = crc;
+        this.csize = compressedSize;
+        this.size = size;
+        this.method = compressionMethod;
+        this.xdostime = xdostime;
+        this.dataOffset = dataOffset;
+        this.setExtra0(extra, false);
+    }
+
+    /**
+     * Creates a new zip entry with the specified name.
+     *
+     * @param  name
+     *         The entry name
+     *
+     * @throws NullPointerException if the entry name is null
+     * @throws IllegalArgumentException if the entry name is longer than
+     *         0xFFFF bytes
+     */
+    public ZipEntry(String name) {
+        Objects.requireNonNull(name, "name");
+        // Android-changed: Explicitly use UTF_8 instead of the default charset.
+        // if (name.length() > 0xFFFF) {
+        //     throw new IllegalArgumentException("entry name too long");
+        // }
+        if (name.getBytes(StandardCharsets.UTF_8).length > 0xffff) {
+            throw new IllegalArgumentException(name + " too long: " +
+                    name.getBytes(StandardCharsets.UTF_8).length);
+        }
+        this.name = name;
+    }
+
+    /**
+     * Creates a new zip entry with fields taken from the specified
+     * zip entry.
+     *
+     * @param  e
+     *         A zip Entry object
+     *
+     * @throws NullPointerException if the entry object is null
+     */
+    public ZipEntry(ZipEntry e) {
+        Objects.requireNonNull(e, "entry");
+        name = e.name;
+        xdostime = e.xdostime;
+        mtime = e.mtime;
+        atime = e.atime;
+        ctime = e.ctime;
+        crc = e.crc;
+        size = e.size;
+        csize = e.csize;
+        method = e.method;
+        flag = e.flag;
+        extra = e.extra;
+        comment = e.comment;
+        // Android-added: Add dataOffset for internal use.
+        dataOffset = e.dataOffset;
+    }
+
+    /**
+     * Creates a new un-initialized zip entry
+     */
+    ZipEntry() {}
+
+    // Android-added: Add dataOffset for internal use.
+    /** @hide */
+    public long getDataOffset() {
+        return dataOffset;
+    }
+
+    /**
+     * Returns the name of the entry.
+     * @return the name of the entry
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the last modification time of the entry.
+     *
+     * <p> If the entry is output to a ZIP file or ZIP file formatted
+     * output stream the last modification time set by this method will
+     * be stored into the {@code date and time fields} of the zip file
+     * entry and encoded in standard {@code MS-DOS date and time format}.
+     * The {@link java.util.TimeZone#getDefault() default TimeZone} is
+     * used to convert the epoch time to the MS-DOS data and time.
+     *
+     * @param  time
+     *         The last modification time of the entry in milliseconds
+     *         since the epoch
+     *
+     * @see #getTime()
+     * @see #getLastModifiedTime()
+     */
+    public void setTime(long time) {
+        this.xdostime = javaToExtendedDosTime(time);
+        // Avoid setting the mtime field if time is in the valid
+        // range for a DOS time
+        if (xdostime != DOSTIME_BEFORE_1980 && time <= UPPER_DOSTIME_BOUND) {
+            this.mtime = null;
+        } else {
+            this.mtime = FileTime.from(time, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    /**
+     * Returns the last modification time of the entry.
+     *
+     * <p> If the entry is read from a ZIP file or ZIP file formatted
+     * input stream, this is the last modification time from the {@code
+     * date and time fields} of the zip file entry. The
+     * {@link java.util.TimeZone#getDefault() default TimeZone} is used
+     * to convert the standard MS-DOS formatted date and time to the
+     * epoch time.
+     *
+     * @return  The last modification time of the entry in milliseconds
+     *          since the epoch, or -1 if not specified
+     *
+     * @see #setTime(long)
+     * @see #setLastModifiedTime(FileTime)
+     */
+    public long getTime() {
+        if (mtime != null) {
+            return mtime.toMillis();
+        }
+        return (xdostime != -1) ? extendedDosToJavaTime(xdostime) : -1;
+    }
+
+    /**
+     * Sets the last modification time of the entry.
+     *
+     * <p> When output to a ZIP file or ZIP file formatted output stream
+     * the last modification time set by this method will be stored into
+     * zip file entry's {@code date and time fields} in {@code standard
+     * MS-DOS date and time format}), and the extended timestamp fields
+     * in {@code optional extra data} in UTC time.
+     *
+     * @param  time
+     *         The last modification time of the entry
+     * @return This zip entry
+     *
+     * @throws NullPointerException if the {@code time} is null
+     *
+     * @see #getLastModifiedTime()
+     * @since 1.8
+     */
+    public ZipEntry setLastModifiedTime(FileTime time) {
+        this.mtime = Objects.requireNonNull(time, "lastModifiedTime");
+        this.xdostime = javaToExtendedDosTime(time.to(TimeUnit.MILLISECONDS));
+        return this;
+    }
+
+    /**
+     * Returns the last modification time of the entry.
+     *
+     * <p> If the entry is read from a ZIP file or ZIP file formatted
+     * input stream, this is the last modification time from the zip
+     * file entry's {@code optional extra data} if the extended timestamp
+     * fields are present. Otherwise the last modification time is read
+     * from the entry's {@code date and time fields}, the {@link
+     * java.util.TimeZone#getDefault() default TimeZone} is used to convert
+     * the standard MS-DOS formatted date and time to the epoch time.
+     *
+     * @return The last modification time of the entry, null if not specified
+     *
+     * @see #setLastModifiedTime(FileTime)
+     * @since 1.8
+     */
+    public FileTime getLastModifiedTime() {
+        if (mtime != null)
+            return mtime;
+        if (xdostime == -1)
+            return null;
+        return FileTime.from(getTime(), TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Sets the last access time of the entry.
+     *
+     * <p> If set, the last access time will be stored into the extended
+     * timestamp fields of entry's {@code optional extra data}, when output
+     * to a ZIP file or ZIP file formatted stream.
+     *
+     * @param  time
+     *         The last access time of the entry
+     * @return This zip entry
+     *
+     * @throws NullPointerException if the {@code time} is null
+     *
+     * @see #getLastAccessTime()
+     * @since 1.8
+     */
+    public ZipEntry setLastAccessTime(FileTime time) {
+        this.atime = Objects.requireNonNull(time, "lastAccessTime");
+        return this;
+    }
+
+    /**
+     * Returns the last access time of the entry.
+     *
+     * <p> The last access time is from the extended timestamp fields
+     * of entry's {@code optional extra data} when read from a ZIP file
+     * or ZIP file formatted stream.
+     *
+     * @return The last access time of the entry, null if not specified
+
+     * @see #setLastAccessTime(FileTime)
+     * @since 1.8
+     */
+    public FileTime getLastAccessTime() {
+        return atime;
+    }
+
+    /**
+     * Sets the creation time of the entry.
+     *
+     * <p> If set, the creation time will be stored into the extended
+     * timestamp fields of entry's {@code optional extra data}, when
+     * output to a ZIP file or ZIP file formatted stream.
+     *
+     * @param  time
+     *         The creation time of the entry
+     * @return This zip entry
+     *
+     * @throws NullPointerException if the {@code time} is null
+     *
+     * @see #getCreationTime()
+     * @since 1.8
+     */
+    public ZipEntry setCreationTime(FileTime time) {
+        this.ctime = Objects.requireNonNull(time, "creationTime");
+        return this;
+    }
+
+    /**
+     * Returns the creation time of the entry.
+     *
+     * <p> The creation time is from the extended timestamp fields of
+     * entry's {@code optional extra data} when read from a ZIP file
+     * or ZIP file formatted stream.
+     *
+     * @return the creation time of the entry, null if not specified
+     * @see #setCreationTime(FileTime)
+     * @since 1.8
+     */
+    public FileTime getCreationTime() {
+        return ctime;
+    }
+
+    /**
+     * Sets the uncompressed size of the entry data.
+     *
+     * @param size the uncompressed size in bytes
+     *
+     * @throws IllegalArgumentException if the specified size is less
+     *         than 0, is greater than 0xFFFFFFFF when
+     *         <a href="package-summary.html#zip64">ZIP64 format</a> is not supported,
+     *         or is less than 0 when ZIP64 is supported
+     * @see #getSize()
+     */
+    public void setSize(long size) {
+        if (size < 0) {
+            throw new IllegalArgumentException("invalid entry size");
+        }
+        this.size = size;
+    }
+
+    /**
+     * Returns the uncompressed size of the entry data.
+     *
+     * @return the uncompressed size of the entry data, or -1 if not known
+     * @see #setSize(long)
+     */
+    public long getSize() {
+        return size;
+    }
+
+    /**
+     * Returns the size of the compressed entry data.
+     *
+     * <p> In the case of a stored entry, the compressed size will be the same
+     * as the uncompressed size of the entry.
+     *
+     * @return the size of the compressed entry data, or -1 if not known
+     * @see #setCompressedSize(long)
+     */
+    public long getCompressedSize() {
+        return csize;
+    }
+
+    /**
+     * Sets the size of the compressed entry data.
+     *
+     * @param csize the compressed size to set to
+     *
+     * @see #getCompressedSize()
+     */
+    public void setCompressedSize(long csize) {
+        this.csize = csize;
+    }
+
+    /**
+     * Sets the CRC-32 checksum of the uncompressed entry data.
+     *
+     * @param crc the CRC-32 value
+     *
+     * @throws IllegalArgumentException if the specified CRC-32 value is
+     *         less than 0 or greater than 0xFFFFFFFF
+     * @see #getCrc()
+     */
+    public void setCrc(long crc) {
+        if (crc < 0 || crc > 0xFFFFFFFFL) {
+            throw new IllegalArgumentException("invalid entry crc-32");
+        }
+        this.crc = crc;
+    }
+
+    /**
+     * Returns the CRC-32 checksum of the uncompressed entry data.
+     *
+     * @return the CRC-32 checksum of the uncompressed entry data, or -1 if
+     * not known
+     *
+     * @see #setCrc(long)
+     */
+    public long getCrc() {
+        return crc;
+    }
+
+    /**
+     * Sets the compression method for the entry.
+     *
+     * @param method the compression method, either STORED or DEFLATED
+     *
+     * @throws  IllegalArgumentException if the specified compression
+     *          method is invalid
+     * @see #getMethod()
+     */
+    public void setMethod(int method) {
+        if (method != STORED && method != DEFLATED) {
+            throw new IllegalArgumentException("invalid compression method");
+        }
+        this.method = method;
+    }
+
+    /**
+     * Returns the compression method of the entry.
+     *
+     * @return the compression method of the entry, or -1 if not specified
+     * @see #setMethod(int)
+     */
+    public int getMethod() {
+        return method;
+    }
+
+    /**
+     * Sets the optional extra field data for the entry.
+     *
+     * <p> Invoking this method may change this entry's last modification
+     * time, last access time and creation time, if the {@code extra} field
+     * data includes the extensible timestamp fields, such as {@code NTFS tag
+     * 0x0001} or {@code Info-ZIP Extended Timestamp}, as specified in
+     * <a href="http://www.info-zip.org/doc/appnote-19970311-iz.zip">Info-ZIP
+     * Application Note 970311</a>.
+     *
+     * @param  extra
+     *         The extra field data bytes
+     *
+     * @throws IllegalArgumentException if the length of the specified
+     *         extra field data is greater than 0xFFFF bytes
+     *
+     * @see #getExtra()
+     */
+    public void setExtra(byte[] extra) {
+        setExtra0(extra, false);
+    }
+
+    /**
+     * Sets the optional extra field data for the entry.
+     *
+     * @param extra
+     *        the extra field data bytes
+     * @param doZIP64
+     *        if true, set size and csize from ZIP64 fields if present
+     */
+    void setExtra0(byte[] extra, boolean doZIP64) {
+        if (extra != null) {
+            if (extra.length > 0xFFFF) {
+                throw new IllegalArgumentException("invalid extra field length");
+            }
+            // extra fields are in "HeaderID(2)DataSize(2)Data... format
+            int off = 0;
+            int len = extra.length;
+            while (off + 4 < len) {
+                int tag = get16(extra, off);
+                int sz = get16(extra, off + 2);
+                off += 4;
+                if (off + sz > len)         // invalid data
+                    break;
+                switch (tag) {
+                case EXTID_ZIP64:
+                    if (doZIP64) {
+                        // LOC extra zip64 entry MUST include BOTH original
+                        // and compressed file size fields.
+                        // If invalid zip64 extra fields, simply skip. Even
+                        // it's rare, it's possible the entry size happens to
+                        // be the magic value and it "accidently" has some
+                        // bytes in extra match the id.
+                        if (sz >= 16) {
+                            size = get64(extra, off);
+                            csize = get64(extra, off + 8);
+                        }
+                    }
+                    break;
+                case EXTID_NTFS:
+                    if (sz < 32) // reserved  4 bytes + tag 2 bytes + size 2 bytes
+                        break;   // m[a|c]time 24 bytes
+                    int pos = off + 4;               // reserved 4 bytes
+                    if (get16(extra, pos) !=  0x0001 || get16(extra, pos + 2) != 24)
+                        break;
+                    mtime = winTimeToFileTime(get64(extra, pos + 4));
+                    atime = winTimeToFileTime(get64(extra, pos + 12));
+                    ctime = winTimeToFileTime(get64(extra, pos + 20));
+                    break;
+                case EXTID_EXTT:
+                    int flag = Byte.toUnsignedInt(extra[off]);
+                    int sz0 = 1;
+                    // The CEN-header extra field contains the modification
+                    // time only, or no timestamp at all. 'sz' is used to
+                    // flag its presence or absence. But if mtime is present
+                    // in LOC it must be present in CEN as well.
+                    if ((flag & 0x1) != 0 && (sz0 + 4) <= sz) {
+                        mtime = unixTimeToFileTime(get32(extra, off + sz0));
+                        sz0 += 4;
+                    }
+                    if ((flag & 0x2) != 0 && (sz0 + 4) <= sz) {
+                        atime = unixTimeToFileTime(get32(extra, off + sz0));
+                        sz0 += 4;
+                    }
+                    if ((flag & 0x4) != 0 && (sz0 + 4) <= sz) {
+                        ctime = unixTimeToFileTime(get32(extra, off + sz0));
+                        sz0 += 4;
+                    }
+                    break;
+                 default:
+                }
+                off += sz;
+            }
+        }
+        this.extra = extra;
+    }
+
+    /**
+     * Returns the extra field data for the entry.
+     *
+     * @return the extra field data for the entry, or null if none
+     *
+     * @see #setExtra(byte[])
+     */
+    public byte[] getExtra() {
+        return extra;
+    }
+
+    /**
+     * Sets the optional comment string for the entry.
+     *
+     * <p>ZIP entry comments have maximum length of 0xffff. If the length of the
+     * specified comment string is greater than 0xFFFF bytes after encoding, only
+     * the first 0xFFFF bytes are output to the ZIP file entry.
+     *
+     * @param comment the comment string
+     *
+     * @see #getComment()
+     */
+    public void setComment(String comment) {
+        // BEGIN Android-added: Explicitly use UTF_8 instead of the default charset.
+        if (comment != null && comment.getBytes(StandardCharsets.UTF_8).length > 0xffff) {
+            throw new IllegalArgumentException(comment + " too long: " +
+                    comment.getBytes(StandardCharsets.UTF_8).length);
+        }
+        // END Android-added: Explicitly use UTF_8 instead of the default charset.
+
+        this.comment = comment;
+    }
+
+    /**
+     * Returns the comment string for the entry.
+     *
+     * @return the comment string for the entry, or null if none
+     *
+     * @see #setComment(String)
+     */
+    public String getComment() {
+        return comment;
+    }
+
+    /**
+     * Returns true if this is a directory entry. A directory entry is
+     * defined to be one whose name ends with a '/'.
+     * @return true if this is a directory entry
+     */
+    public boolean isDirectory() {
+        return name.endsWith("/");
+    }
+
+    /**
+     * Returns a string representation of the ZIP entry.
+     */
+    public String toString() {
+        return getName();
+    }
+
+    /**
+     * Returns the hash code value for this entry.
+     */
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    /**
+     * Returns a copy of this entry.
+     */
+    public Object clone() {
+        try {
+            ZipEntry e = (ZipEntry)super.clone();
+            e.extra = (extra == null) ? null : extra.clone();
+            return e;
+        } catch (CloneNotSupportedException e) {
+            // This should never happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+}
diff --git a/java/util/zip/ZipError.java b/java/util/zip/ZipError.java
new file mode 100644
index 0000000..2799c8e
--- /dev/null
+++ b/java/util/zip/ZipError.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/**
+ * Signals that an unrecoverable error has occurred.
+ *
+ * @author  Dave Bristor
+ * @since   1.6
+ */
+public class ZipError extends InternalError {
+    private static final long serialVersionUID = 853973422266861979L;
+
+    /**
+     * Constructs a ZipError with the given detail message.
+     * @param s the {@code String} containing a detail message
+     */
+    public ZipError(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/zip/ZipException.java b/java/util/zip/ZipException.java
new file mode 100644
index 0000000..4bcfe03
--- /dev/null
+++ b/java/util/zip/ZipException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.IOException;
+
+/**
+ * Signals that a Zip exception of some sort has occurred.
+ *
+ * @author  unascribed
+ * @see     java.io.IOException
+ * @since   JDK1.0
+ */
+
+public
+class ZipException extends IOException {
+    private static final long serialVersionUID = 8000196834066748623L;
+
+    /**
+     * Constructs a <code>ZipException</code> with <code>null</code>
+     * as its error detail message.
+     */
+    public ZipException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>ZipException</code> with the specified detail
+     * message.
+     *
+     * @param   s   the detail message.
+     */
+
+    public ZipException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/zip/ZipFile.java b/java/util/zip/ZipFile.java
new file mode 100644
index 0000000..851aab1
--- /dev/null
+++ b/java/util/zip/ZipFile.java
@@ -0,0 +1,931 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.Closeable;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.WeakHashMap;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import dalvik.system.CloseGuard;
+
+import static java.util.zip.ZipConstants64.*;
+
+/**
+ * This class is used to read entries from a zip file.
+ *
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
+ * @author      David Connelly
+ */
+public
+class ZipFile implements ZipConstants, Closeable {
+    // Android-note: jzfile does not require @ReachabilitySensitive annotation.
+    // The @ReachabilitySensitive annotation is usually added to instance fields that references
+    // native data that is cleaned up when the instance becomes unreachable. Its presence ensures
+    // that the instance object is not finalized until the field is no longer used. Without it an
+    // instance could be finalized during execution of an instance method iff that method's this
+    // variable holds the last reference to the instance and the method had copied all the fields
+    // it needs out of the instance. That would release the native data, invalidating its reference
+    // and would cause serious problems if the method had taken a copy of that field and
+    // then called a native method that would try to use it.
+    //
+    // This field does not require the annotation because all usages of this field are enclosed
+    // within a synchronized(this) block and finalizing of the object referenced in a synchronized
+    // block is not allowed as that would release its monitor that is currently in use.
+    private long jzfile;  // address of jzfile data
+    private final String name;     // zip file name
+    private final int total;       // total number of entries
+    private final boolean locsig;  // if zip file starts with LOCSIG (usually true)
+    private volatile boolean closeRequested = false;
+
+    // Android-added: CloseGuard support
+    private final CloseGuard guard = CloseGuard.get();
+
+    // Android-added: Do not use unlink() to implement OPEN_DELETE.
+    // Upstream uses unlink() to cause the file name to be removed from the filesystem after it is
+    // opened but that does not work on fuse fs as it causes problems with lseek. Android simply
+    // keeps a reference to the File so that it can explicitly delete it during close.
+    //
+    // OpenJDK 9+181 has a pure Java implementation of ZipFile that does not use unlink() and
+    // instead does something very similar to what Android does. If Android adopts it then this
+    // patch can be dropped.
+    // See http://b/28950284 and http://b/28901232 for more details.
+    private final File fileToRemoveOnClose;
+
+    private static final int STORED = ZipEntry.STORED;
+    private static final int DEFLATED = ZipEntry.DEFLATED;
+
+    /**
+     * Mode flag to open a zip file for reading.
+     */
+    public static final int OPEN_READ = 0x1;
+
+    /**
+     * Mode flag to open a zip file and mark it for deletion.  The file will be
+     * deleted some time between the moment that it is opened and the moment
+     * that it is closed, but its contents will remain accessible via the
+     * <tt>ZipFile</tt> object until either the close method is invoked or the
+     * virtual machine exits.
+     */
+    public static final int OPEN_DELETE = 0x4;
+
+    // Android-removed: initIDs() not used on Android.
+    /*
+    static {
+        /* Zip library is loaded from System.initializeSystemClass *
+        initIDs();
+    }
+
+    private static native void initIDs();
+    */
+
+    private static final boolean usemmap;
+
+    static {
+        // Android-changed: Always use mmap.
+        /*
+        // A system prpperty to disable mmap use to avoid vm crash when
+        // in-use zip file is accidently overwritten by others.
+        String prop = sun.misc.VM.getSavedProperty("sun.zip.disableMemoryMapping");
+        usemmap = (prop == null ||
+                   !(prop.length() == 0 || prop.equalsIgnoreCase("true")));
+        */
+        usemmap = true;
+    }
+
+    /**
+     * Opens a zip file for reading.
+     *
+     * <p>First, if there is a security manager, its <code>checkRead</code>
+     * method is called with the <code>name</code> argument as its argument
+     * to ensure the read is allowed.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names and comments.
+     *
+     * @param name the name of the zip file
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkRead</code> method doesn't allow read access to the file.
+     *
+     * @see SecurityManager#checkRead(java.lang.String)
+     */
+    public ZipFile(String name) throws IOException {
+        this(new File(name), OPEN_READ);
+    }
+
+    /**
+     * Opens a new <code>ZipFile</code> to read from the specified
+     * <code>File</code> object in the specified mode.  The mode argument
+     * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>.
+     *
+     * <p>First, if there is a security manager, its <code>checkRead</code>
+     * method is called with the <code>name</code> argument as its argument to
+     * ensure the read is allowed.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names and comments
+     *
+     * @param file the ZIP file to be opened for reading
+     * @param mode the mode in which the file is to be opened
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if a security manager exists and
+     *         its <code>checkRead</code> method
+     *         doesn't allow read access to the file,
+     *         or its <code>checkDelete</code> method doesn't allow deleting
+     *         the file when the <tt>OPEN_DELETE</tt> flag is set.
+     * @throws IllegalArgumentException if the <tt>mode</tt> argument is invalid
+     * @see SecurityManager#checkRead(java.lang.String)
+     * @since 1.3
+     */
+    public ZipFile(File file, int mode) throws IOException {
+        this(file, mode, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Opens a ZIP file for reading given the specified File object.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names and comments.
+     *
+     * @param file the ZIP file to be opened for reading
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     */
+    public ZipFile(File file) throws ZipException, IOException {
+        this(file, OPEN_READ);
+    }
+
+    private ZipCoder zc;
+
+    /**
+     * Opens a new <code>ZipFile</code> to read from the specified
+     * <code>File</code> object in the specified mode.  The mode argument
+     * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>.
+     *
+     * <p>First, if there is a security manager, its <code>checkRead</code>
+     * method is called with the <code>name</code> argument as its argument to
+     * ensure the read is allowed.
+     *
+     * @param file the ZIP file to be opened for reading
+     * @param mode the mode in which the file is to be opened
+     * @param charset
+     *        the {@linkplain java.nio.charset.Charset charset} to
+     *        be used to decode the ZIP entry name and comment that are not
+     *        encoded by using UTF-8 encoding (indicated by entry's general
+     *        purpose flag).
+     *
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     *
+     * @throws SecurityException
+     *         if a security manager exists and its <code>checkRead</code>
+     *         method doesn't allow read access to the file,or its
+     *         <code>checkDelete</code> method doesn't allow deleting the
+     *         file when the <tt>OPEN_DELETE</tt> flag is set
+     *
+     * @throws IllegalArgumentException if the <tt>mode</tt> argument is invalid
+     *
+     * @see SecurityManager#checkRead(java.lang.String)
+     *
+     * @since 1.7
+     */
+    public ZipFile(File file, int mode, Charset charset) throws IOException
+    {
+        if (((mode & OPEN_READ) == 0) ||
+            ((mode & ~(OPEN_READ | OPEN_DELETE)) != 0)) {
+            throw new IllegalArgumentException("Illegal mode: 0x"+
+                                               Integer.toHexString(mode));
+        }
+        String name = file.getPath();
+        // Android-removed: SecurityManager is always null
+        /*
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkRead(name);
+            if ((mode & OPEN_DELETE) != 0) {
+                sm.checkDelete(name);
+            }
+        }
+        */
+
+        // Android-added: Do not use unlink() to implement OPEN_DELETE.
+        fileToRemoveOnClose = ((mode & OPEN_DELETE) != 0) ? file : null;
+
+        if (charset == null)
+            throw new NullPointerException("charset is null");
+        this.zc = ZipCoder.get(charset);
+        // Android-removed: Skip perf counters
+        // long t0 = System.nanoTime();
+        jzfile = open(name, mode, file.lastModified(), usemmap);
+        // Android-removed: Skip perf counters
+        // sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0);
+        // sun.misc.PerfCounter.getZipFileCount().increment();
+        this.name = name;
+        this.total = getTotal(jzfile);
+        this.locsig = startsWithLOC(jzfile);
+        // Android-added: CloseGuard support
+        guard.open("close");
+    }
+
+    /**
+     * Opens a zip file for reading.
+     *
+     * <p>First, if there is a security manager, its <code>checkRead</code>
+     * method is called with the <code>name</code> argument as its argument
+     * to ensure the read is allowed.
+     *
+     * @param name the name of the zip file
+     * @param charset
+     *        the {@linkplain java.nio.charset.Charset charset} to
+     *        be used to decode the ZIP entry name and comment that are not
+     *        encoded by using UTF-8 encoding (indicated by entry's general
+     *        purpose flag).
+     *
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException
+     *         if a security manager exists and its <code>checkRead</code>
+     *         method doesn't allow read access to the file
+     *
+     * @see SecurityManager#checkRead(java.lang.String)
+     *
+     * @since 1.7
+     */
+    public ZipFile(String name, Charset charset) throws IOException
+    {
+        this(new File(name), OPEN_READ, charset);
+    }
+
+    /**
+     * Opens a ZIP file for reading given the specified File object.
+     * @param file the ZIP file to be opened for reading
+     * @param charset
+     *        The {@linkplain java.nio.charset.Charset charset} to be
+     *        used to decode the ZIP entry name and comment (ignored if
+     *        the <a href="package-summary.html#lang_encoding"> language
+     *        encoding bit</a> of the ZIP entry's general purpose bit
+     *        flag is set).
+     *
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     *
+     * @since 1.7
+     */
+    public ZipFile(File file, Charset charset) throws IOException
+    {
+        this(file, OPEN_READ, charset);
+    }
+
+    /**
+     * Returns the zip file comment, or null if none.
+     *
+     * @return the comment string for the zip file, or null if none
+     *
+     * @throws IllegalStateException if the zip file has been closed
+     *
+     * Since 1.7
+     */
+    public String getComment() {
+        synchronized (this) {
+            ensureOpen();
+            byte[] bcomm = getCommentBytes(jzfile);
+            if (bcomm == null)
+                return null;
+            return zc.toString(bcomm, bcomm.length);
+        }
+    }
+
+    /**
+     * Returns the zip file entry for the specified name, or null
+     * if not found.
+     *
+     * @param name the name of the entry
+     * @return the zip file entry, or null if not found
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public ZipEntry getEntry(String name) {
+        if (name == null) {
+            throw new NullPointerException("name");
+        }
+        long jzentry = 0;
+        synchronized (this) {
+            ensureOpen();
+            jzentry = getEntry(jzfile, zc.getBytes(name), true);
+            if (jzentry != 0) {
+                ZipEntry ze = getZipEntry(name, jzentry);
+                freeEntry(jzfile, jzentry);
+                return ze;
+            }
+        }
+        return null;
+    }
+
+    private static native long getEntry(long jzfile, byte[] name,
+                                        boolean addSlash);
+
+    // freeEntry releases the C jzentry struct.
+    private static native void freeEntry(long jzfile, long jzentry);
+
+    // the outstanding inputstreams that need to be closed,
+    // mapped to the inflater objects they use.
+    private final Map<InputStream, Inflater> streams = new WeakHashMap<>();
+
+    /**
+     * Returns an input stream for reading the contents of the specified
+     * zip file entry.
+     *
+     * <p> Closing this ZIP file will, in turn, close all input
+     * streams that have been returned by invocations of this method.
+     *
+     * @param entry the zip file entry
+     * @return the input stream for reading the contents of the specified
+     * zip file entry.
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public InputStream getInputStream(ZipEntry entry) throws IOException {
+        if (entry == null) {
+            throw new NullPointerException("entry");
+        }
+        long jzentry = 0;
+        ZipFileInputStream in = null;
+        synchronized (this) {
+            ensureOpen();
+            if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
+                // Android-changed: Find entry by name, falling back to name/ if cannot be found.
+                // Needed for ClassPathURLStreamHandler handling of URLs without trailing slashes.
+                // This was added as part of the work to move StrictJarFile from libcore to
+                // framework, see http://b/111293098 for more details.
+                // It should be possible to revert this after upgrading to OpenJDK 8u144 or above.
+                // jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), false);
+                jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), true);
+            } else {
+                // Android-changed: Find entry by name, falling back to name/ if cannot be found.
+                // jzentry = getEntry(jzfile, zc.getBytes(entry.name), false);
+                jzentry = getEntry(jzfile, zc.getBytes(entry.name), true);
+            }
+            if (jzentry == 0) {
+                return null;
+            }
+            in = new ZipFileInputStream(jzentry);
+
+            switch (getEntryMethod(jzentry)) {
+            case STORED:
+                synchronized (streams) {
+                    streams.put(in, null);
+                }
+                return in;
+            case DEFLATED:
+                // MORE: Compute good size for inflater stream:
+                long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
+                // Android-changed: Use 64k buffer size, performs better than 8k.
+                // See http://b/65491407.
+                // if (size > 65536) size = 8192;
+                if (size > 65536) size = 65536;
+                if (size <= 0) size = 4096;
+                Inflater inf = getInflater();
+                InputStream is =
+                    new ZipFileInflaterInputStream(in, inf, (int)size);
+                synchronized (streams) {
+                    streams.put(is, inf);
+                }
+                return is;
+            default:
+                throw new ZipException("invalid compression method");
+            }
+        }
+    }
+
+    private class ZipFileInflaterInputStream extends InflaterInputStream {
+        private volatile boolean closeRequested = false;
+        private boolean eof = false;
+        private final ZipFileInputStream zfin;
+
+        ZipFileInflaterInputStream(ZipFileInputStream zfin, Inflater inf,
+                int size) {
+            super(zfin, inf, size);
+            this.zfin = zfin;
+        }
+
+        public void close() throws IOException {
+            if (closeRequested)
+                return;
+            closeRequested = true;
+
+            super.close();
+            Inflater inf;
+            synchronized (streams) {
+                inf = streams.remove(this);
+            }
+            if (inf != null) {
+                releaseInflater(inf);
+            }
+        }
+
+        // Override fill() method to provide an extra "dummy" byte
+        // at the end of the input stream. This is required when
+        // using the "nowrap" Inflater option.
+        protected void fill() throws IOException {
+            if (eof) {
+                throw new EOFException("Unexpected end of ZLIB input stream");
+            }
+            len = in.read(buf, 0, buf.length);
+            if (len == -1) {
+                buf[0] = 0;
+                len = 1;
+                eof = true;
+            }
+            inf.setInput(buf, 0, len);
+        }
+
+        public int available() throws IOException {
+            if (closeRequested)
+                return 0;
+            long avail = zfin.size() - inf.getBytesWritten();
+            return (avail > (long) Integer.MAX_VALUE ?
+                    Integer.MAX_VALUE : (int) avail);
+        }
+
+        protected void finalize() throws Throwable {
+            close();
+        }
+    }
+
+    /*
+     * Gets an inflater from the list of available inflaters or allocates
+     * a new one.
+     */
+    private Inflater getInflater() {
+        Inflater inf;
+        synchronized (inflaterCache) {
+            while (null != (inf = inflaterCache.poll())) {
+                if (false == inf.ended()) {
+                    return inf;
+                }
+            }
+        }
+        return new Inflater(true);
+    }
+
+    /*
+     * Releases the specified inflater to the list of available inflaters.
+     */
+    private void releaseInflater(Inflater inf) {
+        if (false == inf.ended()) {
+            inf.reset();
+            synchronized (inflaterCache) {
+                inflaterCache.add(inf);
+            }
+        }
+    }
+
+    // List of available Inflater objects for decompression
+    private Deque<Inflater> inflaterCache = new ArrayDeque<>();
+
+    /**
+     * Returns the path name of the ZIP file.
+     * @return the path name of the ZIP file
+     */
+    public String getName() {
+        return name;
+    }
+
+    private class ZipEntryIterator implements Enumeration<ZipEntry>, Iterator<ZipEntry> {
+        private int i = 0;
+
+        public ZipEntryIterator() {
+            ensureOpen();
+        }
+
+        public boolean hasMoreElements() {
+            return hasNext();
+        }
+
+        public boolean hasNext() {
+            synchronized (ZipFile.this) {
+                ensureOpen();
+                return i < total;
+            }
+        }
+
+        public ZipEntry nextElement() {
+            return next();
+        }
+
+        public ZipEntry next() {
+            synchronized (ZipFile.this) {
+                ensureOpen();
+                if (i >= total) {
+                    throw new NoSuchElementException();
+                }
+                long jzentry = getNextEntry(jzfile, i++);
+                if (jzentry == 0) {
+                    String message;
+                    if (closeRequested) {
+                        message = "ZipFile concurrently closed";
+                    } else {
+                        message = getZipMessage(ZipFile.this.jzfile);
+                    }
+                    throw new ZipError("jzentry == 0" +
+                                       ",\n jzfile = " + ZipFile.this.jzfile +
+                                       ",\n total = " + ZipFile.this.total +
+                                       ",\n name = " + ZipFile.this.name +
+                                       ",\n i = " + i +
+                                       ",\n message = " + message
+                        );
+                }
+                ZipEntry ze = getZipEntry(null, jzentry);
+                freeEntry(jzfile, jzentry);
+                return ze;
+            }
+        }
+    }
+
+    /**
+     * Returns an enumeration of the ZIP file entries.
+     * @return an enumeration of the ZIP file entries
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public Enumeration<? extends ZipEntry> entries() {
+        return new ZipEntryIterator();
+    }
+
+    /**
+     * Return an ordered {@code Stream} over the ZIP file entries.
+     * Entries appear in the {@code Stream} in the order they appear in
+     * the central directory of the ZIP file.
+     *
+     * @return an ordered {@code Stream} of entries in this ZIP file
+     * @throws IllegalStateException if the zip file has been closed
+     * @since 1.8
+     */
+    public Stream<? extends ZipEntry> stream() {
+        return StreamSupport.stream(Spliterators.spliterator(
+                new ZipEntryIterator(), size(),
+                Spliterator.ORDERED | Spliterator.DISTINCT |
+                        Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
+    }
+
+    private ZipEntry getZipEntry(String name, long jzentry) {
+        ZipEntry e = new ZipEntry();
+        e.flag = getEntryFlag(jzentry);  // get the flag first
+        if (name != null) {
+            e.name = name;
+        } else {
+            byte[] bname = getEntryBytes(jzentry, JZENTRY_NAME);
+            if (!zc.isUTF8() && (e.flag & EFS) != 0) {
+                e.name = zc.toStringUTF8(bname, bname.length);
+            } else {
+                e.name = zc.toString(bname, bname.length);
+            }
+        }
+        e.xdostime = getEntryTime(jzentry);
+        e.crc = getEntryCrc(jzentry);
+        e.size = getEntrySize(jzentry);
+        e.csize = getEntryCSize(jzentry);
+        e.method = getEntryMethod(jzentry);
+        e.setExtra0(getEntryBytes(jzentry, JZENTRY_EXTRA), false);
+        byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT);
+        if (bcomm == null) {
+            e.comment = null;
+        } else {
+            if (!zc.isUTF8() && (e.flag & EFS) != 0) {
+                e.comment = zc.toStringUTF8(bcomm, bcomm.length);
+            } else {
+                e.comment = zc.toString(bcomm, bcomm.length);
+            }
+        }
+        return e;
+    }
+
+    private static native long getNextEntry(long jzfile, int i);
+
+    /**
+     * Returns the number of entries in the ZIP file.
+     * @return the number of entries in the ZIP file
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public int size() {
+        ensureOpen();
+        return total;
+    }
+
+    /**
+     * Closes the ZIP file.
+     * <p> Closing this ZIP file will close all of the input streams
+     * previously returned by invocations of the {@link #getInputStream
+     * getInputStream} method.
+     *
+     * @throws IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (closeRequested)
+            return;
+        // Android-added: CloseGuard support
+        if (guard != null) {
+            guard.close();
+        }
+        closeRequested = true;
+
+        synchronized (this) {
+            // Close streams, release their inflaters
+            // BEGIN Android-added: null field check to avoid NullPointerException during finalize.
+            // If the constructor threw an exception then the streams / inflaterCache fields can
+            // be null and close() can be called by the finalizer.
+            if (streams != null) {
+            // END Android-added: null field check to avoid NullPointerException during finalize.
+                synchronized (streams) {
+                    if (false == streams.isEmpty()) {
+                        Map<InputStream, Inflater> copy = new HashMap<>(streams);
+                        streams.clear();
+                        for (Map.Entry<InputStream, Inflater> e : copy.entrySet()) {
+                            e.getKey().close();
+                            Inflater inf = e.getValue();
+                            if (inf != null) {
+                                inf.end();
+                            }
+                        }
+                    }
+                }
+            // BEGIN Android-added: null field check to avoid NullPointerException during finalize.
+            }
+
+            if (inflaterCache != null) {
+            // END Android-added: null field check to avoid NullPointerException during finalize.
+                // Release cached inflaters
+                Inflater inf;
+                synchronized (inflaterCache) {
+                    while (null != (inf = inflaterCache.poll())) {
+                        inf.end();
+                    }
+                }
+            // BEGIN Android-added: null field check to avoid NullPointerException during finalize.
+            }
+            // END Android-added: null field check to avoid NullPointerException during finalize.
+
+            if (jzfile != 0) {
+                // Close the zip file
+                long zf = this.jzfile;
+                jzfile = 0;
+
+                close(zf);
+            }
+            // Android-added: Do not use unlink() to implement OPEN_DELETE.
+            if (fileToRemoveOnClose != null) {
+                fileToRemoveOnClose.delete();
+            }
+        }
+    }
+
+    /**
+     * Ensures that the system resources held by this ZipFile object are
+     * released when there are no more references to it.
+     *
+     * <p>
+     * Since the time when GC would invoke this method is undetermined,
+     * it is strongly recommended that applications invoke the <code>close</code>
+     * method as soon they have finished accessing this <code>ZipFile</code>.
+     * This will prevent holding up system resources for an undetermined
+     * length of time.
+     *
+     * @throws IOException if an I/O error has occurred
+     * @see    java.util.zip.ZipFile#close()
+     */
+    protected void finalize() throws IOException {
+        // Android-added: CloseGuard support
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+        close();
+    }
+
+    private static native void close(long jzfile);
+
+    private void ensureOpen() {
+        if (closeRequested) {
+            throw new IllegalStateException("zip file closed");
+        }
+
+        if (jzfile == 0) {
+            throw new IllegalStateException("The object is not initialized.");
+        }
+    }
+
+    private void ensureOpenOrZipException() throws IOException {
+        if (closeRequested) {
+            throw new ZipException("ZipFile closed");
+        }
+    }
+
+    /*
+     * Inner class implementing the input stream used to read a
+     * (possibly compressed) zip file entry.
+     */
+   private class ZipFileInputStream extends InputStream {
+        private volatile boolean zfisCloseRequested = false;
+        protected long jzentry; // address of jzentry data
+        private   long pos;     // current position within entry data
+        protected long rem;     // number of remaining bytes within entry
+        protected long size;    // uncompressed size of this entry
+
+        ZipFileInputStream(long jzentry) {
+            pos = 0;
+            rem = getEntryCSize(jzentry);
+            size = getEntrySize(jzentry);
+            this.jzentry = jzentry;
+        }
+
+        public int read(byte b[], int off, int len) throws IOException {
+            // Android-added: Always throw an exception when reading from closed zipfile.
+            // Required by the JavaDoc for InputStream.read(byte[], int, int). Upstream version
+            // 8u121-b13 is not compliant but that bug has been fixed in upstream version 9+181
+            // as part of a major change to switch to a pure Java implementation.
+            // See https://bugs.openjdk.java.net/browse/JDK-8145260 and
+            // https://bugs.openjdk.java.net/browse/JDK-8142508.
+            ensureOpenOrZipException();
+
+            synchronized (ZipFile.this) {
+                long rem = this.rem;
+                long pos = this.pos;
+                if (rem == 0) {
+                    return -1;
+                }
+                if (len <= 0) {
+                    return 0;
+                }
+                if (len > rem) {
+                    len = (int) rem;
+                }
+
+                // Android-removed: Always throw an exception when reading from closed zipfile.
+                // Moved to the start of the method.
+                //ensureOpenOrZipException();
+                len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b,
+                                   off, len);
+                if (len > 0) {
+                    this.pos = (pos + len);
+                    this.rem = (rem - len);
+                }
+            }
+            if (rem == 0) {
+                close();
+            }
+            return len;
+        }
+
+        public int read() throws IOException {
+            byte[] b = new byte[1];
+            if (read(b, 0, 1) == 1) {
+                return b[0] & 0xff;
+            } else {
+                return -1;
+            }
+        }
+
+        public long skip(long n) {
+            if (n > rem)
+                n = rem;
+            pos += n;
+            rem -= n;
+            if (rem == 0) {
+                close();
+            }
+            return n;
+        }
+
+        public int available() {
+            return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem;
+        }
+
+        public long size() {
+            return size;
+        }
+
+        public void close() {
+            if (zfisCloseRequested)
+                return;
+            zfisCloseRequested = true;
+
+            rem = 0;
+            synchronized (ZipFile.this) {
+                if (jzentry != 0 && ZipFile.this.jzfile != 0) {
+                    freeEntry(ZipFile.this.jzfile, jzentry);
+                    jzentry = 0;
+                }
+            }
+            synchronized (streams) {
+                streams.remove(this);
+            }
+        }
+
+        protected void finalize() {
+            close();
+        }
+    }
+
+    // Android-removed: Access startsWithLocHeader() directly.
+    /*
+    static {
+        sun.misc.SharedSecrets.setJavaUtilZipFileAccess(
+            new sun.misc.JavaUtilZipFileAccess() {
+                public boolean startsWithLocHeader(ZipFile zip) {
+                    return zip.startsWithLocHeader();
+                }
+             }
+        );
+    }
+    */
+
+    /**
+     * Returns {@code true} if, and only if, the zip file begins with {@code
+     * LOCSIG}.
+     * @hide
+     */
+    // Android-changed: Access startsWithLocHeader() directly.
+    // Make hidden public for use by sun.misc.URLClassPath
+    // private boolean startsWithLocHeader() {
+    public boolean startsWithLocHeader() {
+        return locsig;
+    }
+
+    // BEGIN Android-added: Provide access to underlying file descriptor for testing.
+    // See http://b/111148957 for background information.
+    /** @hide */
+    // @VisibleForTesting
+    public int getFileDescriptor() {
+        return getFileDescriptor(jzfile);
+    }
+
+    private static native int getFileDescriptor(long jzfile);
+    // END Android-added: Provide access to underlying file descriptor for testing.
+
+    private static native long open(String name, int mode, long lastModified,
+                                    boolean usemmap) throws IOException;
+    private static native int getTotal(long jzfile);
+    private static native boolean startsWithLOC(long jzfile);
+    private static native int read(long jzfile, long jzentry,
+                                   long pos, byte[] b, int off, int len);
+
+    // access to the native zentry object
+    private static native long getEntryTime(long jzentry);
+    private static native long getEntryCrc(long jzentry);
+    private static native long getEntryCSize(long jzentry);
+    private static native long getEntrySize(long jzentry);
+    private static native int getEntryMethod(long jzentry);
+    private static native int getEntryFlag(long jzentry);
+    private static native byte[] getCommentBytes(long jzfile);
+
+    private static final int JZENTRY_NAME = 0;
+    private static final int JZENTRY_EXTRA = 1;
+    private static final int JZENTRY_COMMENT = 2;
+    private static native byte[] getEntryBytes(long jzentry, int type);
+
+    private static native String getZipMessage(long jzfile);
+}
diff --git a/java/util/zip/ZipInputStream.java b/java/util/zip/ZipInputStream.java
new file mode 100644
index 0000000..aaebb49
--- /dev/null
+++ b/java/util/zip/ZipInputStream.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import java.io.PushbackInputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
+
+/**
+ * This class implements an input stream filter for reading files in the
+ * ZIP file format. Includes support for both compressed and uncompressed
+ * entries.
+ *
+ * @author      David Connelly
+ */
+public
+class ZipInputStream extends InflaterInputStream implements ZipConstants {
+    private ZipEntry entry;
+    private int flag;
+    private CRC32 crc = new CRC32();
+    private long remaining;
+    private byte[] tmpbuf = new byte[512];
+
+    private static final int STORED = ZipEntry.STORED;
+    private static final int DEFLATED = ZipEntry.DEFLATED;
+
+    private boolean closed = false;
+    // this flag is set to true after EOF has reached for
+    // one entry
+    private boolean entryEOF = false;
+
+    private ZipCoder zc;
+
+    /**
+     * Check to make sure that this stream has not been closed
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new ZIP input stream.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names.
+     *
+     * @param in the actual input stream
+     */
+    public ZipInputStream(InputStream in) {
+        this(in, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Creates a new ZIP input stream.
+     *
+     * @param in the actual input stream
+     *
+     * @param charset
+     *        The {@linkplain java.nio.charset.Charset charset} to be
+     *        used to decode the ZIP entry name (ignored if the
+     *        <a href="package-summary.html#lang_encoding"> language
+     *        encoding bit</a> of the ZIP entry's general purpose bit
+     *        flag is set).
+     *
+     * @since 1.7
+     */
+    public ZipInputStream(InputStream in, Charset charset) {
+        super(new PushbackInputStream(in, 512), new Inflater(true), 512);
+        // Android-changed: Unconditionally close external inflaters (b/26462400)
+        // usesDefaultInflater = true;
+        if(in == null) {
+            throw new NullPointerException("in is null");
+        }
+        if (charset == null)
+            throw new NullPointerException("charset is null");
+        this.zc = ZipCoder.get(charset);
+    }
+
+    /**
+     * Reads the next ZIP file entry and positions the stream at the
+     * beginning of the entry data.
+     * @return the next ZIP file entry, or null if there are no more entries
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public ZipEntry getNextEntry() throws IOException {
+        ensureOpen();
+        if (entry != null) {
+            closeEntry();
+        }
+        crc.reset();
+        inf.reset();
+        if ((entry = readLOC()) == null) {
+            return null;
+        }
+        // Android-changed: Return more accurate value from available().
+        // Initialize the remaining field with the number of bytes that can be read from the entry
+        // for both uncompressed and compressed entries so that it can be used to provide a more
+        // accurate return value for available().
+        // if (entry.method == STORED) {
+        if (entry.method == STORED || entry.method == DEFLATED) {
+            remaining = entry.size;
+        }
+        entryEOF = false;
+        return entry;
+    }
+
+    /**
+     * Closes the current ZIP entry and positions the stream for reading the
+     * next entry.
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public void closeEntry() throws IOException {
+        ensureOpen();
+        while (read(tmpbuf, 0, tmpbuf.length) != -1) ;
+        entryEOF = true;
+    }
+
+    /**
+     * Returns 0 after EOF has reached for the current entry data,
+     * otherwise always return 1.
+     * <p>
+     * Programs should not count on this method to return the actual number
+     * of bytes that could be read without blocking.
+     *
+     * @return     1 before EOF and 0 after EOF has reached for current entry.
+     * @exception  IOException  if an I/O error occurs.
+     *
+     */
+    public int available() throws IOException {
+        ensureOpen();
+        // Android-changed: Return more accurate value from available().
+        // Tracks the remaining bytes in order to return a more accurate value for the available
+        // bytes. Given an entry of size N both Android and upstream will return 1 until N bytes
+        // have been read at which point Android will return 0 and upstream will return 1.
+        // Upstream will only return 0 after an attempt to read a byte fails because the EOF has
+        // been reached. See http://b/111439440 for more details.
+        // if (entryEOF) {
+        if (entryEOF || (entry != null && remaining == 0)) {
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    /**
+     * Reads from the current ZIP entry into an array of bytes.
+     * If <code>len</code> is not zero, the method
+     * blocks until some input is available; otherwise, no
+     * bytes are read and <code>0</code> is returned.
+     * @param b the buffer into which the data is read
+     * @param off the start offset in the destination array <code>b</code>
+     * @param len the maximum number of bytes read
+     * @return the actual number of bytes read, or -1 if the end of the
+     *         entry is reached
+     * @exception  NullPointerException if <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException if <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        ensureOpen();
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        if (entry == null) {
+            return -1;
+        }
+        switch (entry.method) {
+        case DEFLATED:
+            len = super.read(b, off, len);
+            if (len == -1) {
+                readEnd(entry);
+                entryEOF = true;
+                entry = null;
+            } else {
+                crc.update(b, off, len);
+                // Android-added: Return more accurate value from available().
+                // Update the remaining field so it is an accurate count of the number of bytes
+                // remaining in this stream, after deflation.
+                remaining -= len;
+            }
+            return len;
+        case STORED:
+            if (remaining <= 0) {
+                entryEOF = true;
+                entry = null;
+                return -1;
+            }
+            if (len > remaining) {
+                len = (int)remaining;
+            }
+            len = in.read(b, off, len);
+            if (len == -1) {
+                throw new ZipException("unexpected EOF");
+            }
+            crc.update(b, off, len);
+            remaining -= len;
+            if (remaining == 0 && entry.crc != crc.getValue()) {
+                throw new ZipException(
+                    "invalid entry CRC (expected 0x" + Long.toHexString(entry.crc) +
+                    " but got 0x" + Long.toHexString(crc.getValue()) + ")");
+            }
+            return len;
+        default:
+            throw new ZipException("invalid compression method");
+        }
+    }
+
+    /**
+     * Skips specified number of bytes in the current ZIP entry.
+     * @param n the number of bytes to skip
+     * @return the actual number of bytes skipped
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     * @exception IllegalArgumentException if {@code n < 0}
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0) {
+            throw new IllegalArgumentException("negative skip length");
+        }
+        ensureOpen();
+        int max = (int)Math.min(n, Integer.MAX_VALUE);
+        int total = 0;
+        while (total < max) {
+            int len = max - total;
+            if (len > tmpbuf.length) {
+                len = tmpbuf.length;
+            }
+            len = read(tmpbuf, 0, len);
+            if (len == -1) {
+                entryEOF = true;
+                break;
+            }
+            total += len;
+        }
+        return total;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources associated
+     * with the stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            super.close();
+            closed = true;
+        }
+    }
+
+    private byte[] b = new byte[256];
+
+    /*
+     * Reads local file (LOC) header for next entry.
+     */
+    private ZipEntry readLOC() throws IOException {
+        try {
+            readFully(tmpbuf, 0, LOCHDR);
+        } catch (EOFException e) {
+            return null;
+        }
+        if (get32(tmpbuf, 0) != LOCSIG) {
+            return null;
+        }
+        // get flag first, we need check EFS.
+        flag = get16(tmpbuf, LOCFLG);
+        // get the entry name and create the ZipEntry first
+        int len = get16(tmpbuf, LOCNAM);
+        int blen = b.length;
+        if (len > blen) {
+            do {
+                blen = blen * 2;
+            } while (len > blen);
+            b = new byte[blen];
+        }
+        readFully(b, 0, len);
+        // Force to use UTF-8 if the EFS bit is ON, even the cs is NOT UTF-8
+        ZipEntry e = createZipEntry(((flag & EFS) != 0)
+                                    ? zc.toStringUTF8(b, len)
+                                    : zc.toString(b, len));
+        // now get the remaining fields for the entry
+        if ((flag & 1) == 1) {
+            throw new ZipException("encrypted ZIP entry not supported");
+        }
+        e.method = get16(tmpbuf, LOCHOW);
+        e.xdostime = get32(tmpbuf, LOCTIM);
+        if ((flag & 8) == 8) {
+            // Android-Changed: Remove the requirement that only DEFLATED entries
+            // can have data descriptors. This is not required by the ZIP spec and
+            // is inconsistent with the behaviour of ZipFile and versions of Android
+            // prior to Android N.
+            //
+            // /* "Data Descriptor" present */
+            // if (e.method != DEFLATED) {
+            //     throw new ZipException(
+            //             "only DEFLATED entries can have EXT descriptor");
+            // }
+        } else {
+            e.crc = get32(tmpbuf, LOCCRC);
+            e.csize = get32(tmpbuf, LOCSIZ);
+            e.size = get32(tmpbuf, LOCLEN);
+        }
+        len = get16(tmpbuf, LOCEXT);
+        if (len > 0) {
+            byte[] extra = new byte[len];
+            readFully(extra, 0, len);
+            e.setExtra0(extra,
+                        e.csize == ZIP64_MAGICVAL || e.size == ZIP64_MAGICVAL);
+        }
+        return e;
+    }
+
+    /**
+     * Creates a new <code>ZipEntry</code> object for the specified
+     * entry name.
+     *
+     * @param name the ZIP file entry name
+     * @return the ZipEntry just created
+     */
+    protected ZipEntry createZipEntry(String name) {
+        return new ZipEntry(name);
+    }
+
+    /*
+     * Reads end of deflated entry as well as EXT descriptor if present.
+     */
+    private void readEnd(ZipEntry e) throws IOException {
+        int n = inf.getRemaining();
+        if (n > 0) {
+            ((PushbackInputStream)in).unread(buf, len - n, n);
+        }
+        if ((flag & 8) == 8) {
+            /* "Data Descriptor" present */
+            if (inf.getBytesWritten() > ZIP64_MAGICVAL ||
+                inf.getBytesRead() > ZIP64_MAGICVAL) {
+                // ZIP64 format
+                readFully(tmpbuf, 0, ZIP64_EXTHDR);
+                long sig = get32(tmpbuf, 0);
+                if (sig != EXTSIG) { // no EXTSIG present
+                    e.crc = sig;
+                    e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC);
+                    e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC);
+                    ((PushbackInputStream)in).unread(
+                        tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC - 1, ZIP64_EXTCRC);
+                } else {
+                    e.crc = get32(tmpbuf, ZIP64_EXTCRC);
+                    e.csize = get64(tmpbuf, ZIP64_EXTSIZ);
+                    e.size = get64(tmpbuf, ZIP64_EXTLEN);
+                }
+            } else {
+                readFully(tmpbuf, 0, EXTHDR);
+                long sig = get32(tmpbuf, 0);
+                if (sig != EXTSIG) { // no EXTSIG present
+                    e.crc = sig;
+                    e.csize = get32(tmpbuf, EXTSIZ - EXTCRC);
+                    e.size = get32(tmpbuf, EXTLEN - EXTCRC);
+                    ((PushbackInputStream)in).unread(
+                                               tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC);
+                } else {
+                    e.crc = get32(tmpbuf, EXTCRC);
+                    e.csize = get32(tmpbuf, EXTSIZ);
+                    e.size = get32(tmpbuf, EXTLEN);
+                }
+            }
+        }
+        if (e.size != inf.getBytesWritten()) {
+            throw new ZipException(
+                "invalid entry size (expected " + e.size +
+                " but got " + inf.getBytesWritten() + " bytes)");
+        }
+        if (e.csize != inf.getBytesRead()) {
+            throw new ZipException(
+                "invalid entry compressed size (expected " + e.csize +
+                " but got " + inf.getBytesRead() + " bytes)");
+        }
+        if (e.crc != crc.getValue()) {
+            throw new ZipException(
+                "invalid entry CRC (expected 0x" + Long.toHexString(e.crc) +
+                " but got 0x" + Long.toHexString(crc.getValue()) + ")");
+        }
+    }
+
+    /*
+     * Reads bytes, blocking until all bytes are read.
+     */
+    private void readFully(byte[] b, int off, int len) throws IOException {
+        while (len > 0) {
+            int n = in.read(b, off, len);
+            if (n == -1) {
+                throw new EOFException();
+            }
+            off += n;
+            len -= n;
+        }
+    }
+
+}
diff --git a/java/util/zip/ZipOutputStream.java b/java/util/zip/ZipOutputStream.java
new file mode 100644
index 0000000..dd005ec
--- /dev/null
+++ b/java/util/zip/ZipOutputStream.java
@@ -0,0 +1,752 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Vector;
+import java.util.HashSet;
+import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
+
+/**
+ * This class implements an output stream filter for writing files in the
+ * ZIP file format. Includes support for both compressed and uncompressed
+ * entries.
+ *
+ * @author      David Connelly
+ */
+public
+class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
+
+    /**
+     * Whether to use ZIP64 for zip files with more than 64k entries.
+     * Until ZIP64 support in zip implementations is ubiquitous, this
+     * system property allows the creation of zip files which can be
+     * read by legacy zip implementations which tolerate "incorrect"
+     * total entry count fields, such as the ones in jdk6, and even
+     * some in jdk7.
+     */
+    // Android-changed: Always allow use of Zip64.
+    private static final boolean inhibitZip64 = false;
+    //  Boolean.parseBoolean(
+    //      java.security.AccessController.doPrivileged(
+    //          new sun.security.action.GetPropertyAction(
+    //              "jdk.util.zip.inhibitZip64", "false")));
+
+    private static class XEntry {
+        final ZipEntry entry;
+        final long offset;
+        public XEntry(ZipEntry entry, long offset) {
+            this.entry = entry;
+            this.offset = offset;
+        }
+    }
+
+    private XEntry current;
+    private Vector<XEntry> xentries = new Vector<>();
+    private HashSet<String> names = new HashSet<>();
+    private CRC32 crc = new CRC32();
+    private long written = 0;
+    private long locoff = 0;
+    private byte[] comment;
+    private int method = DEFLATED;
+    private boolean finished;
+
+    private boolean closed = false;
+
+    private final ZipCoder zc;
+
+    private static int version(ZipEntry e) throws ZipException {
+        switch (e.method) {
+        case DEFLATED: return 20;
+        case STORED:   return 10;
+        default: throw new ZipException("unsupported compression method");
+        }
+    }
+
+    /**
+     * Checks to make sure that this stream has not been closed.
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+    /**
+     * Compression method for uncompressed (STORED) entries.
+     */
+    public static final int STORED = ZipEntry.STORED;
+
+    /**
+     * Compression method for compressed (DEFLATED) entries.
+     */
+    public static final int DEFLATED = ZipEntry.DEFLATED;
+
+    /**
+     * Creates a new ZIP output stream.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used
+     * to encode the entry names and comments.
+     *
+     * @param out the actual output stream
+     */
+    public ZipOutputStream(OutputStream out) {
+        this(out, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Creates a new ZIP output stream.
+     *
+     * @param out the actual output stream
+     *
+     * @param charset the {@linkplain java.nio.charset.Charset charset}
+     *                to be used to encode the entry names and comments
+     *
+     * @since 1.7
+     */
+    public ZipOutputStream(OutputStream out, Charset charset) {
+        super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
+        if (charset == null)
+            throw new NullPointerException("charset is null");
+        this.zc = ZipCoder.get(charset);
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Sets the ZIP file comment.
+     * @param comment the comment string
+     * @exception IllegalArgumentException if the length of the specified
+     *            ZIP file comment is greater than 0xFFFF bytes
+     */
+    public void setComment(String comment) {
+        if (comment != null) {
+            this.comment = zc.getBytes(comment);
+            if (this.comment.length > 0xffff)
+                throw new IllegalArgumentException("ZIP file comment too long.");
+        }
+    }
+
+    /**
+     * Sets the default compression method for subsequent entries. This
+     * default will be used whenever the compression method is not specified
+     * for an individual ZIP file entry, and is initially set to DEFLATED.
+     * @param method the default compression method
+     * @exception IllegalArgumentException if the specified compression method
+     *            is invalid
+     */
+    public void setMethod(int method) {
+        if (method != DEFLATED && method != STORED) {
+            throw new IllegalArgumentException("invalid compression method");
+        }
+        this.method = method;
+    }
+
+    /**
+     * Sets the compression level for subsequent entries which are DEFLATED.
+     * The default setting is DEFAULT_COMPRESSION.
+     * @param level the compression level (0-9)
+     * @exception IllegalArgumentException if the compression level is invalid
+     */
+    public void setLevel(int level) {
+        def.setLevel(level);
+    }
+
+    /**
+     * Begins writing a new ZIP file entry and positions the stream to the
+     * start of the entry data. Closes the current entry if still active.
+     * The default compression method will be used if no compression method
+     * was specified for the entry, and the current time will be used if
+     * the entry has no set modification time.
+     * @param e the ZIP entry to be written
+     * @exception ZipException if a ZIP format error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public void putNextEntry(ZipEntry e) throws IOException {
+        ensureOpen();
+        if (current != null) {
+            closeEntry();       // close previous entry
+        }
+        if (e.xdostime == -1) {
+            // by default, do NOT use extended timestamps in extra
+            // data, for now.
+            e.setTime(System.currentTimeMillis());
+        }
+        if (e.method == -1) {
+            e.method = method;  // use default method
+        }
+        // store size, compressed size, and crc-32 in LOC header
+        e.flag = 0;
+        switch (e.method) {
+        case DEFLATED:
+            // store size, compressed size, and crc-32 in data descriptor
+            // immediately following the compressed entry data
+            if (e.size  == -1 || e.csize == -1 || e.crc   == -1)
+                e.flag = 8;
+
+            break;
+        case STORED:
+            // compressed size, uncompressed size, and crc-32 must all be
+            // set for entries using STORED compression method
+            if (e.size == -1) {
+                e.size = e.csize;
+            } else if (e.csize == -1) {
+                e.csize = e.size;
+            } else if (e.size != e.csize) {
+                throw new ZipException(
+                    "STORED entry where compressed != uncompressed size");
+            }
+            if (e.size == -1 || e.crc == -1) {
+                throw new ZipException(
+                    "STORED entry missing size, compressed size, or crc-32");
+            }
+            break;
+        default:
+            throw new ZipException("unsupported compression method");
+        }
+        if (! names.add(e.name)) {
+            throw new ZipException("duplicate entry: " + e.name);
+        }
+        if (zc.isUTF8())
+            e.flag |= EFS;
+        current = new XEntry(e, written);
+        xentries.add(current);
+        writeLOC(current);
+    }
+
+    /**
+     * Closes the current ZIP entry and positions the stream for writing
+     * the next entry.
+     * @exception ZipException if a ZIP format error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public void closeEntry() throws IOException {
+        ensureOpen();
+        if (current != null) {
+            ZipEntry e = current.entry;
+            switch (e.method) {
+            case DEFLATED:
+                def.finish();
+                while (!def.finished()) {
+                    deflate();
+                }
+                if ((e.flag & 8) == 0) {
+                    // verify size, compressed size, and crc-32 settings
+                    if (e.size != def.getBytesRead()) {
+                        throw new ZipException(
+                            "invalid entry size (expected " + e.size +
+                            " but got " + def.getBytesRead() + " bytes)");
+                    }
+                    if (e.csize != def.getBytesWritten()) {
+                        throw new ZipException(
+                            "invalid entry compressed size (expected " +
+                            e.csize + " but got " + def.getBytesWritten() + " bytes)");
+                    }
+                    if (e.crc != crc.getValue()) {
+                        throw new ZipException(
+                            "invalid entry CRC-32 (expected 0x" +
+                            Long.toHexString(e.crc) + " but got 0x" +
+                            Long.toHexString(crc.getValue()) + ")");
+                    }
+                } else {
+                    e.size  = def.getBytesRead();
+                    e.csize = def.getBytesWritten();
+                    e.crc = crc.getValue();
+                    writeEXT(e);
+                }
+                def.reset();
+                written += e.csize;
+                break;
+            case STORED:
+                // we already know that both e.size and e.csize are the same
+                if (e.size != written - locoff) {
+                    throw new ZipException(
+                        "invalid entry size (expected " + e.size +
+                        " but got " + (written - locoff) + " bytes)");
+                }
+                if (e.crc != crc.getValue()) {
+                    throw new ZipException(
+                         "invalid entry crc-32 (expected 0x" +
+                         Long.toHexString(e.crc) + " but got 0x" +
+                         Long.toHexString(crc.getValue()) + ")");
+                }
+                break;
+            default:
+                throw new ZipException("invalid compression method");
+            }
+            crc.reset();
+            current = null;
+        }
+    }
+
+    /**
+     * Writes an array of bytes to the current ZIP entry data. This method
+     * will block until all the bytes are written.
+     * @param b the data to be written
+     * @param off the start offset in the data
+     * @param len the number of bytes that are written
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public synchronized void write(byte[] b, int off, int len)
+        throws IOException
+    {
+        ensureOpen();
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+
+        if (current == null) {
+            throw new ZipException("no current ZIP entry");
+        }
+        ZipEntry entry = current.entry;
+        switch (entry.method) {
+        case DEFLATED:
+            super.write(b, off, len);
+            break;
+        case STORED:
+            written += len;
+            if (written - locoff > entry.size) {
+                throw new ZipException(
+                    "attempt to write past end of STORED entry");
+            }
+            out.write(b, off, len);
+            break;
+        default:
+            throw new ZipException("invalid compression method");
+        }
+        crc.update(b, off, len);
+    }
+
+    /**
+     * Finishes writing the contents of the ZIP output stream without closing
+     * the underlying stream. Use this method when applying multiple filters
+     * in succession to the same output stream.
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O exception has occurred
+     */
+    public void finish() throws IOException {
+        ensureOpen();
+        if (finished) {
+            return;
+        }
+        if (current != null) {
+            closeEntry();
+        }
+        // write central directory
+        long off = written;
+        for (XEntry xentry : xentries)
+            writeCEN(xentry);
+        writeEND(off, written - off);
+        finished = true;
+    }
+
+    /**
+     * Closes the ZIP output stream as well as the stream being filtered.
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            super.close();
+            closed = true;
+        }
+    }
+
+    /*
+     * Writes local file (LOC) header for specified entry.
+     */
+    private void writeLOC(XEntry xentry) throws IOException {
+        ZipEntry e = xentry.entry;
+        int flag = e.flag;
+        boolean hasZip64 = false;
+        int elen = getExtraLen(e.extra);
+
+        writeInt(LOCSIG);               // LOC header signature
+        if ((flag & 8) == 8) {
+            writeShort(version(e));     // version needed to extract
+            writeShort(flag);           // general purpose bit flag
+            writeShort(e.method);       // compression method
+            writeInt(e.xdostime);       // last modification time
+            // store size, uncompressed size, and crc-32 in data descriptor
+            // immediately following compressed entry data
+            writeInt(0);
+            writeInt(0);
+            writeInt(0);
+        } else {
+            if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
+                hasZip64 = true;
+                writeShort(45);         // ver 4.5 for zip64
+            } else {
+                writeShort(version(e)); // version needed to extract
+            }
+            writeShort(flag);           // general purpose bit flag
+            writeShort(e.method);       // compression method
+            writeInt(e.xdostime);       // last modification time
+            writeInt(e.crc);            // crc-32
+            if (hasZip64) {
+                writeInt(ZIP64_MAGICVAL);
+                writeInt(ZIP64_MAGICVAL);
+                elen += 20;        //headid(2) + size(2) + size(8) + csize(8)
+            } else {
+                writeInt(e.csize);  // compressed size
+                writeInt(e.size);   // uncompressed size
+            }
+        }
+        byte[] nameBytes = zc.getBytes(e.name);
+        writeShort(nameBytes.length);
+
+        int elenEXTT = 0;               // info-zip extended timestamp
+        int flagEXTT = 0;
+        if (e.mtime != null) {
+            elenEXTT += 4;
+            flagEXTT |= EXTT_FLAG_LMT;
+        }
+        if (e.atime != null) {
+            elenEXTT += 4;
+            flagEXTT |= EXTT_FLAG_LAT;
+        }
+        if (e.ctime != null) {
+            elenEXTT += 4;
+            flagEXTT |= EXTT_FLAT_CT;
+        }
+        if (flagEXTT != 0)
+            elen += (elenEXTT + 5);    // headid(2) + size(2) + flag(1) + data
+        writeShort(elen);
+        writeBytes(nameBytes, 0, nameBytes.length);
+        if (hasZip64) {
+            writeShort(ZIP64_EXTID);
+            writeShort(16);
+            writeLong(e.size);
+            writeLong(e.csize);
+        }
+        if (flagEXTT != 0) {
+            writeShort(EXTID_EXTT);
+            writeShort(elenEXTT + 1);      // flag + data
+            writeByte(flagEXTT);
+            if (e.mtime != null)
+                writeInt(fileTimeToUnixTime(e.mtime));
+            if (e.atime != null)
+                writeInt(fileTimeToUnixTime(e.atime));
+            if (e.ctime != null)
+                writeInt(fileTimeToUnixTime(e.ctime));
+        }
+        writeExtra(e.extra);
+        locoff = written;
+    }
+
+    /*
+     * Writes extra data descriptor (EXT) for specified entry.
+     */
+    private void writeEXT(ZipEntry e) throws IOException {
+        writeInt(EXTSIG);           // EXT header signature
+        writeInt(e.crc);            // crc-32
+        if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
+            writeLong(e.csize);
+            writeLong(e.size);
+        } else {
+            writeInt(e.csize);          // compressed size
+            writeInt(e.size);           // uncompressed size
+        }
+    }
+
+    /*
+     * Write central directory (CEN) header for specified entry.
+     * REMIND: add support for file attributes
+     */
+    private void writeCEN(XEntry xentry) throws IOException {
+        ZipEntry e  = xentry.entry;
+        int flag = e.flag;
+        int version = version(e);
+        long csize = e.csize;
+        long size = e.size;
+        long offset = xentry.offset;
+        int elenZIP64 = 0;
+        boolean hasZip64 = false;
+
+        if (e.csize >= ZIP64_MAGICVAL) {
+            csize = ZIP64_MAGICVAL;
+            elenZIP64 += 8;              // csize(8)
+            hasZip64 = true;
+        }
+        if (e.size >= ZIP64_MAGICVAL) {
+            size = ZIP64_MAGICVAL;    // size(8)
+            elenZIP64 += 8;
+            hasZip64 = true;
+        }
+        if (xentry.offset >= ZIP64_MAGICVAL) {
+            offset = ZIP64_MAGICVAL;
+            elenZIP64 += 8;              // offset(8)
+            hasZip64 = true;
+        }
+        writeInt(CENSIG);           // CEN header signature
+        if (hasZip64) {
+            writeShort(45);         // ver 4.5 for zip64
+            writeShort(45);
+        } else {
+            writeShort(version);    // version made by
+            writeShort(version);    // version needed to extract
+        }
+        writeShort(flag);           // general purpose bit flag
+        writeShort(e.method);       // compression method
+        writeInt(e.xdostime);       // last modification time
+        writeInt(e.crc);            // crc-32
+        writeInt(csize);            // compressed size
+        writeInt(size);             // uncompressed size
+        byte[] nameBytes = zc.getBytes(e.name);
+        writeShort(nameBytes.length);
+
+        int elen = getExtraLen(e.extra);
+        if (hasZip64) {
+            elen += (elenZIP64 + 4);// + headid(2) + datasize(2)
+        }
+        // cen info-zip extended timestamp only outputs mtime
+        // but set the flag for a/ctime, if present in loc
+        int flagEXTT = 0;
+        if (e.mtime != null) {
+            elen += 4;              // + mtime(4)
+            flagEXTT |= EXTT_FLAG_LMT;
+        }
+        if (e.atime != null) {
+            flagEXTT |= EXTT_FLAG_LAT;
+        }
+        if (e.ctime != null) {
+            flagEXTT |= EXTT_FLAT_CT;
+        }
+        if (flagEXTT != 0) {
+            elen += 5;             // headid + sz + flag
+        }
+        writeShort(elen);
+        byte[] commentBytes;
+        if (e.comment != null) {
+            commentBytes = zc.getBytes(e.comment);
+            writeShort(Math.min(commentBytes.length, 0xffff));
+        } else {
+            commentBytes = null;
+            writeShort(0);
+        }
+        writeShort(0);              // starting disk number
+        writeShort(0);              // internal file attributes (unused)
+        writeInt(0);                // external file attributes (unused)
+        writeInt(offset);           // relative offset of local header
+        writeBytes(nameBytes, 0, nameBytes.length);
+
+        // take care of EXTID_ZIP64 and EXTID_EXTT
+        if (hasZip64) {
+            writeShort(ZIP64_EXTID);// Zip64 extra
+            writeShort(elenZIP64);
+            if (size == ZIP64_MAGICVAL)
+                writeLong(e.size);
+            if (csize == ZIP64_MAGICVAL)
+                writeLong(e.csize);
+            if (offset == ZIP64_MAGICVAL)
+                writeLong(xentry.offset);
+        }
+        if (flagEXTT != 0) {
+            writeShort(EXTID_EXTT);
+            if (e.mtime != null) {
+                writeShort(5);      // flag + mtime
+                writeByte(flagEXTT);
+                writeInt(fileTimeToUnixTime(e.mtime));
+            } else {
+                writeShort(1);      // flag only
+                writeByte(flagEXTT);
+            }
+        }
+        writeExtra(e.extra);
+        if (commentBytes != null) {
+            writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff));
+        }
+    }
+
+    /*
+     * Writes end of central directory (END) header.
+     */
+    private void writeEND(long off, long len) throws IOException {
+        boolean hasZip64 = false;
+        long xlen = len;
+        long xoff = off;
+        if (xlen >= ZIP64_MAGICVAL) {
+            xlen = ZIP64_MAGICVAL;
+            hasZip64 = true;
+        }
+        if (xoff >= ZIP64_MAGICVAL) {
+            xoff = ZIP64_MAGICVAL;
+            hasZip64 = true;
+        }
+        int count = xentries.size();
+        if (count >= ZIP64_MAGICCOUNT) {
+            hasZip64 |= !inhibitZip64;
+            if (hasZip64) {
+                count = ZIP64_MAGICCOUNT;
+            }
+        }
+        if (hasZip64) {
+            long off64 = written;
+            //zip64 end of central directory record
+            writeInt(ZIP64_ENDSIG);        // zip64 END record signature
+            writeLong(ZIP64_ENDHDR - 12);  // size of zip64 end
+            writeShort(45);                // version made by
+            writeShort(45);                // version needed to extract
+            writeInt(0);                   // number of this disk
+            writeInt(0);                   // central directory start disk
+            writeLong(xentries.size());    // number of directory entires on disk
+            writeLong(xentries.size());    // number of directory entires
+            writeLong(len);                // length of central directory
+            writeLong(off);                // offset of central directory
+
+            //zip64 end of central directory locator
+            writeInt(ZIP64_LOCSIG);        // zip64 END locator signature
+            writeInt(0);                   // zip64 END start disk
+            writeLong(off64);              // offset of zip64 END
+            writeInt(1);                   // total number of disks (?)
+        }
+        writeInt(ENDSIG);                 // END record signature
+        writeShort(0);                    // number of this disk
+        writeShort(0);                    // central directory start disk
+        writeShort(count);                // number of directory entries on disk
+        writeShort(count);                // total number of directory entries
+        writeInt(xlen);                   // length of central directory
+        writeInt(xoff);                   // offset of central directory
+        if (comment != null) {            // zip file comment
+            writeShort(comment.length);
+            writeBytes(comment, 0, comment.length);
+        } else {
+            writeShort(0);
+        }
+    }
+
+    /*
+     * Returns the length of extra data without EXTT and ZIP64.
+     */
+    private int getExtraLen(byte[] extra) {
+        if (extra == null)
+            return 0;
+        int skipped = 0;
+        int len = extra.length;
+        int off = 0;
+        while (off + 4 <= len) {
+            int tag = get16(extra, off);
+            int sz = get16(extra, off + 2);
+            if (sz < 0 || (off + 4 + sz) > len) {
+                break;
+            }
+            if (tag == EXTID_EXTT || tag == EXTID_ZIP64) {
+                skipped += (sz + 4);
+            }
+            off += (sz + 4);
+        }
+        return len - skipped;
+    }
+
+    /*
+     * Writes extra data without EXTT and ZIP64.
+     *
+     * Extra timestamp and ZIP64 data is handled/output separately
+     * in writeLOC and writeCEN.
+     */
+    private void writeExtra(byte[] extra) throws IOException {
+        if (extra != null) {
+            int len = extra.length;
+            int off = 0;
+            while (off + 4 <= len) {
+                int tag = get16(extra, off);
+                int sz = get16(extra, off + 2);
+                if (sz < 0 || (off + 4 + sz) > len) {
+                    writeBytes(extra, off, len - off);
+                    return;
+                }
+                if (tag != EXTID_EXTT && tag != EXTID_ZIP64) {
+                    writeBytes(extra, off, sz + 4);
+                }
+                off += (sz + 4);
+            }
+            if (off < len) {
+                writeBytes(extra, off, len - off);
+            }
+        }
+    }
+
+    /*
+     * Writes a 8-bit byte to the output stream.
+     */
+    private void writeByte(int v) throws IOException {
+        OutputStream out = this.out;
+        out.write(v & 0xff);
+        written += 1;
+    }
+
+    /*
+     * Writes a 16-bit short to the output stream in little-endian byte order.
+     */
+    private void writeShort(int v) throws IOException {
+        OutputStream out = this.out;
+        out.write((v >>> 0) & 0xff);
+        out.write((v >>> 8) & 0xff);
+        written += 2;
+    }
+
+    /*
+     * Writes a 32-bit int to the output stream in little-endian byte order.
+     */
+    private void writeInt(long v) throws IOException {
+        OutputStream out = this.out;
+        out.write((int)((v >>>  0) & 0xff));
+        out.write((int)((v >>>  8) & 0xff));
+        out.write((int)((v >>> 16) & 0xff));
+        out.write((int)((v >>> 24) & 0xff));
+        written += 4;
+    }
+
+    /*
+     * Writes a 64-bit int to the output stream in little-endian byte order.
+     */
+    private void writeLong(long v) throws IOException {
+        OutputStream out = this.out;
+        out.write((int)((v >>>  0) & 0xff));
+        out.write((int)((v >>>  8) & 0xff));
+        out.write((int)((v >>> 16) & 0xff));
+        out.write((int)((v >>> 24) & 0xff));
+        out.write((int)((v >>> 32) & 0xff));
+        out.write((int)((v >>> 40) & 0xff));
+        out.write((int)((v >>> 48) & 0xff));
+        out.write((int)((v >>> 56) & 0xff));
+        written += 8;
+    }
+
+    /*
+     * Writes an array of bytes to the output stream.
+     */
+    private void writeBytes(byte[] b, int off, int len) throws IOException {
+        super.out.write(b, off, len);
+        written += len;
+    }
+}
diff --git a/java/util/zip/ZipUtils.java b/java/util/zip/ZipUtils.java
new file mode 100644
index 0000000..fce4d0e
--- /dev/null
+++ b/java/util/zip/ZipUtils.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.nio.file.attribute.FileTime;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+class ZipUtils {
+
+    // used to adjust values between Windows and java epoch
+    private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
+
+    /**
+     * Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
+     */
+    public static final FileTime winTimeToFileTime(long wtime) {
+        return FileTime.from(wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS,
+                             TimeUnit.MICROSECONDS);
+    }
+
+    /**
+     * Converts FileTime to Windows time.
+     */
+    public static final long fileTimeToWinTime(FileTime ftime) {
+        return (ftime.to(TimeUnit.MICROSECONDS) - WINDOWS_EPOCH_IN_MICROSECONDS) * 10;
+    }
+
+    /**
+     * Converts "standard Unix time"(in seconds, UTC/GMT) to FileTime
+     */
+    public static final FileTime unixTimeToFileTime(long utime) {
+        return FileTime.from(utime, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Converts FileTime to "standard Unix time".
+     */
+    public static final long fileTimeToUnixTime(FileTime ftime) {
+        return ftime.to(TimeUnit.SECONDS);
+    }
+
+    /**
+     * Converts DOS time to Java time (number of milliseconds since epoch).
+     */
+    private static long dosToJavaTime(long dtime) {
+        @SuppressWarnings("deprecation") // Use of date constructor.
+        Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
+                          (int)(((dtime >> 21) & 0x0f) - 1),
+                          (int)((dtime >> 16) & 0x1f),
+                          (int)((dtime >> 11) & 0x1f),
+                          (int)((dtime >> 5) & 0x3f),
+                          (int)((dtime << 1) & 0x3e));
+        return d.getTime();
+    }
+
+    /**
+     * Converts extended DOS time to Java time, where up to 1999 milliseconds
+     * might be encoded into the upper half of the returned long.
+     *
+     * @param xdostime the extended DOS time value
+     * @return milliseconds since epoch
+     */
+    public static long extendedDosToJavaTime(long xdostime) {
+        long time = dosToJavaTime(xdostime);
+        return time + (xdostime >> 32);
+    }
+
+    /**
+     * Converts Java time to DOS time.
+     */
+    @SuppressWarnings("deprecation") // Use of date methods
+    private static long javaToDosTime(long time) {
+        Date d = new Date(time);
+        int year = d.getYear() + 1900;
+        if (year < 1980) {
+            return ZipEntry.DOSTIME_BEFORE_1980;
+        }
+        // Android-changed: backport of JDK-8130914 fix
+        return ((year - 1980) << 25 | (d.getMonth() + 1) << 21 |
+                d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
+                d.getSeconds() >> 1) & 0xffffffffL;
+    }
+
+    /**
+     * Converts Java time to DOS time, encoding any milliseconds lost
+     * in the conversion into the upper half of the returned long.
+     *
+     * @param time milliseconds since epoch
+     * @return DOS time with 2s remainder encoded into upper half
+     */
+    public static long javaToExtendedDosTime(long time) {
+        if (time < 0) {
+            return ZipEntry.DOSTIME_BEFORE_1980;
+        }
+        long dostime = javaToDosTime(time);
+        return (dostime != ZipEntry.DOSTIME_BEFORE_1980)
+                ? dostime + ((time % 2000) << 32)
+                : ZipEntry.DOSTIME_BEFORE_1980;
+    }
+
+    /**
+     * Fetches unsigned 16-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final int get16(byte b[], int off) {
+        return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8);
+    }
+
+    /**
+     * Fetches unsigned 32-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final long get32(byte b[], int off) {
+        return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL;
+    }
+
+    /**
+     * Fetches signed 64-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final long get64(byte b[], int off) {
+        return get32(b, off) | (get32(b, off+4) << 32);
+    }
+}